]>
git.proxmox.com Git - rustc.git/blob - vendor/chalk-ir-0.14.0/src/visit.rs
1 //! Traits for visiting bits of IR.
5 BoundVar
, Const
, ConstValue
, DebruijnIndex
, DomainGoal
, Goal
, InferenceVar
, Interner
, Lifetime
,
6 LifetimeData
, PlaceholderIndex
, ProgramClause
, Ty
, TyData
, WhereClause
,
13 pub use visitors
::VisitExt
;
15 /// A "result type" that can be returned from a visitor. Visitors pick
16 /// an appropriate result type depending on what sort of operation they
17 /// are doing. A common choice is `FindAny`, which indicates that the visitor
18 /// is searching for something and that the visitor should stop once it is found.
19 pub trait VisitResult
: Sized
{
22 /// Returns true if this result is "complete" and we can stop visiting any
23 /// further parts of the term. This is used by `FindAny`, for example, to
24 /// stop the search after a match has been found.
25 fn return_early(&self) -> bool
;
26 fn combine(self, other
: Self) -> Self;
28 /// Convenience helper for use in writing `Visitor` impls. Returns `self`
29 /// if `return_early()` is true, but otherwise combines `self` with the
30 /// result of invoking `op`.
32 /// If you have a struct with two fields, `foo` and `bar`, you can
33 /// thus write code like
36 /// self.foo.visit_with(visitor, outer_binder)
37 /// .and_then(|| self.bar.visit_with(visitor, outer_binder))
40 /// and `bar` will only be visited if necessary.
41 fn and_then(self, op
: impl FnOnce() -> Self) -> Self {
42 if self.return_early() {
50 /// Unit type for a visitor indicates a "side-effecting" visitor that
51 /// should visit an entire term.
52 impl VisitResult
for () {
55 fn return_early(&self) -> bool
{
58 fn combine(self, _other
: Self) {}
61 /// A "visitor" recursively folds some term -- that is, some bit of IR,
62 /// such as a `Goal`, and computes a value as a result.
65 /// To **apply** a visitor, use the `Visit::visit_with` method, like so
68 /// let result = x.visit_with(&mut visitor, 0);
70 pub trait Visitor
<'i
, I
: Interner
>
74 type Result
: VisitResult
;
76 /// Creates a `dyn` value from this visitor. Unfortunately, this
77 /// must be added manually to each impl of visitor; it permits the
78 /// default implements below to create a `&mut dyn Visitor` from
79 /// `Self` without knowing what `Self` is (by invoking this
80 /// method). Effectively, this limits impls of `visitor` to types
81 /// for which we are able to create a dyn value (i.e., not `[T]`
83 fn as_dyn(&mut self) -> &mut dyn Visitor
<'i
, I
, Result
= Self::Result
>;
85 /// Top-level callback: invoked for each `Ty<I>` that is
86 /// encountered when visiting. By default, invokes
87 /// `super_visit_with`, which will in turn invoke the more
88 /// specialized visiting methods below, like `visit_free_var`.
89 fn visit_ty(&mut self, ty
: &Ty
<I
>, outer_binder
: DebruijnIndex
) -> Self::Result
{
90 ty
.super_visit_with(self.as_dyn(), outer_binder
)
93 /// Top-level callback: invoked for each `Lifetime<I>` that is
94 /// encountered when visiting. By default, invokes
95 /// `super_visit_with`, which will in turn invoke the more
96 /// specialized visiting methods below, like `visit_free_var`.
99 lifetime
: &Lifetime
<I
>,
100 outer_binder
: DebruijnIndex
,
102 lifetime
.super_visit_with(self.as_dyn(), outer_binder
)
105 /// Top-level callback: invoked for each `Const<I>` that is
106 /// encountered when visiting. By default, invokes
107 /// `super_visit_with`, which will in turn invoke the more
108 /// specialized visiting methods below, like `visit_free_var`.
109 fn visit_const(&mut self, constant
: &Const
<I
>, outer_binder
: DebruijnIndex
) -> Self::Result
{
110 constant
.super_visit_with(self.as_dyn(), outer_binder
)
113 /// Invoked for every program clause. By default, recursively visits the goals contents.
114 fn visit_program_clause(
116 clause
: &ProgramClause
<I
>,
117 outer_binder
: DebruijnIndex
,
119 clause
.super_visit_with(self.as_dyn(), outer_binder
)
122 /// Invoked for every goal. By default, recursively visits the goals contents.
123 fn visit_goal(&mut self, goal
: &Goal
<I
>, outer_binder
: DebruijnIndex
) -> Self::Result
{
124 goal
.super_visit_with(self.as_dyn(), outer_binder
)
127 fn visit_domain_goal(
129 domain_goal
: &DomainGoal
<I
>,
130 outer_binder
: DebruijnIndex
,
132 domain_goal
.super_visit_with(self.as_dyn(), outer_binder
)
135 /// If overridden to return true, then visiting will panic if a
136 /// free variable is encountered. This should be done if free
137 /// type/lifetime/const variables are not expected.
138 fn forbid_free_vars(&self) -> bool
{
142 /// Invoked for `BoundVar` instances that are not bound
143 /// within the type being visited over:
144 fn visit_free_var(&mut self, bound_var
: BoundVar
, outer_binder
: DebruijnIndex
) -> Self::Result
{
145 if self.forbid_free_vars() {
147 "unexpected free variable `{:?}` with outer binder {:?}",
148 bound_var
, outer_binder
155 /// If overridden to return true, we will panic when a free
156 /// placeholder type/lifetime is encountered.
157 fn forbid_free_placeholders(&self) -> bool
{
161 /// Invoked for each occurrence of a placeholder type; these are
162 /// used when we instantiate binders universally.
163 fn visit_free_placeholder(
165 universe
: PlaceholderIndex
,
166 _outer_binder
: DebruijnIndex
,
168 if self.forbid_free_placeholders() {
169 panic
!("unexpected placeholder type `{:?}`", universe
)
175 fn visit_where_clause(
177 where_clause
: &WhereClause
<I
>,
178 outer_binder
: DebruijnIndex
,
180 where_clause
.super_visit_with(self.as_dyn(), outer_binder
)
183 /// If overridden to return true, inference variables will trigger
184 /// panics when visited. Used when inference variables are
186 fn forbid_inference_vars(&self) -> bool
{
190 /// Invoked for each occurrence of a inference type; these are
191 /// used when we instantiate binders universally.
192 fn visit_inference_var(
195 _outer_binder
: DebruijnIndex
,
197 if self.forbid_inference_vars() {
198 panic
!("unexpected inference type `{:?}`", var
)
204 fn interner(&self) -> &'i I
;
207 /// Applies the given `visitor` to a value, producing a visited result
208 /// of type `Visitor::Result`.
209 pub trait Visit
<I
: Interner
>: Debug
{
210 /// Apply the given visitor `visitor` to `self`; `binders` is the
211 /// number of binders that are in scope when beginning the
212 /// visitor. Typically `binders` starts as 0, but is adjusted when
213 /// we encounter `Binders<T>` in the IR or other similar
215 fn visit_with
<'i
, R
: VisitResult
>(
217 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
218 outer_binder
: DebruijnIndex
,
224 /// For types where "visit" invokes a callback on the `visitor`, the
225 /// `SuperVisit` trait captures the recursive behavior that visits all
226 /// the contents of the type.
227 pub trait SuperVisit
<I
: Interner
>: Visit
<I
> {
228 fn super_visit_with
<'i
, R
: VisitResult
>(
230 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
231 outer_binder
: DebruijnIndex
,
237 /// "visiting" a type invokes the `visit_ty` method on the visitor; this
238 /// usually (in turn) invokes `super_visit_ty` to visit the individual
240 impl<I
: Interner
> Visit
<I
> for Ty
<I
> {
241 fn visit_with
<'i
, R
: VisitResult
>(
243 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
244 outer_binder
: DebruijnIndex
,
249 visitor
.visit_ty(self, outer_binder
)
253 /// "Super visit" for a type invokes te more detailed callbacks on the type
254 impl<I
> SuperVisit
<I
> for Ty
<I
>
258 fn super_visit_with
<'i
, R
: VisitResult
>(
260 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
261 outer_binder
: DebruijnIndex
,
266 let interner
= visitor
.interner();
267 match self.data(interner
) {
268 TyData
::BoundVar(bound_var
) => {
269 if let Some(_
) = bound_var
.shifted_out_to(outer_binder
) {
270 visitor
.visit_free_var(*bound_var
, outer_binder
)
275 TyData
::Dyn(clauses
) => clauses
.visit_with(visitor
, outer_binder
),
276 TyData
::InferenceVar(var
, _
) => visitor
.visit_inference_var(*var
, outer_binder
),
277 TyData
::Apply(apply
) => apply
.visit_with(visitor
, outer_binder
),
278 TyData
::Placeholder(ui
) => visitor
.visit_free_placeholder(*ui
, outer_binder
),
279 TyData
::Alias(proj
) => proj
.visit_with(visitor
, outer_binder
),
280 TyData
::Function(fun
) => fun
.visit_with(visitor
, outer_binder
),
285 impl<I
: Interner
> Visit
<I
> for Lifetime
<I
> {
286 fn visit_with
<'i
, R
: VisitResult
>(
288 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
289 outer_binder
: DebruijnIndex
,
294 visitor
.visit_lifetime(self, outer_binder
)
298 impl<I
: Interner
> SuperVisit
<I
> for Lifetime
<I
> {
299 fn super_visit_with
<'i
, R
: VisitResult
>(
301 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
302 outer_binder
: DebruijnIndex
,
307 let interner
= visitor
.interner();
308 match self.data(interner
) {
309 LifetimeData
::BoundVar(bound_var
) => {
310 if let Some(_
) = bound_var
.shifted_out_to(outer_binder
) {
311 visitor
.visit_free_var(*bound_var
, outer_binder
)
316 LifetimeData
::InferenceVar(var
) => visitor
.visit_inference_var(*var
, outer_binder
),
317 LifetimeData
::Placeholder(universe
) => {
318 visitor
.visit_free_placeholder(*universe
, outer_binder
)
320 LifetimeData
::Phantom(..) => unreachable
!(),
325 impl<I
: Interner
> Visit
<I
> for Const
<I
> {
326 fn visit_with
<'i
, R
: VisitResult
>(
328 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
329 outer_binder
: DebruijnIndex
,
334 visitor
.visit_const(self, outer_binder
)
338 impl<I
: Interner
> SuperVisit
<I
> for Const
<I
> {
339 fn super_visit_with
<'i
, R
: VisitResult
>(
341 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
342 outer_binder
: DebruijnIndex
,
347 let interner
= visitor
.interner();
348 match &self.data(interner
).value
{
349 ConstValue
::BoundVar(bound_var
) => {
350 if let Some(_
) = bound_var
.shifted_out_to(outer_binder
) {
351 visitor
.visit_free_var(*bound_var
, outer_binder
)
356 ConstValue
::InferenceVar(var
) => visitor
.visit_inference_var(*var
, outer_binder
),
357 ConstValue
::Placeholder(universe
) => {
358 visitor
.visit_free_placeholder(*universe
, outer_binder
)
360 ConstValue
::Concrete(_
) => R
::new(),
365 impl<I
: Interner
> Visit
<I
> for Goal
<I
> {
366 fn visit_with
<'i
, R
: VisitResult
>(
368 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
369 outer_binder
: DebruijnIndex
,
374 visitor
.visit_goal(self, outer_binder
)
378 impl<I
: Interner
> SuperVisit
<I
> for Goal
<I
> {
379 fn super_visit_with
<'i
, R
: VisitResult
>(
381 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
382 outer_binder
: DebruijnIndex
,
387 let interner
= visitor
.interner();
388 self.data(interner
).visit_with(visitor
, outer_binder
)
392 impl<I
: Interner
> Visit
<I
> for ProgramClause
<I
> {
393 fn visit_with
<'i
, R
: VisitResult
>(
395 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
396 outer_binder
: DebruijnIndex
,
401 visitor
.visit_program_clause(self, outer_binder
)
405 impl<I
: Interner
> Visit
<I
> for WhereClause
<I
> {
406 fn visit_with
<'i
, R
: VisitResult
>(
408 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
409 outer_binder
: DebruijnIndex
,
414 visitor
.visit_where_clause(self, outer_binder
)
418 impl<I
: Interner
> Visit
<I
> for DomainGoal
<I
> {
419 fn visit_with
<'i
, R
: VisitResult
>(
421 visitor
: &mut dyn Visitor
<'i
, I
, Result
= R
>,
422 outer_binder
: DebruijnIndex
,
427 visitor
.visit_domain_goal(self, outer_binder
)