rustc_ast_ir/
visit.rs
1use core::ops::ControlFlow;
2
3pub 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}