rustc_ast_ir/
visit.rs

1use core::ops::ControlFlow;
2
3/// Similar to the `Try` trait, but also implemented for `()`.
4pub trait VisitorResult {
5    type Residual;
6    fn output() -> Self;
7    fn from_residual(residual: Self::Residual) -> Self;
8    fn from_branch(b: ControlFlow<Self::Residual>) -> Self;
9    fn branch(self) -> ControlFlow<Self::Residual>;
10}
11
12impl VisitorResult for () {
13    #[cfg(feature = "nightly")]
14    type Residual = !;
15
16    #[cfg(not(feature = "nightly"))]
17    type Residual = core::convert::Infallible;
18
19    fn output() -> Self {}
20    fn from_residual(_: Self::Residual) -> Self {}
21    fn from_branch(_: ControlFlow<Self::Residual>) -> Self {}
22    fn branch(self) -> ControlFlow<Self::Residual> {
23        ControlFlow::Continue(())
24    }
25}
26
27impl<T> VisitorResult for ControlFlow<T> {
28    type Residual = T;
29
30    fn output() -> Self {
31        ControlFlow::Continue(())
32    }
33    fn from_residual(residual: Self::Residual) -> Self {
34        ControlFlow::Break(residual)
35    }
36    fn from_branch(b: Self) -> Self {
37        b
38    }
39    fn branch(self) -> Self {
40        self
41    }
42}
43
44#[macro_export]
45macro_rules! try_visit {
46    ($e:expr) => {
47        match $crate::visit::VisitorResult::branch($e) {
48            core::ops::ControlFlow::Continue(()) => (),
49            #[allow(unreachable_code)]
50            core::ops::ControlFlow::Break(r) => {
51                return $crate::visit::VisitorResult::from_residual(r);
52            }
53        }
54    };
55}
56
57#[macro_export]
58macro_rules! visit_opt {
59    ($visitor: expr, $method: ident, $opt: expr $(, $($extra_args: expr),* )?) => {
60        if let Some(x) = $opt {
61            $crate::try_visit!($visitor.$method(x $(, $($extra_args,)* )?));
62        }
63    }
64}
65
66#[macro_export]
67macro_rules! walk_list {
68    ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => {
69        for elem in $list {
70            $crate::try_visit!($visitor.$method(elem $(, $($extra_args,)* )?));
71        }
72    }
73}
74
75#[macro_export]
76macro_rules! walk_visitable_list {
77    ($visitor: expr, $list: expr $(, $($extra_args: expr),* )?) => {
78        for elem in $list {
79            $crate::try_visit!(elem.visit_with($visitor $(, $($extra_args,)* )?));
80        }
81    }
82}