]> git.proxmox.com Git - rustc.git/blame - vendor/chalk-ir-0.55.0/src/visit.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / vendor / chalk-ir-0.55.0 / src / visit.rs
CommitLineData
f9f354fc
XL
1//! Traits for visiting bits of IR.
2use std::fmt::Debug;
3
4use crate::{
f035d41b 5 BoundVar, Const, ConstValue, DebruijnIndex, DomainGoal, Goal, InferenceVar, Interner, Lifetime,
29967ef6 6 LifetimeData, PlaceholderIndex, ProgramClause, Ty, TyKind, WhereClause,
f9f354fc
XL
7};
8
9mod binder_impls;
10mod boring_impls;
11pub mod visitors;
12
13pub use visitors::VisitExt;
14
5869c6ff
XL
15/// An copy of the unstable `std::ops::ControlFlow` for use in Chalk visitors.
16pub enum ControlFlow<B, C = ()> {
17 /// Continue in the loop, using the given value for the next iteration
18 Continue(C),
19 /// Exit the loop, yielding the given value
20 Break(B),
21}
22
23impl<B, C> ControlFlow<B, C> {
24 /// Returns `true` if this is a `Break` variant.
25 #[inline]
26 pub fn is_break(&self) -> bool {
27 matches!(*self, ControlFlow::Break(_))
28 }
29
30 /// Returns `true` if this is a `Continue` variant.
31 #[inline]
32 pub fn is_continue(&self) -> bool {
33 matches!(*self, ControlFlow::Continue(_))
34 }
35
36 /// Converts the `ControlFlow` into an `Option` which is `Some`
37 /// if the `ControlFlow` was `Break` and `None` otherwise.
38 #[inline]
39 pub fn break_value(self) -> Option<B> {
40 match self {
41 ControlFlow::Continue(..) => None,
42 ControlFlow::Break(x) => Some(x),
f9f354fc
XL
43 }
44 }
45}
46
5869c6ff
XL
47impl<B> ControlFlow<B, ()> {
48 /// It's frequently the case that there's no value needed with `Continue`,
49 /// so this provides a way to avoid typing `(())`, if you prefer it.
50 pub const CONTINUE: Self = ControlFlow::Continue(());
51}
f9f354fc 52
5869c6ff
XL
53impl<C> ControlFlow<(), C> {
54 /// APIs like `try_for_each` don't need values with `Break`,
55 /// so this provides a way to avoid typing `(())`, if you prefer it.
56 pub const BREAK: Self = ControlFlow::Break(());
57}
58
59/// Unwraps a `ControlFlow` or propagates its `Break` value.
60/// This replaces the `Try` implementation that would be used
61/// with `std::ops::ControlFlow`.
62#[macro_export]
63macro_rules! try_break {
64 ($expr:expr) => {
65 match $expr {
66 $crate::visit::ControlFlow::Continue(c) => c,
67 $crate::visit::ControlFlow::Break(b) => return $crate::visit::ControlFlow::Break(b),
68 }
69 };
f9f354fc
XL
70}
71
72/// A "visitor" recursively folds some term -- that is, some bit of IR,
73/// such as a `Goal`, and computes a value as a result.
74///
75///
76/// To **apply** a visitor, use the `Visit::visit_with` method, like so
77///
78/// ```rust,ignore
79/// let result = x.visit_with(&mut visitor, 0);
80/// ```
81pub trait Visitor<'i, I: Interner>
82where
83 I: 'i,
84{
5869c6ff
XL
85 /// The "break type" of the visitor, often `()`. It represents the result
86 /// the visitor yields when it stops visiting.
87 type BreakTy;
f9f354fc
XL
88
89 /// Creates a `dyn` value from this visitor. Unfortunately, this
90 /// must be added manually to each impl of visitor; it permits the
91 /// default implements below to create a `&mut dyn Visitor` from
92 /// `Self` without knowing what `Self` is (by invoking this
93 /// method). Effectively, this limits impls of `visitor` to types
94 /// for which we are able to create a dyn value (i.e., not `[T]`
95 /// types).
5869c6ff 96 fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, BreakTy = Self::BreakTy>;
f9f354fc
XL
97
98 /// Top-level callback: invoked for each `Ty<I>` that is
99 /// encountered when visiting. By default, invokes
100 /// `super_visit_with`, which will in turn invoke the more
f035d41b 101 /// specialized visiting methods below, like `visit_free_var`.
5869c6ff 102 fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
103 ty.super_visit_with(self.as_dyn(), outer_binder)
104 }
105
106 /// Top-level callback: invoked for each `Lifetime<I>` that is
107 /// encountered when visiting. By default, invokes
108 /// `super_visit_with`, which will in turn invoke the more
f035d41b 109 /// specialized visiting methods below, like `visit_free_var`.
f9f354fc
XL
110 fn visit_lifetime(
111 &mut self,
112 lifetime: &Lifetime<I>,
113 outer_binder: DebruijnIndex,
5869c6ff 114 ) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
115 lifetime.super_visit_with(self.as_dyn(), outer_binder)
116 }
117
f035d41b
XL
118 /// Top-level callback: invoked for each `Const<I>` that is
119 /// encountered when visiting. By default, invokes
120 /// `super_visit_with`, which will in turn invoke the more
121 /// specialized visiting methods below, like `visit_free_var`.
5869c6ff
XL
122 fn visit_const(
123 &mut self,
124 constant: &Const<I>,
125 outer_binder: DebruijnIndex,
126 ) -> ControlFlow<Self::BreakTy> {
f035d41b
XL
127 constant.super_visit_with(self.as_dyn(), outer_binder)
128 }
129
f9f354fc
XL
130 /// Invoked for every program clause. By default, recursively visits the goals contents.
131 fn visit_program_clause(
132 &mut self,
133 clause: &ProgramClause<I>,
134 outer_binder: DebruijnIndex,
5869c6ff 135 ) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
136 clause.super_visit_with(self.as_dyn(), outer_binder)
137 }
138
139 /// Invoked for every goal. By default, recursively visits the goals contents.
5869c6ff
XL
140 fn visit_goal(
141 &mut self,
142 goal: &Goal<I>,
143 outer_binder: DebruijnIndex,
144 ) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
145 goal.super_visit_with(self.as_dyn(), outer_binder)
146 }
147
f035d41b 148 /// Invoked for each domain goal.
f9f354fc
XL
149 fn visit_domain_goal(
150 &mut self,
151 domain_goal: &DomainGoal<I>,
152 outer_binder: DebruijnIndex,
5869c6ff 153 ) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
154 domain_goal.super_visit_with(self.as_dyn(), outer_binder)
155 }
156
157 /// If overridden to return true, then visiting will panic if a
158 /// free variable is encountered. This should be done if free
f035d41b 159 /// type/lifetime/const variables are not expected.
f9f354fc
XL
160 fn forbid_free_vars(&self) -> bool {
161 false
162 }
163
f035d41b 164 /// Invoked for `BoundVar` instances that are not bound
f9f354fc 165 /// within the type being visited over:
5869c6ff
XL
166 fn visit_free_var(
167 &mut self,
168 bound_var: BoundVar,
169 outer_binder: DebruijnIndex,
170 ) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
171 if self.forbid_free_vars() {
172 panic!(
173 "unexpected free variable `{:?}` with outer binder {:?}",
174 bound_var, outer_binder
175 )
176 } else {
5869c6ff 177 ControlFlow::CONTINUE
f9f354fc
XL
178 }
179 }
180
f035d41b 181 /// If overridden to return true, we will panic when a free
f9f354fc
XL
182 /// placeholder type/lifetime is encountered.
183 fn forbid_free_placeholders(&self) -> bool {
184 false
185 }
186
187 /// Invoked for each occurrence of a placeholder type; these are
188 /// used when we instantiate binders universally.
f035d41b 189 fn visit_free_placeholder(
f9f354fc
XL
190 &mut self,
191 universe: PlaceholderIndex,
192 _outer_binder: DebruijnIndex,
5869c6ff 193 ) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
194 if self.forbid_free_placeholders() {
195 panic!("unexpected placeholder type `{:?}`", universe)
196 } else {
5869c6ff 197 ControlFlow::CONTINUE
f9f354fc
XL
198 }
199 }
200
f035d41b 201 /// Invoked for each where clause.
f9f354fc
XL
202 fn visit_where_clause(
203 &mut self,
204 where_clause: &WhereClause<I>,
205 outer_binder: DebruijnIndex,
5869c6ff 206 ) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
207 where_clause.super_visit_with(self.as_dyn(), outer_binder)
208 }
209
f9f354fc
XL
210 /// If overridden to return true, inference variables will trigger
211 /// panics when visited. Used when inference variables are
212 /// unexpected.
213 fn forbid_inference_vars(&self) -> bool {
214 false
215 }
216
217 /// Invoked for each occurrence of a inference type; these are
218 /// used when we instantiate binders universally.
f035d41b 219 fn visit_inference_var(
f9f354fc
XL
220 &mut self,
221 var: InferenceVar,
222 _outer_binder: DebruijnIndex,
5869c6ff 223 ) -> ControlFlow<Self::BreakTy> {
f9f354fc
XL
224 if self.forbid_inference_vars() {
225 panic!("unexpected inference type `{:?}`", var)
226 } else {
5869c6ff 227 ControlFlow::CONTINUE
f9f354fc
XL
228 }
229 }
230
f035d41b 231 /// Gets the visitor's interner.
f9f354fc
XL
232 fn interner(&self) -> &'i I;
233}
234
235/// Applies the given `visitor` to a value, producing a visited result
236/// of type `Visitor::Result`.
237pub trait Visit<I: Interner>: Debug {
238 /// Apply the given visitor `visitor` to `self`; `binders` is the
239 /// number of binders that are in scope when beginning the
240 /// visitor. Typically `binders` starts as 0, but is adjusted when
241 /// we encounter `Binders<T>` in the IR or other similar
242 /// constructs.
5869c6ff 243 fn visit_with<'i, B>(
f9f354fc 244 &self,
5869c6ff 245 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 246 outer_binder: DebruijnIndex,
5869c6ff 247 ) -> ControlFlow<B>
f9f354fc
XL
248 where
249 I: 'i;
250}
251
252/// For types where "visit" invokes a callback on the `visitor`, the
253/// `SuperVisit` trait captures the recursive behavior that visits all
254/// the contents of the type.
255pub trait SuperVisit<I: Interner>: Visit<I> {
f035d41b 256 /// Recursively visits the type contents.
5869c6ff 257 fn super_visit_with<'i, B>(
f9f354fc 258 &self,
5869c6ff 259 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 260 outer_binder: DebruijnIndex,
5869c6ff 261 ) -> ControlFlow<B>
f9f354fc
XL
262 where
263 I: 'i;
264}
265
266/// "visiting" a type invokes the `visit_ty` method on the visitor; this
267/// usually (in turn) invokes `super_visit_ty` to visit the individual
268/// parts.
269impl<I: Interner> Visit<I> for Ty<I> {
5869c6ff 270 fn visit_with<'i, B>(
f9f354fc 271 &self,
5869c6ff 272 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 273 outer_binder: DebruijnIndex,
5869c6ff 274 ) -> ControlFlow<B>
f9f354fc
XL
275 where
276 I: 'i,
277 {
278 visitor.visit_ty(self, outer_binder)
279 }
280}
281
5869c6ff 282/// "Super visit" for a type invokes the more detailed callbacks on the type
f9f354fc
XL
283impl<I> SuperVisit<I> for Ty<I>
284where
285 I: Interner,
286{
5869c6ff 287 fn super_visit_with<'i, B>(
f9f354fc 288 &self,
5869c6ff 289 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 290 outer_binder: DebruijnIndex,
5869c6ff 291 ) -> ControlFlow<B>
f9f354fc
XL
292 where
293 I: 'i,
294 {
295 let interner = visitor.interner();
29967ef6
XL
296 match self.kind(interner) {
297 TyKind::BoundVar(bound_var) => {
f9f354fc 298 if let Some(_) = bound_var.shifted_out_to(outer_binder) {
f035d41b 299 visitor.visit_free_var(*bound_var, outer_binder)
f9f354fc 300 } else {
5869c6ff 301 ControlFlow::CONTINUE
f9f354fc
XL
302 }
303 }
29967ef6
XL
304 TyKind::Dyn(clauses) => clauses.visit_with(visitor, outer_binder),
305 TyKind::InferenceVar(var, _) => visitor.visit_inference_var(*var, outer_binder),
306 TyKind::Placeholder(ui) => visitor.visit_free_placeholder(*ui, outer_binder),
307 TyKind::Alias(proj) => proj.visit_with(visitor, outer_binder),
308 TyKind::Function(fun) => fun.visit_with(visitor, outer_binder),
309 TyKind::Adt(_id, substitution) => substitution.visit_with(visitor, outer_binder),
310 TyKind::AssociatedType(_assoc_ty, substitution) => {
311 substitution.visit_with(visitor, outer_binder)
312 }
313 TyKind::Scalar(scalar) => scalar.visit_with(visitor, outer_binder),
5869c6ff
XL
314 TyKind::Str => ControlFlow::CONTINUE,
315 TyKind::Tuple(arity, substitution) => {
316 try_break!(arity.visit_with(visitor, outer_binder));
317 substitution.visit_with(visitor, outer_binder)
318 }
319 TyKind::OpaqueType(opaque_ty, substitution) => {
320 try_break!(opaque_ty.visit_with(visitor, outer_binder));
321 substitution.visit_with(visitor, outer_binder)
322 }
29967ef6 323 TyKind::Slice(substitution) => substitution.visit_with(visitor, outer_binder),
5869c6ff
XL
324 TyKind::FnDef(fn_def, substitution) => {
325 try_break!(fn_def.visit_with(visitor, outer_binder));
326 substitution.visit_with(visitor, outer_binder)
327 }
29967ef6 328 TyKind::Ref(mutability, lifetime, ty) => {
5869c6ff
XL
329 try_break!(mutability.visit_with(visitor, outer_binder));
330 try_break!(lifetime.visit_with(visitor, outer_binder));
331 ty.visit_with(visitor, outer_binder)
332 }
333 TyKind::Raw(mutability, ty) => {
334 try_break!(mutability.visit_with(visitor, outer_binder));
335 ty.visit_with(visitor, outer_binder)
336 }
337 TyKind::Never => ControlFlow::CONTINUE,
338 TyKind::Array(ty, const_) => {
339 try_break!(ty.visit_with(visitor, outer_binder));
340 const_.visit_with(visitor, outer_binder)
341 }
342 TyKind::Closure(id, substitution) => {
343 try_break!(id.visit_with(visitor, outer_binder));
344 substitution.visit_with(visitor, outer_binder)
345 }
346 TyKind::Generator(generator, substitution) => {
347 try_break!(generator.visit_with(visitor, outer_binder));
348 substitution.visit_with(visitor, outer_binder)
349 }
350 TyKind::GeneratorWitness(witness, substitution) => {
351 try_break!(witness.visit_with(visitor, outer_binder));
352 substitution.visit_with(visitor, outer_binder)
29967ef6 353 }
29967ef6 354 TyKind::Foreign(foreign_ty) => foreign_ty.visit_with(visitor, outer_binder),
5869c6ff 355 TyKind::Error => ControlFlow::CONTINUE,
f9f354fc
XL
356 }
357 }
358}
359
360impl<I: Interner> Visit<I> for Lifetime<I> {
5869c6ff 361 fn visit_with<'i, B>(
f9f354fc 362 &self,
5869c6ff 363 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 364 outer_binder: DebruijnIndex,
5869c6ff 365 ) -> ControlFlow<B>
f9f354fc
XL
366 where
367 I: 'i,
368 {
369 visitor.visit_lifetime(self, outer_binder)
370 }
371}
372
373impl<I: Interner> SuperVisit<I> for Lifetime<I> {
5869c6ff 374 fn super_visit_with<'i, B>(
f9f354fc 375 &self,
5869c6ff 376 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 377 outer_binder: DebruijnIndex,
5869c6ff 378 ) -> ControlFlow<B>
f9f354fc
XL
379 where
380 I: 'i,
381 {
382 let interner = visitor.interner();
383 match self.data(interner) {
384 LifetimeData::BoundVar(bound_var) => {
385 if let Some(_) = bound_var.shifted_out_to(outer_binder) {
f035d41b 386 visitor.visit_free_var(*bound_var, outer_binder)
f9f354fc 387 } else {
5869c6ff 388 ControlFlow::CONTINUE
f9f354fc
XL
389 }
390 }
f035d41b 391 LifetimeData::InferenceVar(var) => visitor.visit_inference_var(*var, outer_binder),
f9f354fc 392 LifetimeData::Placeholder(universe) => {
f035d41b 393 visitor.visit_free_placeholder(*universe, outer_binder)
f9f354fc 394 }
5869c6ff
XL
395 LifetimeData::Static | LifetimeData::Empty(_) | LifetimeData::Erased => {
396 ControlFlow::CONTINUE
397 }
398 LifetimeData::Phantom(void, ..) => match *void {},
f9f354fc
XL
399 }
400 }
401}
402
f035d41b 403impl<I: Interner> Visit<I> for Const<I> {
5869c6ff 404 fn visit_with<'i, B>(
f035d41b 405 &self,
5869c6ff 406 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f035d41b 407 outer_binder: DebruijnIndex,
5869c6ff 408 ) -> ControlFlow<B>
f035d41b
XL
409 where
410 I: 'i,
411 {
412 visitor.visit_const(self, outer_binder)
413 }
414}
415
416impl<I: Interner> SuperVisit<I> for Const<I> {
5869c6ff 417 fn super_visit_with<'i, B>(
f035d41b 418 &self,
5869c6ff 419 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f035d41b 420 outer_binder: DebruijnIndex,
5869c6ff 421 ) -> ControlFlow<B>
f035d41b
XL
422 where
423 I: 'i,
424 {
425 let interner = visitor.interner();
426 match &self.data(interner).value {
427 ConstValue::BoundVar(bound_var) => {
428 if let Some(_) = bound_var.shifted_out_to(outer_binder) {
429 visitor.visit_free_var(*bound_var, outer_binder)
430 } else {
5869c6ff 431 ControlFlow::CONTINUE
f035d41b
XL
432 }
433 }
434 ConstValue::InferenceVar(var) => visitor.visit_inference_var(*var, outer_binder),
435 ConstValue::Placeholder(universe) => {
436 visitor.visit_free_placeholder(*universe, outer_binder)
437 }
5869c6ff 438 ConstValue::Concrete(_) => ControlFlow::CONTINUE,
f035d41b
XL
439 }
440 }
441}
442
f9f354fc 443impl<I: Interner> Visit<I> for Goal<I> {
5869c6ff 444 fn visit_with<'i, B>(
f9f354fc 445 &self,
5869c6ff 446 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 447 outer_binder: DebruijnIndex,
5869c6ff 448 ) -> ControlFlow<B>
f9f354fc
XL
449 where
450 I: 'i,
451 {
452 visitor.visit_goal(self, outer_binder)
453 }
454}
455
456impl<I: Interner> SuperVisit<I> for Goal<I> {
5869c6ff 457 fn super_visit_with<'i, B>(
f9f354fc 458 &self,
5869c6ff 459 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 460 outer_binder: DebruijnIndex,
5869c6ff 461 ) -> ControlFlow<B>
f9f354fc
XL
462 where
463 I: 'i,
464 {
465 let interner = visitor.interner();
466 self.data(interner).visit_with(visitor, outer_binder)
467 }
468}
469
470impl<I: Interner> Visit<I> for ProgramClause<I> {
5869c6ff 471 fn visit_with<'i, B>(
f9f354fc 472 &self,
5869c6ff 473 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 474 outer_binder: DebruijnIndex,
5869c6ff 475 ) -> ControlFlow<B>
f9f354fc
XL
476 where
477 I: 'i,
478 {
479 visitor.visit_program_clause(self, outer_binder)
480 }
481}
482
483impl<I: Interner> Visit<I> for WhereClause<I> {
5869c6ff 484 fn visit_with<'i, B>(
f9f354fc 485 &self,
5869c6ff 486 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 487 outer_binder: DebruijnIndex,
5869c6ff 488 ) -> ControlFlow<B>
f9f354fc
XL
489 where
490 I: 'i,
491 {
492 visitor.visit_where_clause(self, outer_binder)
493 }
494}
495
496impl<I: Interner> Visit<I> for DomainGoal<I> {
5869c6ff 497 fn visit_with<'i, B>(
f9f354fc 498 &self,
5869c6ff 499 visitor: &mut dyn Visitor<'i, I, BreakTy = B>,
f9f354fc 500 outer_binder: DebruijnIndex,
5869c6ff 501 ) -> ControlFlow<B>
f9f354fc
XL
502 where
503 I: 'i,
504 {
505 visitor.visit_domain_goal(self, outer_binder)
506 }
507}