diff options
Diffstat (limited to 'vendor/chalk-ir-0.80.0/src/visit.rs')
-rw-r--r-- | vendor/chalk-ir-0.80.0/src/visit.rs | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/vendor/chalk-ir-0.80.0/src/visit.rs b/vendor/chalk-ir-0.80.0/src/visit.rs new file mode 100644 index 000000000..ace1fd5cf --- /dev/null +++ b/vendor/chalk-ir-0.80.0/src/visit.rs @@ -0,0 +1,424 @@ +//! Traits for visiting bits of IR. +use std::fmt::Debug; +use std::ops::ControlFlow; + +use crate::{ + BoundVar, Const, ConstValue, DebruijnIndex, DomainGoal, Goal, InferenceVar, Interner, Lifetime, + LifetimeData, PlaceholderIndex, ProgramClause, Ty, TyKind, WhereClause, +}; + +mod binder_impls; +mod boring_impls; +pub mod visitors; + +pub use visitors::VisitExt; + +/// Unwraps a `ControlFlow` or propagates its `Break` value. +/// This replaces the `Try` implementation that would be used +/// with `std::ops::ControlFlow`. +#[macro_export] +macro_rules! try_break { + ($expr:expr) => { + match $expr { + std::ops::ControlFlow::Continue(c) => c, + std::ops::ControlFlow::Break(b) => return std::ops::ControlFlow::Break(b), + } + }; +} + +/// A "visitor" recursively folds some term -- that is, some bit of IR, +/// such as a `Goal`, and computes a value as a result. +/// +/// +/// To **apply** a visitor, use the `Visit::visit_with` method, like so +/// +/// ```rust,ignore +/// let result = x.visit_with(&mut visitor, 0); +/// ``` +pub trait Visitor<I: Interner> { + /// The "break type" of the visitor, often `()`. It represents the result + /// the visitor yields when it stops visiting. + type BreakTy; + + /// Creates a `dyn` value from this visitor. Unfortunately, this + /// must be added manually to each impl of visitor; it permits the + /// default implements below to create a `&mut dyn Visitor` from + /// `Self` without knowing what `Self` is (by invoking this + /// method). Effectively, this limits impls of `visitor` to types + /// for which we are able to create a dyn value (i.e., not `[T]` + /// types). + fn as_dyn(&mut self) -> &mut dyn Visitor<I, BreakTy = Self::BreakTy>; + + /// Top-level callback: invoked for each `Ty<I>` that is + /// encountered when visiting. By default, invokes + /// `super_visit_with`, which will in turn invoke the more + /// specialized visiting methods below, like `visit_free_var`. + fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> { + ty.super_visit_with(self.as_dyn(), outer_binder) + } + + /// Top-level callback: invoked for each `Lifetime<I>` that is + /// encountered when visiting. By default, invokes + /// `super_visit_with`, which will in turn invoke the more + /// specialized visiting methods below, like `visit_free_var`. + fn visit_lifetime( + &mut self, + lifetime: &Lifetime<I>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + lifetime.super_visit_with(self.as_dyn(), outer_binder) + } + + /// Top-level callback: invoked for each `Const<I>` that is + /// encountered when visiting. By default, invokes + /// `super_visit_with`, which will in turn invoke the more + /// specialized visiting methods below, like `visit_free_var`. + fn visit_const( + &mut self, + constant: &Const<I>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + constant.super_visit_with(self.as_dyn(), outer_binder) + } + + /// Invoked for every program clause. By default, recursively visits the goals contents. + fn visit_program_clause( + &mut self, + clause: &ProgramClause<I>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + clause.super_visit_with(self.as_dyn(), outer_binder) + } + + /// Invoked for every goal. By default, recursively visits the goals contents. + fn visit_goal( + &mut self, + goal: &Goal<I>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + goal.super_visit_with(self.as_dyn(), outer_binder) + } + + /// Invoked for each domain goal. + fn visit_domain_goal( + &mut self, + domain_goal: &DomainGoal<I>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + domain_goal.super_visit_with(self.as_dyn(), outer_binder) + } + + /// If overridden to return true, then visiting will panic if a + /// free variable is encountered. This should be done if free + /// type/lifetime/const variables are not expected. + fn forbid_free_vars(&self) -> bool { + false + } + + /// Invoked for `BoundVar` instances that are not bound + /// within the type being visited over: + fn visit_free_var( + &mut self, + bound_var: BoundVar, + outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + if self.forbid_free_vars() { + panic!( + "unexpected free variable `{:?}` with outer binder {:?}", + bound_var, outer_binder + ) + } else { + ControlFlow::Continue(()) + } + } + + /// If overridden to return true, we will panic when a free + /// placeholder type/lifetime is encountered. + fn forbid_free_placeholders(&self) -> bool { + false + } + + /// Invoked for each occurrence of a placeholder type; these are + /// used when we instantiate binders universally. + fn visit_free_placeholder( + &mut self, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + if self.forbid_free_placeholders() { + panic!("unexpected placeholder type `{:?}`", universe) + } else { + ControlFlow::Continue(()) + } + } + + /// Invoked for each where clause. + fn visit_where_clause( + &mut self, + where_clause: &WhereClause<I>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + where_clause.super_visit_with(self.as_dyn(), outer_binder) + } + + /// If overridden to return true, inference variables will trigger + /// panics when visited. Used when inference variables are + /// unexpected. + fn forbid_inference_vars(&self) -> bool { + false + } + + /// Invoked for each occurrence of a inference type; these are + /// used when we instantiate binders universally. + fn visit_inference_var( + &mut self, + var: InferenceVar, + _outer_binder: DebruijnIndex, + ) -> ControlFlow<Self::BreakTy> { + if self.forbid_inference_vars() { + panic!("unexpected inference type `{:?}`", var) + } else { + ControlFlow::Continue(()) + } + } + + /// Gets the visitor's interner. + fn interner(&self) -> I; +} + +/// Applies the given `visitor` to a value, producing a visited result +/// of type `Visitor::Result`. +pub trait Visit<I: Interner>: Debug { + /// Apply the given visitor `visitor` to `self`; `binders` is the + /// number of binders that are in scope when beginning the + /// visitor. Typically `binders` starts as 0, but is adjusted when + /// we encounter `Binders<T>` in the IR or other similar + /// constructs. + fn visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B>; +} + +/// For types where "visit" invokes a callback on the `visitor`, the +/// `SuperVisit` trait captures the recursive behavior that visits all +/// the contents of the type. +pub trait SuperVisit<I: Interner>: Visit<I> { + /// Recursively visits the type contents. + fn super_visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B>; +} + +/// "visiting" a type invokes the `visit_ty` method on the visitor; this +/// usually (in turn) invokes `super_visit_ty` to visit the individual +/// parts. +impl<I: Interner> Visit<I> for Ty<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + visitor.visit_ty(self, outer_binder) + } +} + +/// "Super visit" for a type invokes the more detailed callbacks on the type +impl<I> SuperVisit<I> for Ty<I> +where + I: Interner, +{ + fn super_visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + let interner = visitor.interner(); + match self.kind(interner) { + TyKind::BoundVar(bound_var) => { + if bound_var.shifted_out_to(outer_binder).is_some() { + visitor.visit_free_var(*bound_var, outer_binder) + } else { + ControlFlow::Continue(()) + } + } + TyKind::Dyn(clauses) => clauses.visit_with(visitor, outer_binder), + TyKind::InferenceVar(var, _) => visitor.visit_inference_var(*var, outer_binder), + TyKind::Placeholder(ui) => visitor.visit_free_placeholder(*ui, outer_binder), + TyKind::Alias(proj) => proj.visit_with(visitor, outer_binder), + TyKind::Function(fun) => fun.visit_with(visitor, outer_binder), + TyKind::Adt(_id, substitution) => substitution.visit_with(visitor, outer_binder), + TyKind::AssociatedType(_assoc_ty, substitution) => { + substitution.visit_with(visitor, outer_binder) + } + TyKind::Scalar(scalar) => scalar.visit_with(visitor, outer_binder), + TyKind::Str => ControlFlow::Continue(()), + TyKind::Tuple(arity, substitution) => { + try_break!(arity.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::OpaqueType(opaque_ty, substitution) => { + try_break!(opaque_ty.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::Slice(substitution) => substitution.visit_with(visitor, outer_binder), + TyKind::FnDef(fn_def, substitution) => { + try_break!(fn_def.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::Ref(mutability, lifetime, ty) => { + try_break!(mutability.visit_with(visitor, outer_binder)); + try_break!(lifetime.visit_with(visitor, outer_binder)); + ty.visit_with(visitor, outer_binder) + } + TyKind::Raw(mutability, ty) => { + try_break!(mutability.visit_with(visitor, outer_binder)); + ty.visit_with(visitor, outer_binder) + } + TyKind::Never => ControlFlow::Continue(()), + TyKind::Array(ty, const_) => { + try_break!(ty.visit_with(visitor, outer_binder)); + const_.visit_with(visitor, outer_binder) + } + TyKind::Closure(id, substitution) => { + try_break!(id.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::Generator(generator, substitution) => { + try_break!(generator.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::GeneratorWitness(witness, substitution) => { + try_break!(witness.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::Foreign(foreign_ty) => foreign_ty.visit_with(visitor, outer_binder), + TyKind::Error => ControlFlow::Continue(()), + } + } +} + +impl<I: Interner> Visit<I> for Lifetime<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + visitor.visit_lifetime(self, outer_binder) + } +} + +impl<I: Interner> SuperVisit<I> for Lifetime<I> { + fn super_visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + let interner = visitor.interner(); + match self.data(interner) { + LifetimeData::BoundVar(bound_var) => { + if bound_var.shifted_out_to(outer_binder).is_some() { + visitor.visit_free_var(*bound_var, outer_binder) + } else { + ControlFlow::Continue(()) + } + } + LifetimeData::InferenceVar(var) => visitor.visit_inference_var(*var, outer_binder), + LifetimeData::Placeholder(universe) => { + visitor.visit_free_placeholder(*universe, outer_binder) + } + LifetimeData::Static | LifetimeData::Empty(_) | LifetimeData::Erased => { + ControlFlow::Continue(()) + } + LifetimeData::Phantom(void, ..) => match *void {}, + } + } +} + +impl<I: Interner> Visit<I> for Const<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + visitor.visit_const(self, outer_binder) + } +} + +impl<I: Interner> SuperVisit<I> for Const<I> { + fn super_visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + let interner = visitor.interner(); + match &self.data(interner).value { + ConstValue::BoundVar(bound_var) => { + if bound_var.shifted_out_to(outer_binder).is_some() { + visitor.visit_free_var(*bound_var, outer_binder) + } else { + ControlFlow::Continue(()) + } + } + ConstValue::InferenceVar(var) => visitor.visit_inference_var(*var, outer_binder), + ConstValue::Placeholder(universe) => { + visitor.visit_free_placeholder(*universe, outer_binder) + } + ConstValue::Concrete(_) => ControlFlow::Continue(()), + } + } +} + +impl<I: Interner> Visit<I> for Goal<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + visitor.visit_goal(self, outer_binder) + } +} + +impl<I: Interner> SuperVisit<I> for Goal<I> { + fn super_visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + let interner = visitor.interner(); + self.data(interner).visit_with(visitor, outer_binder) + } +} + +impl<I: Interner> Visit<I> for ProgramClause<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + visitor.visit_program_clause(self, outer_binder) + } +} + +impl<I: Interner> Visit<I> for WhereClause<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + visitor.visit_where_clause(self, outer_binder) + } +} + +impl<I: Interner> Visit<I> for DomainGoal<I> { + fn visit_with<B>( + &self, + visitor: &mut dyn Visitor<I, BreakTy = B>, + outer_binder: DebruijnIndex, + ) -> ControlFlow<B> { + visitor.visit_domain_goal(self, outer_binder) + } +} |