| use core::ops::ControlFlow; | |
| /// Similar to the `Try` trait, but also implemented for `()`. | |
| pub trait VisitorResult { | |
| type Residual; | |
| fn output() -> Self; | |
| fn from_residual(residual: Self::Residual) -> Self; | |
| fn from_branch(b: ControlFlow<Self::Residual>) -> Self; | |
| fn branch(self) -> ControlFlow<Self::Residual>; | |
| } | |
| impl VisitorResult for () { | |
| #[cfg(feature = "nightly")] | |
| type Residual = !; | |
| #[cfg(not(feature = "nightly"))] | |
| type Residual = core::convert::Infallible; | |
| fn output() -> Self {} | |
| fn from_residual(_: Self::Residual) -> Self {} | |
| fn from_branch(_: ControlFlow<Self::Residual>) -> Self {} | |
| fn branch(self) -> ControlFlow<Self::Residual> { | |
| ControlFlow::Continue(()) | |
| } | |
| } | |
| impl<T> VisitorResult for ControlFlow<T> { | |
| type Residual = T; | |
| fn output() -> Self { | |
| ControlFlow::Continue(()) | |
| } | |
| fn from_residual(residual: Self::Residual) -> Self { | |
| ControlFlow::Break(residual) | |
| } | |
| fn from_branch(b: Self) -> Self { | |
| b | |
| } | |
| fn branch(self) -> Self { | |
| self | |
| } | |
| } | |
| impl<E> VisitorResult for Result<(), E> { | |
| type Residual = E; | |
| fn output() -> Self { | |
| Ok(()) | |
| } | |
| fn from_residual(residual: Self::Residual) -> Self { | |
| Err(residual) | |
| } | |
| fn from_branch(b: ControlFlow<Self::Residual>) -> Self { | |
| match b { | |
| ControlFlow::Continue(()) => Ok(()), | |
| ControlFlow::Break(e) => Err(e), | |
| } | |
| } | |
| fn branch(self) -> ControlFlow<Self::Residual> { | |
| match self { | |
| Ok(()) => ControlFlow::Continue(()), | |
| Err(e) => ControlFlow::Break(e), | |
| } | |
| } | |
| } | |
| #[macro_export] | |
| macro_rules! try_visit { | |
| ($e:expr) => { | |
| match $crate::visit::VisitorResult::branch($e) { | |
| core::ops::ControlFlow::Continue(()) => (), | |
| #[allow(unreachable_code)] | |
| core::ops::ControlFlow::Break(r) => { | |
| return $crate::visit::VisitorResult::from_residual(r); | |
| } | |
| } | |
| }; | |
| } | |
| #[macro_export] | |
| macro_rules! visit_opt { | |
| ($visitor: expr, $method: ident, $opt: expr $(, $($extra_args: expr),* )?) => { | |
| if let Some(x) = $opt { | |
| $crate::try_visit!($visitor.$method(x $(, $($extra_args,)* )?)); | |
| } | |
| } | |
| } | |
| #[macro_export] | |
| macro_rules! walk_list { | |
| ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => { | |
| for elem in $list { | |
| $crate::try_visit!($visitor.$method(elem $(, $($extra_args,)* )?)); | |
| } | |
| } | |
| } | |
| #[macro_export] | |
| macro_rules! walk_visitable_list { | |
| ($visitor: expr, $list: expr $(, $($extra_args: expr),* )?) => { | |
| for elem in $list { | |
| $crate::try_visit!(::rustc_type_ir::TypeVisitable::visit_with(elem, $visitor $(, $($extra_args,)* )?)); | |
| } | |
| } | |
| } |