1use std::ops::ControlFlow;
2
3use crate::item::Item;
4use crate::{Constness, Param, UseItem};
5use crate::{
6 Expression, HirId, Ident, Module, Path, PathDef,
7 Statement, Type,
8 item::Field,
9 expr::{ArithmeticOp, CmpOp, LitValue, LogicalOp, UnaryOp},
10 hir, stmt,
11};
12
13pub trait Visitor<'hir> {
14 type Result: VisitorResult;
15 type Ctx: VisitorCtx<'hir>;
16
17 fn get_ctx(&mut self) -> &mut Self::Ctx;
18
19 fn visit_module(&mut self, m: &'hir Module<'hir>) -> Self::Result { walk_module(self, m) }
20
21 fn visit_param(&mut self, param: &'hir Param<'hir>) -> Self::Result {
22 walk_param(self, param)
23 }
24
25 fn visit_item(&mut self, item: &'hir Item<'hir>) -> Self::Result {
26 walk_item(self, item)
27 }
28
29 fn visit_use(&mut self, item: &'hir Item<'hir>, u: &'hir UseItem<'hir>) -> Self::Result {
30 walk_use(self, item, u)
31 }
32
33 fn visit_type_alias(&mut self, item: &'hir Item<'hir>, ty: &'hir Type<'hir>, name: &'hir PathDef) -> Self::Result {
34 walk_type_alias(self, item, ty, name)
35 }
36
37 fn visit_variable_definition(&mut self,
38 base: &'hir Item<'hir>,
39 name: &'hir PathDef,
40 ty: Option<&'hir Type<'hir>>,
41 init: Option<&'hir Expression<'hir>>,
42 constness: Constness,
43 ) -> Self::Result {
44 walk_variable_definition(self, base, name, ty, init, constness)
45 }
46
47 fn visit_expression(&mut self, expr: &'hir Expression<'hir>) -> Self::Result {
48 walk_expression(self, expr)
49 }
50
51 fn visit_expression_as_stmt(
52 &mut self,
53 _base: &'hir Statement<'hir>,
54 expr: &'hir Expression<'hir>,
55 ) -> Self::Result {
56 walk_expression(self, expr)
57 }
58
59 fn visit_ref(
60 &mut self,
61 _base: &'hir Expression<'hir>,
62 r: &'hir Expression<'hir>,
63 ) -> Self::Result {
64 walk_ref(self, r)
65 }
66
67 fn visit_cast(
68 &mut self,
69 _base: &'hir Expression<'hir>,
70 expr: &'hir Expression<'hir>,
71 to: &'hir Type<'hir>,
72 ) -> Self::Result {
73 walk_cast(self, expr, to)
74 }
75
76 fn visit_deref(
77 &mut self,
78 _base: &'hir Expression<'hir>,
79 r: &'hir Expression<'hir>,
80 ) -> Self::Result {
81 walk_deref(self, r)
82 }
83
84 fn visit_unary(&mut self, _op: &UnaryOp, expr: &'hir Expression<'hir>) -> Self::Result {
85 walk_unary(self, expr)
86 }
87
88 fn visit_logical(
89 &mut self,
90 _base: &'hir Expression<'hir>,
91 left: &'hir Expression<'hir>,
92 op: &LogicalOp,
93 right: &'hir Expression<'hir>,
94 ) -> Self::Result {
95 walk_logical(self, left, op, right)
96 }
97
98 fn visit_comparison(
99 &mut self,
100 _base: &'hir Expression<'hir>,
101 left: &'hir Expression<'hir>,
102 op: &CmpOp,
103 right: &'hir Expression<'hir>,
104 ) -> Self::Result {
105 walk_comparison(self, left, op, right)
106 }
107
108 fn visit_arithmetic(
109 &mut self,
110 _base: &'hir Expression<'hir>,
111 left: &'hir Expression<'hir>,
112 op: &ArithmeticOp,
113 right: &'hir Expression<'hir>,
114 ) -> Self::Result {
115 walk_arithmetic(self, left, op, right)
116 }
117
118 fn visit_ternary(
119 &mut self,
120 _base: &'hir Expression<'hir>,
121 cond: &'hir Expression<'hir>,
122 if_true: &'hir Expression<'hir>,
123 if_false: &'hir Expression<'hir>,
124 ) -> Self::Result {
125 walk_ternary(self, cond, if_true, if_false)
126 }
127
128 fn visit_assignment(
129 &mut self,
130 _base: &'hir Expression<'hir>,
131 left: &'hir Expression<'hir>,
132 right: &'hir Expression<'hir>,
133 ) -> Self::Result {
134 walk_assignment(self, left, right)
135 }
136
137 fn visit_variable(
138 &mut self,
139 _base: &'hir Expression<'hir>,
140 path: &'hir hir::Path,
141 ) -> Self::Result {
142 walk_variable(self, path)
143 }
144
145 fn visit_function_definition(
146 &mut self,
147 _is_extern: bool,
148 _is_variadic: bool,
149 base: &'hir Item<'hir>,
150 name: &'hir PathDef,
151 params: &'hir [Param<'hir>],
152 ret_ty: &'hir Type<'hir>,
153 body: Option<&'hir [Statement<'hir>]>,
154 ) -> Self::Result {
155 walk_function_definition(self, base, name, params, ret_ty, body)
156 }
157
158 fn visit_struct_definition(
159 &mut self,
160 base: &'hir Item<'hir>,
161 name: &'hir PathDef,
162 fields: &'hir [Field<'hir>],
163 ) -> Self::Result {
164 walk_struct_definition(self, base, name, fields)
165 }
166
167 fn visit_field(
168 &mut self,
169 _def: &'hir Item<'hir>,
170 param: &'hir Field<'hir>,
171 ) -> Self::Result {
172 walk_field(self, param)
173 }
174
175 fn visit_statement(&mut self, stmt: &'hir Statement<'hir>) -> Self::Result {
176 walk_statement(self, stmt)
177 }
178
179 fn visit_block(
180 &mut self,
181 _base: &'hir Statement<'hir>,
182 block: &'hir [Statement<'hir>],
183 ) -> Self::Result {
184 walk_block(self, block)
185 }
186
187 fn visit_break(&mut self, _base: &'hir Statement<'hir>) -> Self::Result {
188 Self::Result::output()
189 }
190
191 fn visit_empty(&mut self, _base: &'hir Statement<'hir>) -> Self::Result {
192 Self::Result::output()
193 }
194
195 fn visit_continue(&mut self, _base: &'hir Statement<'hir>) -> Self::Result {
196 Self::Result::output()
197 }
198
199 fn visit_return(
200 &mut self,
201 _base: &'hir Statement<'hir>,
202 ret: Option<&'hir Expression<'hir>>,
203 ) -> Self::Result {
204 walk_return(self, ret)
205 }
206
207 fn visit_literal(&mut self, _expr: &'hir Expression<'hir>, _lit: &LitValue) -> Self::Result {
208 Self::Result::output()
209 }
210
211 fn visit_pathdef(&mut self, _owner: HirId, _pdef: &'hir PathDef) -> Self::Result {
212 Self::Result::output()
213 }
214
215 fn visit_path(&mut self, _path: &'hir Path) -> Self::Result { Self::Result::output() }
216
217 fn visit_for(
218 &mut self,
219 _base: &'hir Statement,
220 init: Option<&'hir Item<'hir>>,
221 cond: Option<&'hir Expression<'hir>>,
222 inc: Option<&'hir Expression<'hir>>,
223 body: &'hir Statement<'hir>,
224 ) -> Self::Result {
225 walk_for(self, init, cond, inc, body)
226 }
227
228 fn visit_while(
229 &mut self,
230 _base: &'hir Statement,
231 cond: &'hir Expression<'hir>,
232 body: &'hir Statement<'hir>,
233 ) -> Self::Result {
234 walk_while(self, cond, body)
235 }
236
237 fn visit_if(
238 &mut self,
239 _base: &'hir Statement,
240 cond: &'hir Expression<'hir>,
241 if_true: &'hir Statement<'hir>,
242 if_false: Option<&'hir Statement<'hir>>,
243 ) -> Self::Result {
244 walk_if(self, cond, if_true, if_false)
245 }
246
247 fn visit_call(
248 &mut self,
249 _expr: &'hir Expression<'hir>,
250 callee: &'hir Expression<'hir>,
251 args: &'hir [Expression<'hir>],
252 ) -> Self::Result {
253 walk_call(self, callee, args)
254 }
255
256 fn visit_array_access(
257 &mut self,
258 _expr: &'hir Expression<'hir>,
259 array: &'hir Expression<'hir>,
260 index: &'hir Expression<'hir>,
261 ) -> Self::Result {
262 walk_array_access(self, array, index)
263 }
264
265 fn visit_struct_access(
266 &mut self,
267 _expr: &'hir Expression<'hir>,
268 st: &'hir Expression<'hir>,
269 field: Ident,
270 ) -> Self::Result {
271 walk_struct_access(self, st, field)
272 }
273
274 fn visit_type(&mut self, ty: &'hir Type<'hir>) -> Self::Result { walk_type(self, ty) }
275}
276
277macro_rules! walk_iter {
278 ($v:expr, $it:expr, $fn:ident) => {{
279 for elem in $it.iter() {
280 $v.$fn(elem);
281 }
282 }};
283}
284
285macro_rules! walk_opt {
286 ($v:expr, $opt:expr, $fn:ident) => {
287 if let Some(elem) = $opt {
288 $v.$fn(elem);
289 }
290 };
291}
292
293pub fn walk_module<'hir, V>(v: &mut V, prog: &'hir Module<'hir>) -> V::Result
294where
295 V: Visitor<'hir> + ?Sized,
296{
297 v.visit_pathdef(prog.id, prog.name);
298 v.get_ctx().enter_module(prog);
299 for item in prog.items {
300 v.visit_item(item);
301 }
302 v.get_ctx().exit_module();
303 V::Result::output()
304}
305
306pub fn walk_type<'hir, V>(v: &mut V, ty: &'hir Type<'hir>) -> V::Result
307where
308 V: Visitor<'hir> + ?Sized,
309{
310 use hir::types::TypeKind;
311 match &ty.kind {
312 TypeKind::Path(path) => {
313 v.visit_path(path);
314 }
315 TypeKind::Ref(r) => {
316 v.visit_type(r);
317 }
318 TypeKind::Array(ty, _) => {
319 v.visit_type(ty);
320 }
321 TypeKind::Function { is_variadic: _, params, ret_ty } => {
322 walk_iter!(v, params, visit_type);
323 v.visit_type(ret_ty);
324 }
325 TypeKind::Primitive(_) => {}
326 }
327 V::Result::output()
328}
329
330pub fn walk_use<'hir, V>(v: &mut V, item: &'hir Item<'hir>, s: &'hir UseItem<'hir>) -> V::Result
331where
332 V: Visitor<'hir> + ?Sized,
333{
334 v.visit_path(&s.path);
335 v.visit_pathdef(item.id, s.new_name);
336 V::Result::output()
337}
338
339pub fn walk_type_alias<'hir, V>(v: &mut V, item: &'hir Item<'hir>, ty: &'hir Type<'hir>, name: &'hir PathDef) -> V::Result
340where
341 V: Visitor<'hir> + ?Sized,
342{
343 v.visit_type(ty);
344 v.visit_pathdef(item.id, name);
345 V::Result::output()
346}
347
348pub fn walk_param<'hir, V>(v: &mut V, param: &'hir Param<'hir>) -> V::Result
349where
350 V: Visitor<'hir> + ?Sized,
351{
352 v.visit_pathdef(param.id, param.name);
353 v.visit_type(param.ty);
354 V::Result::output()
355}
356
357pub fn walk_item<'hir, V>(v: &mut V, item: &'hir Item<'hir>) -> V::Result
358where
359 V: Visitor<'hir> + ?Sized,
360{
361 use crate::item::ItemKind;
362
363 match &item.kind {
364 ItemKind::Variable { name, ty, init, constness } => v.visit_variable_definition(item, name, *ty, *init, *constness),
365 ItemKind::Use(u) => v.visit_use(item, u),
366 ItemKind::Function {
367 is_extern,
368 is_variadic,
369 name,
370 params,
371 body,
372 ret_ty,
373 } => v.visit_function_definition(*is_extern, *is_variadic, item, name, params, ret_ty, *body),
374 ItemKind::Struct { fields, name } => v.visit_struct_definition(item, name, fields),
375 ItemKind::Mod(m) => v.visit_module(m),
376 ItemKind::TypeAlias { ty, name } => v.visit_type_alias(item, ty, name)
377 }
378}
379
380pub fn walk_variable_definition<'hir, V>(
381 v: &mut V,
382 base: &'hir Item<'hir>,
383 name: &'hir PathDef,
384 ty: Option<&'hir Type<'hir>>,
385 init: Option<&'hir Expression<'hir>>,
386 _constness: Constness,
387) -> V::Result
388where
389 V: Visitor<'hir> + ?Sized,
390{
391 v.visit_pathdef(base.id, name);
392 walk_opt!(v, init, visit_expression);
393 walk_opt!(v, ty, visit_type);
394 V::Result::output()
395}
396
397pub fn walk_function_definition<'hir, V>(
398 v: &mut V,
399 base: &'hir Item<'hir>,
400 name: &'hir PathDef,
401 params: &'hir [Param<'hir>],
402 ret_ty: &'hir Type<'hir>,
403 body: Option<&'hir [Statement<'hir>]>,
404) -> V::Result
405where
406 V: Visitor<'hir> + ?Sized,
407{
408 v.visit_pathdef(base.id, name);
409 v.get_ctx().enter_function(base);
410 for p in params {
411 v.visit_param(p);
412 }
413 if let Some(body) = body {
414 for stmt in body {
415 v.visit_statement(stmt);
416 }
417 }
418 v.visit_type(ret_ty);
419 v.get_ctx().exit_function();
420 V::Result::output()
421}
422
423pub fn walk_struct_definition<'hir, V>(
424 v: &mut V,
425 def: &'hir Item<'hir>,
426 name: &'hir PathDef,
427 fields: &'hir [Field<'hir>],
428) -> V::Result
429where
430 V: Visitor<'hir> + ?Sized,
431{
432 v.visit_pathdef(def.id, name);
433 v.get_ctx().enter_struct(def);
434 for f in fields {
435 v.visit_field(def, f);
436 }
437 v.get_ctx().exit_struct();
438 V::Result::output()
439}
440
441pub fn walk_field<'hir, V>(
442 v: &mut V,
443 f: &'hir Field<'hir>,
444) -> V::Result
445where
446 V: Visitor<'hir> + ?Sized,
447{
448 v.visit_pathdef(f.id, f.name);
449 V::Result::output()
450}
451
452pub fn walk_ref<'hir, V>(v: &mut V, r: &'hir Expression<'hir>) -> V::Result
453where
454 V: Visitor<'hir> + ?Sized,
455{
456 v.visit_expression(r);
457 V::Result::output()
458}
459
460pub fn walk_cast<'hir, V>(
461 v: &mut V,
462 expr: &'hir Expression<'hir>,
463 to: &'hir Type<'hir>,
464) -> V::Result
465where
466 V: Visitor<'hir> + ?Sized,
467{
468 v.visit_expression(expr);
469 v.visit_type(to);
470 V::Result::output()
471}
472
473pub fn walk_deref<'hir, V>(v: &mut V, r: &'hir Expression<'hir>) -> V::Result
474where
475 V: Visitor<'hir> + ?Sized,
476{
477 v.visit_expression(r);
478 V::Result::output()
479}
480
481pub fn walk_unary<'hir, V>(v: &mut V, expr: &'hir Expression<'hir>) -> V::Result
482where
483 V: Visitor<'hir> + ?Sized,
484{
485 v.visit_expression(expr);
486 V::Result::output()
487}
488
489pub fn walk_logical<'hir, V>(
490 v: &mut V,
491 left: &'hir Expression<'hir>,
492 _op: &LogicalOp,
493 right: &'hir Expression<'hir>,
494) -> V::Result
495where
496 V: Visitor<'hir> + ?Sized,
497{
498 v.visit_expression(left);
499 v.visit_expression(right);
500 V::Result::output()
501}
502
503pub fn walk_variable<'hir, V>(v: &mut V, path: &'hir Path) -> V::Result
504where
505 V: Visitor<'hir> + ?Sized,
506{
507 v.visit_path(path);
508 V::Result::output()
509}
510
511pub fn walk_call<'hir, V>(
512 v: &mut V,
513 callee: &'hir Expression<'hir>,
514 args: &'hir [Expression<'hir>],
515) -> V::Result
516where
517 V: Visitor<'hir> + ?Sized,
518{
519 v.visit_expression(callee);
520 walk_iter!(v, args, visit_expression);
521 V::Result::output()
522}
523
524pub fn walk_array_access<'hir, V>(
525 v: &mut V,
526 array: &'hir Expression<'hir>,
527 index: &'hir Expression<'hir>,
528) -> V::Result
529where
530 V: Visitor<'hir> + ?Sized,
531{
532 v.visit_expression(array);
533 v.visit_expression(index);
534 V::Result::output()
535}
536
537pub fn walk_struct_access<'hir, V>(
538 v: &mut V,
539 st: &'hir Expression<'hir>,
540 _field: Ident,
541) -> V::Result
542where
543 V: Visitor<'hir> + ?Sized,
544{
545 v.visit_expression(st);
546 V::Result::output()
547}
548
549pub fn walk_for<'hir, V>(
550 v: &mut V,
551 init: Option<&'hir Item<'hir>>,
552 cond: Option<&'hir Expression<'hir>>,
553 inc: Option<&'hir Expression<'hir>>,
554 body: &'hir Statement<'hir>,
555) -> V::Result
556where
557 V: Visitor<'hir> + ?Sized,
558{
559 walk_opt!(v, init, visit_item);
560 walk_opt!(v, cond, visit_expression);
561 walk_opt!(v, inc, visit_expression);
562 v.visit_statement(body);
563 V::Result::output()
564}
565
566pub fn walk_while<'hir, V>(
567 v: &mut V,
568 cond: &'hir Expression<'hir>,
569 body: &'hir Statement<'hir>,
570) -> V::Result
571where
572 V: Visitor<'hir> + ?Sized,
573{
574 v.visit_expression(cond);
575 v.visit_statement(body);
576 V::Result::output()
577}
578
579pub fn walk_if<'hir, V>(
580 v: &mut V,
581 cond: &'hir Expression<'hir>,
582 if_true: &'hir Statement<'hir>,
583 if_false: Option<&'hir Statement<'hir>>,
584) -> V::Result
585where
586 V: Visitor<'hir> + ?Sized,
587{
588 v.visit_expression(cond);
589 v.visit_statement(if_true);
590 walk_opt!(v, if_false, visit_statement);
591 V::Result::output()
592}
593
594pub fn walk_return<'hir, V>(v: &mut V, expr: Option<&'hir Expression<'hir>>) -> V::Result
595where
596 V: Visitor<'hir> + ?Sized,
597{
598 walk_opt!(v, expr, visit_expression);
599 V::Result::output()
600}
601
602pub fn walk_assignment<'hir, V>(
603 v: &mut V,
604 left: &'hir Expression<'hir>,
605 right: &'hir Expression<'hir>,
606) -> V::Result
607where
608 V: Visitor<'hir> + ?Sized,
609{
610 v.visit_expression(left);
611 v.visit_expression(right);
612 V::Result::output()
613}
614
615pub fn walk_arithmetic<'hir, V>(
616 v: &mut V,
617 left: &'hir Expression<'hir>,
618 _op: &ArithmeticOp,
619 right: &'hir Expression<'hir>,
620) -> V::Result
621where
622 V: Visitor<'hir> + ?Sized,
623{
624 v.visit_expression(left);
625 v.visit_expression(right);
626 V::Result::output()
627}
628
629pub fn walk_comparison<'hir, V>(
630 v: &mut V,
631 left: &'hir Expression<'hir>,
632 _op: &CmpOp,
633 right: &'hir Expression<'hir>,
634) -> V::Result
635where
636 V: Visitor<'hir> + ?Sized,
637{
638 v.visit_expression(left);
639 v.visit_expression(right);
640 V::Result::output()
641}
642
643pub fn walk_ternary<'hir, V>(
644 v: &mut V,
645 cond: &'hir Expression<'hir>,
646 if_true: &'hir Expression<'hir>,
647 if_false: &'hir Expression<'hir>,
648) -> V::Result
649where
650 V: Visitor<'hir> + ?Sized,
651{
652 v.visit_expression(cond);
653 v.visit_expression(if_true);
654 v.visit_expression(if_false);
655 V::Result::output()
656}
657
658pub fn walk_expression<'hir, V>(v: &mut V, expr: &'hir Expression<'hir>) -> V::Result
659where
660 V: Visitor<'hir> + ?Sized,
661{
662 use crate::expr::ExpressionKind;
663 match &expr.kind {
664 ExpressionKind::Array(expressions) => {
665 walk_iter!(v, expressions, visit_expression);
666 }
667 ExpressionKind::Cast {
668 expr: casted_expr,
669 to,
670 } => {
671 v.visit_cast(expr, casted_expr, to);
672 }
673 ExpressionKind::Ref(e) => {
674 v.visit_ref(expr, e);
675 }
676 ExpressionKind::Deref(e) => {
677 v.visit_deref(expr, e);
678 }
679 ExpressionKind::Unary { op, expr } => {
680 v.visit_unary(op, expr);
681 }
682 ExpressionKind::Logical { left, op, right } => {
683 v.visit_logical(expr, left, op, right);
684 }
685 ExpressionKind::Comparison { left, op, right } => {
686 v.visit_comparison(expr, left, op, right);
687 }
688 ExpressionKind::Arithmetic { left, op, right } => {
689 v.visit_arithmetic(expr, left, op, right);
690 }
691 ExpressionKind::Ternary {
692 cond,
693 if_true,
694 if_false,
695 } => {
696 v.visit_ternary(expr, cond, if_true, if_false);
697 }
698 ExpressionKind::Assignment { left, right } => {
699 v.visit_assignment(expr, left, right);
700 }
701 ExpressionKind::Variable(path) => {
702 v.visit_variable(expr, path);
703 }
704 ExpressionKind::Literal(lit_value) => {
705 v.visit_literal(expr, lit_value);
706 }
707 ExpressionKind::Call { callee, args } => {
708 v.visit_call(expr, callee, args);
709 }
710 ExpressionKind::ArrayAccess { arr, index } => {
711 v.visit_array_access(expr, arr, index);
712 }
713 ExpressionKind::StructAccess { st, field } => {
714 v.visit_struct_access(expr, st, *field);
715 }
716 }
717
718 V::Result::output()
719}
720
721pub fn walk_statement<'hir, V>(v: &mut V, stmt: &'hir Statement<'hir>) -> V::Result
722where
723 V: Visitor<'hir> + ?Sized,
724{
725 use stmt::StatementKind;
726 match &stmt.kind {
727 StatementKind::Expr(expression) => v.visit_expression_as_stmt(stmt, expression),
728 StatementKind::Item(item) => v.visit_item(item),
729 StatementKind::Block(statements) => v.visit_block(stmt, statements),
730 StatementKind::If {
731 cond,
732 if_true,
733 if_false,
734 } => v.visit_if(stmt, cond, if_true, *if_false),
735 StatementKind::While { cond, body } => v.visit_while(stmt, cond, body),
736 StatementKind::For {
737 init,
738 cond,
739 inc,
740 body,
741 } => v.visit_for(stmt, *init, *cond, *inc, body),
742 StatementKind::Empty => v.visit_empty(stmt),
743 StatementKind::Break => v.visit_break(stmt),
744 StatementKind::Continue => v.visit_continue(stmt),
745 StatementKind::Return(expression) => v.visit_return(stmt, *expression),
746 };
747
748 V::Result::output()
749}
750
751pub fn walk_block<'hir, V>(v: &mut V, block: &'hir [Statement<'hir>]) -> V::Result
752where
753 V: Visitor<'hir> + ?Sized,
754{
755 for stmt in block {
756 v.visit_statement(stmt);
757 }
758 V::Result::output()
759}
760
761pub trait VisitorResult {
762 type T;
763 type Residual;
764
765 fn output() -> Self;
766 fn from_residual(residual: Self::Residual) -> Self;
767 fn from_branch(b: ControlFlow<Self::Residual, Self::T>) -> Self;
768 fn branch(self) -> ControlFlow<Self::Residual, Self::T>;
769}
770
771impl VisitorResult for () {
772 type T = ();
773 type Residual = core::convert::Infallible;
774
775 fn output() -> Self {}
776 fn from_residual(_residual: Self::Residual) -> Self {}
777 fn from_branch(_b: ControlFlow<Self::Residual>) -> Self {}
778 fn branch(self) -> ControlFlow<Self::Residual> { ControlFlow::Continue(()) }
779}
780
781impl<B, C: Default> VisitorResult for ControlFlow<B, C> {
782 type T = C;
783 type Residual = B;
784
785 fn output() -> Self { ControlFlow::Continue(Self::T::default()) }
786
787 fn from_residual(residual: Self::Residual) -> Self { ControlFlow::Break(residual) }
788
789 fn from_branch(b: ControlFlow<Self::Residual, Self::T>) -> Self { b }
790
791 fn branch(self) -> ControlFlow<Self::Residual, Self::T> { self }
792}
793
794impl<T: Default, E> VisitorResult for Result<T, E> {
795 type T = T;
796 type Residual = E;
797
798 fn output() -> Self { Result::Ok(T::default()) }
799
800 fn from_residual(residual: Self::Residual) -> Self { Self::Err(residual) }
801
802 fn from_branch(b: ControlFlow<Self::Residual, Self::T>) -> Self {
803 match b {
804 ControlFlow::Continue(c) => Ok(c),
805 ControlFlow::Break(b) => Err(b),
806 }
807 }
808
809 fn branch(self) -> ControlFlow<Self::Residual, Self::T> {
810 match self {
811 Ok(t) => ControlFlow::Continue(t),
812 Err(err) => ControlFlow::Break(err),
813 }
814 }
815}
816
817impl<T> VisitorResult for Option<T> {
818 type T = T;
819 type Residual = ();
820
821 fn output() -> Self { None }
822
823 fn from_residual(_residual: Self::Residual) -> Self { None }
824
825 fn from_branch(b: ControlFlow<Self::Residual, Self::T>) -> Self {
826 match b {
827 ControlFlow::Continue(c) => Some(c),
828 ControlFlow::Break(()) => None,
829 }
830 }
831
832 fn branch(self) -> ControlFlow<Self::Residual, Self::T> {
833 match self {
834 Some(e) => ControlFlow::Continue(e),
835 None => ControlFlow::Break(()),
836 }
837 }
838}
839
840pub trait VisitorCtx<'ast> {
841 fn enter_function(&mut self, _func: &'ast Item<'ast>) {}
842 fn exit_function(&mut self) {}
843
844 fn enter_module(&mut self, _mod: &'ast Module<'ast>) {}
845 fn exit_module(&mut self) {}
846
847 fn enter_struct(&mut self, _mod: &'ast Item<'ast>) {}
848 fn exit_struct(&mut self) {}
849}
850
851impl VisitorCtx<'_> for () {}
852
853pub struct BaseVisitorCtx<'hir> {
854 funcs: Vec<&'hir Item<'hir>>,
855}
856
857impl<'hir> BaseVisitorCtx<'hir> {
858 pub fn current_function(&self) -> Option<&'hir Item<'hir>> { self.funcs.last().copied() }
859}
860
861impl<'hir> VisitorCtx<'hir> for BaseVisitorCtx<'hir> {
862 fn enter_function(&mut self, func: &'hir Item<'hir>) { self.funcs.push(func); }
863
864 fn exit_function(&mut self) { self.funcs.pop().unwrap(); }
865}