hir/
visitor.rs

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}