chalk_ir/fold.rs
1//! Traits for transforming bits of IR.
2
3use crate::*;
4use std::convert::Infallible;
5use std::fmt::Debug;
6
7mod binder_impls;
8mod boring_impls;
9mod in_place;
10pub mod shift;
11mod subst;
12
13pub use self::shift::Shift;
14pub use self::subst::Subst;
15
16/// A "folder" is a transformer that can be used to make a copy of
17/// some term -- that is, some bit of IR, such as a `Goal` -- with
18/// certain changes applied. The idea is that it contains methods that
19/// let you swap types/lifetimes for new types/lifetimes; meanwhile,
20/// each bit of IR implements the `TypeFoldable` trait which, given a
21/// `FallibleTypeFolder`, will reconstruct itself, invoking the folder's
22/// methods to transform each of the types/lifetimes embedded within.
23///
24/// As the name suggests, folds performed by `FallibleTypeFolder` can
25/// fail (with type `Error`); if the folder cannot fail, consider
26/// implementing `TypeFolder` instead (which is an infallible, but
27/// otherwise equivalent, trait).
28///
29/// # Usage patterns
30///
31/// ## Substituting for free variables
32///
33/// Most of the time, though, we are not interested in adjust
34/// arbitrary types/lifetimes, but rather just free variables (even
35/// more often, just free existential variables) that appear within
36/// the term.
37///
38/// For this reason, the `FallibleTypeFolder` trait extends two other
39/// traits that contain methods that are invoked when just those particular
40///
41/// In particular, folders can intercept references to free variables
42/// (either existentially or universally quantified) and replace them
43/// with other types/lifetimes as appropriate.
44///
45/// To create a folder `F`, one never implements `FallibleTypeFolder`
46/// directly, but instead implements one of each of these three sub-traits:
47///
48/// - `FreeVarFolder` -- folds `BoundVar` instances that appear free
49/// in the term being folded (use `DefaultFreeVarFolder` to
50/// ignore/forbid these altogether)
51/// - `InferenceFolder` -- folds existential `InferenceVar` instances
52/// that appear in the term being folded (use
53/// `DefaultInferenceFolder` to ignore/forbid these altogether)
54/// - `PlaceholderFolder` -- folds universal `Placeholder` instances
55/// that appear in the term being folded (use
56/// `DefaultPlaceholderFolder` to ignore/forbid these altogether)
57///
58/// To **apply** a folder, use the `TypeFoldable::try_fold_with` method,
59/// like so
60///
61/// ```rust,ignore
62/// let x = x.try_fold_with(&mut folder, 0);
63/// ```
64pub trait FallibleTypeFolder<I: Interner> {
65 /// The type this folder returns when folding fails. This is
66 /// commonly [`NoSolution`].
67 type Error;
68
69 /// Creates a `dyn` value from this folder. Unfortunately, this
70 /// must be added manually to each impl of FallibleTypeFolder; it
71 /// permits the default implements below to create a
72 /// `&mut dyn FallibleTypeFolder` from `Self` without knowing what
73 /// `Self` is (by invoking this method). Effectively, this limits
74 /// impls of `FallibleTypeFolder` to types for which we are able to
75 /// create a dyn value (i.e., not `[T]` types).
76 fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<I, Error = Self::Error>;
77
78 /// Top-level callback: invoked for each `Ty<I>` that is
79 /// encountered when folding. By default, invokes
80 /// `try_super_fold_with`, which will in turn invoke the more
81 /// specialized folding methods below, like `try_fold_free_var_ty`.
82 fn try_fold_ty(
83 &mut self,
84 ty: Ty<I>,
85 outer_binder: DebruijnIndex,
86 ) -> Result<Ty<I>, Self::Error> {
87 ty.try_super_fold_with(self.as_dyn(), outer_binder)
88 }
89
90 /// Top-level callback: invoked for each `Lifetime<I>` that is
91 /// encountered when folding. By default, invokes
92 /// `try_super_fold_with`, which will in turn invoke the more
93 /// specialized folding methods below, like `try_fold_free_var_lifetime`.
94 fn try_fold_lifetime(
95 &mut self,
96 lifetime: Lifetime<I>,
97 outer_binder: DebruijnIndex,
98 ) -> Result<Lifetime<I>, Self::Error> {
99 lifetime.try_super_fold_with(self.as_dyn(), outer_binder)
100 }
101
102 /// Top-level callback: invoked for each `Const<I>` that is
103 /// encountered when folding. By default, invokes
104 /// `try_super_fold_with`, which will in turn invoke the more
105 /// specialized folding methods below, like `try_fold_free_var_const`.
106 fn try_fold_const(
107 &mut self,
108 constant: Const<I>,
109 outer_binder: DebruijnIndex,
110 ) -> Result<Const<I>, Self::Error> {
111 constant.try_super_fold_with(self.as_dyn(), outer_binder)
112 }
113
114 /// Invoked for every program clause. By default, recursively folds the goals contents.
115 fn try_fold_program_clause(
116 &mut self,
117 clause: ProgramClause<I>,
118 outer_binder: DebruijnIndex,
119 ) -> Result<ProgramClause<I>, Self::Error> {
120 clause.try_super_fold_with(self.as_dyn(), outer_binder)
121 }
122
123 /// Invoked for every goal. By default, recursively folds the goals contents.
124 fn try_fold_goal(
125 &mut self,
126 goal: Goal<I>,
127 outer_binder: DebruijnIndex,
128 ) -> Result<Goal<I>, Self::Error> {
129 goal.try_super_fold_with(self.as_dyn(), outer_binder)
130 }
131
132 /// If overridden to return true, then folding will panic if a
133 /// free variable is encountered. This should be done if free
134 /// type/lifetime variables are not expected.
135 fn forbid_free_vars(&self) -> bool {
136 false
137 }
138
139 /// Invoked for `TyKind::BoundVar` instances that are not bound
140 /// within the type being folded over:
141 ///
142 /// - `depth` is the depth of the `TyKind::BoundVar`; this has
143 /// been adjusted to account for binders in scope.
144 /// - `binders` is the number of binders in scope.
145 ///
146 /// This should return a type suitable for a context with
147 /// `binders` in scope.
148 fn try_fold_free_var_ty(
149 &mut self,
150 bound_var: BoundVar,
151 outer_binder: DebruijnIndex,
152 ) -> Result<Ty<I>, Self::Error> {
153 if self.forbid_free_vars() {
154 panic!(
155 "unexpected free variable with depth `{:?}` with outer binder {:?}",
156 bound_var, outer_binder
157 )
158 } else {
159 let bound_var = bound_var.shifted_in_from(outer_binder);
160 Ok(TyKind::<I>::BoundVar(bound_var).intern(self.interner()))
161 }
162 }
163
164 /// As `try_fold_free_var_ty`, but for lifetimes.
165 fn try_fold_free_var_lifetime(
166 &mut self,
167 bound_var: BoundVar,
168 outer_binder: DebruijnIndex,
169 ) -> Result<Lifetime<I>, Self::Error> {
170 if self.forbid_free_vars() {
171 panic!(
172 "unexpected free variable with depth `{:?}` with outer binder {:?}",
173 bound_var, outer_binder
174 )
175 } else {
176 let bound_var = bound_var.shifted_in_from(outer_binder);
177 Ok(LifetimeData::<I>::BoundVar(bound_var).intern(self.interner()))
178 }
179 }
180
181 /// As `try_fold_free_var_ty`, but for constants.
182 fn try_fold_free_var_const(
183 &mut self,
184 ty: Ty<I>,
185 bound_var: BoundVar,
186 outer_binder: DebruijnIndex,
187 ) -> Result<Const<I>, Self::Error> {
188 if self.forbid_free_vars() {
189 panic!(
190 "unexpected free variable with depth `{:?}` with outer binder {:?}",
191 bound_var, outer_binder
192 )
193 } else {
194 let bound_var = bound_var.shifted_in_from(outer_binder);
195 Ok(ConstData {
196 ty: ty.try_fold_with(self.as_dyn(), outer_binder)?,
197 value: ConstValue::<I>::BoundVar(bound_var),
198 }
199 .intern(self.interner()))
200 }
201 }
202
203 /// If overridden to return true, we will panic when a free
204 /// placeholder type/lifetime/const is encountered.
205 fn forbid_free_placeholders(&self) -> bool {
206 false
207 }
208
209 /// Invoked for each occurrence of a placeholder type; these are
210 /// used when we instantiate binders universally. Returns a type
211 /// to use instead, which should be suitably shifted to account
212 /// for `binders`.
213 ///
214 /// - `universe` is the universe of the `TypeName::ForAll` that was found
215 /// - `binders` is the number of binders in scope
216 #[allow(unused_variables)]
217 fn try_fold_free_placeholder_ty(
218 &mut self,
219 universe: PlaceholderIndex,
220 outer_binder: DebruijnIndex,
221 ) -> Result<Ty<I>, Self::Error> {
222 if self.forbid_free_placeholders() {
223 panic!("unexpected placeholder type `{:?}`", universe)
224 } else {
225 Ok(universe.to_ty::<I>(self.interner()))
226 }
227 }
228
229 /// As with `try_fold_free_placeholder_ty`, but for lifetimes.
230 #[allow(unused_variables)]
231 fn try_fold_free_placeholder_lifetime(
232 &mut self,
233 universe: PlaceholderIndex,
234 outer_binder: DebruijnIndex,
235 ) -> Result<Lifetime<I>, Self::Error> {
236 if self.forbid_free_placeholders() {
237 panic!("unexpected placeholder lifetime `{:?}`", universe)
238 } else {
239 Ok(universe.to_lifetime(self.interner()))
240 }
241 }
242
243 /// As with `try_fold_free_placeholder_ty`, but for constants.
244 #[allow(unused_variables)]
245 fn try_fold_free_placeholder_const(
246 &mut self,
247 ty: Ty<I>,
248 universe: PlaceholderIndex,
249 outer_binder: DebruijnIndex,
250 ) -> Result<Const<I>, Self::Error> {
251 if self.forbid_free_placeholders() {
252 panic!("unexpected placeholder const `{:?}`", universe)
253 } else {
254 Ok(universe.to_const(
255 self.interner(),
256 ty.try_fold_with(self.as_dyn(), outer_binder)?,
257 ))
258 }
259 }
260
261 /// If overridden to return true, inference variables will trigger
262 /// panics when folded. Used when inference variables are
263 /// unexpected.
264 fn forbid_inference_vars(&self) -> bool {
265 false
266 }
267
268 /// Invoked for each occurrence of a inference type; these are
269 /// used when we instantiate binders universally. Returns a type
270 /// to use instead, which should be suitably shifted to account
271 /// for `binders`.
272 ///
273 /// - `universe` is the universe of the `TypeName::ForAll` that was found
274 /// - `binders` is the number of binders in scope
275 #[allow(unused_variables)]
276 fn try_fold_inference_ty(
277 &mut self,
278 var: InferenceVar,
279 kind: TyVariableKind,
280 outer_binder: DebruijnIndex,
281 ) -> Result<Ty<I>, Self::Error> {
282 if self.forbid_inference_vars() {
283 panic!("unexpected inference type `{:?}`", var)
284 } else {
285 Ok(var.to_ty(self.interner(), kind))
286 }
287 }
288
289 /// As with `try_fold_inference_ty`, but for lifetimes.
290 #[allow(unused_variables)]
291 fn try_fold_inference_lifetime(
292 &mut self,
293 var: InferenceVar,
294 outer_binder: DebruijnIndex,
295 ) -> Result<Lifetime<I>, Self::Error> {
296 if self.forbid_inference_vars() {
297 panic!("unexpected inference lifetime `'{:?}`", var)
298 } else {
299 Ok(var.to_lifetime(self.interner()))
300 }
301 }
302
303 /// As with `try_fold_inference_ty`, but for constants.
304 #[allow(unused_variables)]
305 fn try_fold_inference_const(
306 &mut self,
307 ty: Ty<I>,
308 var: InferenceVar,
309 outer_binder: DebruijnIndex,
310 ) -> Result<Const<I>, Self::Error> {
311 if self.forbid_inference_vars() {
312 panic!("unexpected inference const `{:?}`", var)
313 } else {
314 Ok(var.to_const(
315 self.interner(),
316 ty.try_fold_with(self.as_dyn(), outer_binder)?,
317 ))
318 }
319 }
320
321 /// Gets the interner that is being folded from.
322 fn interner(&self) -> I;
323}
324
325/// A "folder" is a transformer that can be used to make a copy of
326/// some term -- that is, some bit of IR, such as a `Goal` -- with
327/// certain changes applied. The idea is that it contains methods that
328/// let you swap types/lifetimes for new types/lifetimes; meanwhile,
329/// each bit of IR implements the `TypeFoldable` trait which, given a
330/// `TypeFolder`, will reconstruct itself, invoking the folder's methods
331/// to transform each of the types/lifetimes embedded within.
332///
333/// Folds performed by `TypeFolder` cannot fail. If folds might fail,
334/// consider implementing `FallibleTypeFolder` instead (which is a
335/// fallible, but otherwise equivalent, trait).
336///
337/// # Usage patterns
338///
339/// ## Substituting for free variables
340///
341/// Most of the time, though, we are not interested in adjust
342/// arbitrary types/lifetimes, but rather just free variables (even
343/// more often, just free existential variables) that appear within
344/// the term.
345///
346/// For this reason, the `TypeFolder` trait extends two other traits that
347/// contain methods that are invoked when just those particular
348///
349/// In particular, folders can intercept references to free variables
350/// (either existentially or universally quantified) and replace them
351/// with other types/lifetimes as appropriate.
352///
353/// To create a folder `F`, one never implements `TypeFolder` directly, but instead
354/// implements one of each of these three sub-traits:
355///
356/// - `FreeVarFolder` -- folds `BoundVar` instances that appear free
357/// in the term being folded (use `DefaultFreeVarFolder` to
358/// ignore/forbid these altogether)
359/// - `InferenceFolder` -- folds existential `InferenceVar` instances
360/// that appear in the term being folded (use
361/// `DefaultInferenceFolder` to ignore/forbid these altogether)
362/// - `PlaceholderFolder` -- folds universal `Placeholder` instances
363/// that appear in the term being folded (use
364/// `DefaultPlaceholderFolder` to ignore/forbid these altogether)
365///
366/// To **apply** a folder, use the `TypeFoldable::fold_with` method, like so
367///
368/// ```rust,ignore
369/// let x = x.fold_with(&mut folder, 0);
370/// ```
371pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Infallible> {
372 /// Creates a `dyn` value from this folder. Unfortunately, this
373 /// must be added manually to each impl of TypeFolder; it permits the
374 /// default implements below to create a `&mut dyn TypeFolder` from
375 /// `Self` without knowing what `Self` is (by invoking this
376 /// method). Effectively, this limits impls of `TypeFolder` to types
377 /// for which we are able to create a dyn value (i.e., not `[T]`
378 /// types).
379 fn as_dyn(&mut self) -> &mut dyn TypeFolder<I>;
380
381 /// Top-level callback: invoked for each `Ty<I>` that is
382 /// encountered when folding. By default, invokes
383 /// `super_fold_with`, which will in turn invoke the more
384 /// specialized folding methods below, like `fold_free_var_ty`.
385 fn fold_ty(&mut self, ty: Ty<I>, outer_binder: DebruijnIndex) -> Ty<I> {
386 ty.super_fold_with(TypeFolder::as_dyn(self), outer_binder)
387 }
388
389 /// Top-level callback: invoked for each `Lifetime<I>` that is
390 /// encountered when folding. By default, invokes
391 /// `super_fold_with`, which will in turn invoke the more
392 /// specialized folding methods below, like `fold_free_var_lifetime`.
393 fn fold_lifetime(&mut self, lifetime: Lifetime<I>, outer_binder: DebruijnIndex) -> Lifetime<I> {
394 lifetime.super_fold_with(TypeFolder::as_dyn(self), outer_binder)
395 }
396
397 /// Top-level callback: invoked for each `Const<I>` that is
398 /// encountered when folding. By default, invokes
399 /// `super_fold_with`, which will in turn invoke the more
400 /// specialized folding methods below, like `fold_free_var_const`.
401 fn fold_const(&mut self, constant: Const<I>, outer_binder: DebruijnIndex) -> Const<I> {
402 constant.super_fold_with(TypeFolder::as_dyn(self), outer_binder)
403 }
404
405 /// Invoked for every program clause. By default, recursively folds the goals contents.
406 fn fold_program_clause(
407 &mut self,
408 clause: ProgramClause<I>,
409 outer_binder: DebruijnIndex,
410 ) -> ProgramClause<I> {
411 clause.super_fold_with(TypeFolder::as_dyn(self), outer_binder)
412 }
413
414 /// Invoked for every goal. By default, recursively folds the goals contents.
415 fn fold_goal(&mut self, goal: Goal<I>, outer_binder: DebruijnIndex) -> Goal<I> {
416 goal.super_fold_with(TypeFolder::as_dyn(self), outer_binder)
417 }
418
419 /// If overridden to return true, then folding will panic if a
420 /// free variable is encountered. This should be done if free
421 /// type/lifetime variables are not expected.
422 fn forbid_free_vars(&self) -> bool {
423 false
424 }
425
426 /// Invoked for `TyKind::BoundVar` instances that are not bound
427 /// within the type being folded over:
428 ///
429 /// - `depth` is the depth of the `TyKind::BoundVar`; this has
430 /// been adjusted to account for binders in scope.
431 /// - `binders` is the number of binders in scope.
432 ///
433 /// This should return a type suitable for a context with
434 /// `binders` in scope.
435 fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty<I> {
436 if TypeFolder::forbid_free_vars(self) {
437 panic!(
438 "unexpected free variable with depth `{:?}` with outer binder {:?}",
439 bound_var, outer_binder
440 )
441 } else {
442 let bound_var = bound_var.shifted_in_from(outer_binder);
443 TyKind::<I>::BoundVar(bound_var).intern(TypeFolder::interner(self))
444 }
445 }
446
447 /// As `fold_free_var_ty`, but for lifetimes.
448 fn fold_free_var_lifetime(
449 &mut self,
450 bound_var: BoundVar,
451 outer_binder: DebruijnIndex,
452 ) -> Lifetime<I> {
453 if TypeFolder::forbid_free_vars(self) {
454 panic!(
455 "unexpected free variable with depth `{:?}` with outer binder {:?}",
456 bound_var, outer_binder
457 )
458 } else {
459 let bound_var = bound_var.shifted_in_from(outer_binder);
460 LifetimeData::<I>::BoundVar(bound_var).intern(TypeFolder::interner(self))
461 }
462 }
463
464 /// As `fold_free_var_ty`, but for constants.
465 fn fold_free_var_const(
466 &mut self,
467 ty: Ty<I>,
468 bound_var: BoundVar,
469 outer_binder: DebruijnIndex,
470 ) -> Const<I> {
471 if TypeFolder::forbid_free_vars(self) {
472 panic!(
473 "unexpected free variable with depth `{:?}` with outer binder {:?}",
474 bound_var, outer_binder
475 )
476 } else {
477 let bound_var = bound_var.shifted_in_from(outer_binder);
478 ConstData {
479 ty: ty.fold_with(TypeFolder::as_dyn(self), outer_binder),
480 value: ConstValue::<I>::BoundVar(bound_var),
481 }
482 .intern(TypeFolder::interner(self))
483 }
484 }
485
486 /// If overridden to return true, we will panic when a free
487 /// placeholder type/lifetime/const is encountered.
488 fn forbid_free_placeholders(&self) -> bool {
489 false
490 }
491
492 /// Invoked for each occurrence of a placeholder type; these are
493 /// used when we instantiate binders universally. Returns a type
494 /// to use instead, which should be suitably shifted to account
495 /// for `binders`.
496 ///
497 /// - `universe` is the universe of the `TypeName::ForAll` that was found
498 /// - `binders` is the number of binders in scope
499 #[allow(unused_variables)]
500 fn fold_free_placeholder_ty(
501 &mut self,
502 universe: PlaceholderIndex,
503 outer_binder: DebruijnIndex,
504 ) -> Ty<I> {
505 if TypeFolder::forbid_free_placeholders(self) {
506 panic!("unexpected placeholder type `{:?}`", universe)
507 } else {
508 universe.to_ty::<I>(TypeFolder::interner(self))
509 }
510 }
511
512 /// As with `fold_free_placeholder_ty`, but for lifetimes.
513 #[allow(unused_variables)]
514 fn fold_free_placeholder_lifetime(
515 &mut self,
516 universe: PlaceholderIndex,
517 outer_binder: DebruijnIndex,
518 ) -> Lifetime<I> {
519 if TypeFolder::forbid_free_placeholders(self) {
520 panic!("unexpected placeholder lifetime `{:?}`", universe)
521 } else {
522 universe.to_lifetime(TypeFolder::interner(self))
523 }
524 }
525
526 /// As with `fold_free_placeholder_ty`, but for constants.
527 #[allow(unused_variables)]
528 fn fold_free_placeholder_const(
529 &mut self,
530 ty: Ty<I>,
531 universe: PlaceholderIndex,
532 outer_binder: DebruijnIndex,
533 ) -> Const<I> {
534 if TypeFolder::forbid_free_placeholders(self) {
535 panic!("unexpected placeholder const `{:?}`", universe)
536 } else {
537 universe.to_const(
538 TypeFolder::interner(self),
539 ty.fold_with(TypeFolder::as_dyn(self), outer_binder),
540 )
541 }
542 }
543
544 /// If overridden to return true, inference variables will trigger
545 /// panics when folded. Used when inference variables are
546 /// unexpected.
547 fn forbid_inference_vars(&self) -> bool {
548 false
549 }
550
551 /// Invoked for each occurrence of a inference type; these are
552 /// used when we instantiate binders universally. Returns a type
553 /// to use instead, which should be suitably shifted to account
554 /// for `binders`.
555 ///
556 /// - `universe` is the universe of the `TypeName::ForAll` that was found
557 /// - `binders` is the number of binders in scope
558 #[allow(unused_variables)]
559 fn fold_inference_ty(
560 &mut self,
561 var: InferenceVar,
562 kind: TyVariableKind,
563 outer_binder: DebruijnIndex,
564 ) -> Ty<I> {
565 if TypeFolder::forbid_inference_vars(self) {
566 panic!("unexpected inference type `{:?}`", var)
567 } else {
568 var.to_ty(TypeFolder::interner(self), kind)
569 }
570 }
571
572 /// As with `fold_inference_ty`, but for lifetimes.
573 #[allow(unused_variables)]
574 fn fold_inference_lifetime(
575 &mut self,
576 var: InferenceVar,
577 outer_binder: DebruijnIndex,
578 ) -> Lifetime<I> {
579 if TypeFolder::forbid_inference_vars(self) {
580 panic!("unexpected inference lifetime `'{:?}`", var)
581 } else {
582 var.to_lifetime(TypeFolder::interner(self))
583 }
584 }
585
586 /// As with `fold_inference_ty`, but for constants.
587 #[allow(unused_variables)]
588 fn fold_inference_const(
589 &mut self,
590 ty: Ty<I>,
591 var: InferenceVar,
592 outer_binder: DebruijnIndex,
593 ) -> Const<I> {
594 if TypeFolder::forbid_inference_vars(self) {
595 panic!("unexpected inference const `{:?}`", var)
596 } else {
597 var.to_const(
598 TypeFolder::interner(self),
599 ty.fold_with(TypeFolder::as_dyn(self), outer_binder),
600 )
601 }
602 }
603
604 /// Gets the interner that is being folded from.
605 fn interner(&self) -> I;
606}
607
608/// Applies the given `TypeFolder` to a value, producing a folded result
609/// of type `Self::Result`. The result type is typically the same as
610/// the source type, but in some cases we convert from borrowed
611/// to owned as well (e.g., the folder for `&T` will fold to a fresh
612/// `T`; well, actually `T::Result`).
613pub trait TypeFoldable<I: Interner>: Debug + Sized {
614 /// Apply the given folder `folder` to `self`; `binders` is the
615 /// number of binders that are in scope when beginning the
616 /// folder. Typically `binders` starts as 0, but is adjusted when
617 /// we encounter `Binders<T>` in the IR or other similar
618 /// constructs.
619 fn try_fold_with<E>(
620 self,
621 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
622 outer_binder: DebruijnIndex,
623 ) -> Result<Self, E>;
624
625 /// A convenient alternative to `try_fold_with` for use with infallible
626 /// folders. Do not override this method, to ensure coherence with
627 /// `try_fold_with`.
628 fn fold_with(self, folder: &mut dyn TypeFolder<I>, outer_binder: DebruijnIndex) -> Self {
629 self.try_fold_with(FallibleTypeFolder::as_dyn(folder), outer_binder)
630 .unwrap()
631 }
632}
633
634/// For types where "fold" invokes a callback on the `TypeFolder`, the
635/// `TypeSuperFoldable` trait captures the recursive behavior that folds all
636/// the contents of the type.
637pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
638 /// Recursively folds the value.
639 fn try_super_fold_with<E>(
640 self,
641 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
642 outer_binder: DebruijnIndex,
643 ) -> Result<Self, E>;
644
645 /// A convenient alternative to `try_super_fold_with` for use with
646 /// infallible folders. Do not override this method, to ensure coherence
647 /// with `try_super_fold_with`.
648 fn super_fold_with(self, folder: &mut dyn TypeFolder<I>, outer_binder: DebruijnIndex) -> Self {
649 self.try_super_fold_with(FallibleTypeFolder::as_dyn(folder), outer_binder)
650 .unwrap()
651 }
652}
653
654/// "Folding" a type invokes the `try_fold_ty` method on the folder; this
655/// usually (in turn) invokes `try_super_fold_ty` to fold the individual
656/// parts.
657impl<I: Interner> TypeFoldable<I> for Ty<I> {
658 fn try_fold_with<E>(
659 self,
660 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
661 outer_binder: DebruijnIndex,
662 ) -> Result<Self, E> {
663 folder.try_fold_ty(self, outer_binder)
664 }
665}
666
667/// "Super fold" for a type invokes te more detailed callbacks on the type
668impl<I> TypeSuperFoldable<I> for Ty<I>
669where
670 I: Interner,
671{
672 fn try_super_fold_with<E>(
673 self,
674 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
675 outer_binder: DebruijnIndex,
676 ) -> Result<Ty<I>, E> {
677 let interner = folder.interner();
678 Ok(match self.kind(interner) {
679 TyKind::BoundVar(bound_var) => {
680 if let Some(bound_var1) = bound_var.shifted_out_to(outer_binder) {
681 // This variable was bound outside of the binders
682 // that we have traversed during folding;
683 // therefore, it is free. Let the folder have a
684 // crack at it.
685 folder.try_fold_free_var_ty(bound_var1, outer_binder)?
686 } else {
687 // This variable was bound within the binders that
688 // we folded over, so just return a bound
689 // variable.
690 self
691 }
692 }
693 TyKind::Dyn(clauses) => {
694 TyKind::Dyn(clauses.clone().try_fold_with(folder, outer_binder)?)
695 .intern(folder.interner())
696 }
697 TyKind::InferenceVar(var, kind) => {
698 folder.try_fold_inference_ty(*var, *kind, outer_binder)?
699 }
700 TyKind::Placeholder(ui) => folder.try_fold_free_placeholder_ty(*ui, outer_binder)?,
701 TyKind::Alias(proj) => TyKind::Alias(proj.clone().try_fold_with(folder, outer_binder)?)
702 .intern(folder.interner()),
703 TyKind::Function(fun) => {
704 TyKind::Function(fun.clone().try_fold_with(folder, outer_binder)?)
705 .intern(folder.interner())
706 }
707 TyKind::Adt(id, substitution) => TyKind::Adt(
708 id.try_fold_with(folder, outer_binder)?,
709 substitution.clone().try_fold_with(folder, outer_binder)?,
710 )
711 .intern(folder.interner()),
712 TyKind::AssociatedType(assoc_ty, substitution) => TyKind::AssociatedType(
713 assoc_ty.try_fold_with(folder, outer_binder)?,
714 substitution.clone().try_fold_with(folder, outer_binder)?,
715 )
716 .intern(folder.interner()),
717 TyKind::Scalar(scalar) => TyKind::Scalar(scalar.try_fold_with(folder, outer_binder)?)
718 .intern(folder.interner()),
719 TyKind::Str => TyKind::Str.intern(folder.interner()),
720 TyKind::Tuple(arity, substitution) => TyKind::Tuple(
721 *arity,
722 substitution.clone().try_fold_with(folder, outer_binder)?,
723 )
724 .intern(folder.interner()),
725 TyKind::OpaqueType(opaque_ty, substitution) => TyKind::OpaqueType(
726 opaque_ty.try_fold_with(folder, outer_binder)?,
727 substitution.clone().try_fold_with(folder, outer_binder)?,
728 )
729 .intern(folder.interner()),
730 TyKind::Slice(substitution) => {
731 TyKind::Slice(substitution.clone().try_fold_with(folder, outer_binder)?)
732 .intern(folder.interner())
733 }
734 TyKind::FnDef(fn_def, substitution) => TyKind::FnDef(
735 fn_def.try_fold_with(folder, outer_binder)?,
736 substitution.clone().try_fold_with(folder, outer_binder)?,
737 )
738 .intern(folder.interner()),
739 TyKind::Ref(mutability, lifetime, ty) => TyKind::Ref(
740 mutability.try_fold_with(folder, outer_binder)?,
741 lifetime.clone().try_fold_with(folder, outer_binder)?,
742 ty.clone().try_fold_with(folder, outer_binder)?,
743 )
744 .intern(folder.interner()),
745 TyKind::Raw(mutability, ty) => TyKind::Raw(
746 mutability.try_fold_with(folder, outer_binder)?,
747 ty.clone().try_fold_with(folder, outer_binder)?,
748 )
749 .intern(folder.interner()),
750 TyKind::Never => TyKind::Never.intern(folder.interner()),
751 TyKind::Array(ty, const_) => TyKind::Array(
752 ty.clone().try_fold_with(folder, outer_binder)?,
753 const_.clone().try_fold_with(folder, outer_binder)?,
754 )
755 .intern(folder.interner()),
756 TyKind::Closure(id, substitution) => TyKind::Closure(
757 id.try_fold_with(folder, outer_binder)?,
758 substitution.clone().try_fold_with(folder, outer_binder)?,
759 )
760 .intern(folder.interner()),
761 TyKind::Coroutine(id, substitution) => TyKind::Coroutine(
762 id.try_fold_with(folder, outer_binder)?,
763 substitution.clone().try_fold_with(folder, outer_binder)?,
764 )
765 .intern(folder.interner()),
766 TyKind::CoroutineWitness(id, substitution) => TyKind::CoroutineWitness(
767 id.try_fold_with(folder, outer_binder)?,
768 substitution.clone().try_fold_with(folder, outer_binder)?,
769 )
770 .intern(folder.interner()),
771 TyKind::Foreign(id) => {
772 TyKind::Foreign(id.try_fold_with(folder, outer_binder)?).intern(folder.interner())
773 }
774 TyKind::Error => TyKind::Error.intern(folder.interner()),
775 })
776 }
777}
778
779/// "Folding" a lifetime invokes the `fold_lifetime` method on the folder; this
780/// usually (in turn) invokes `super_fold_lifetime` to fold the individual
781/// parts.
782impl<I: Interner> TypeFoldable<I> for Lifetime<I> {
783 fn try_fold_with<E>(
784 self,
785 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
786 outer_binder: DebruijnIndex,
787 ) -> Result<Self, E> {
788 folder.try_fold_lifetime(self, outer_binder)
789 }
790}
791
792impl<I> TypeSuperFoldable<I> for Lifetime<I>
793where
794 I: Interner,
795{
796 fn try_super_fold_with<E>(
797 self,
798 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
799 outer_binder: DebruijnIndex,
800 ) -> Result<Lifetime<I>, E> {
801 let interner = folder.interner();
802 match self.data(interner) {
803 LifetimeData::BoundVar(bound_var) => {
804 if let Some(bound_var1) = bound_var.shifted_out_to(outer_binder) {
805 // This variable was bound outside of the binders
806 // that we have traversed during folding;
807 // therefore, it is free. Let the folder have a
808 // crack at it.
809 folder.try_fold_free_var_lifetime(bound_var1, outer_binder)
810 } else {
811 // This variable was bound within the binders that
812 // we folded over, so just return a bound
813 // variable.
814 Ok(self)
815 }
816 }
817 LifetimeData::InferenceVar(var) => {
818 folder.try_fold_inference_lifetime(*var, outer_binder)
819 }
820 LifetimeData::Placeholder(universe) => {
821 folder.try_fold_free_placeholder_lifetime(*universe, outer_binder)
822 }
823 LifetimeData::Static => Ok(LifetimeData::<I>::Static.intern(folder.interner())),
824 LifetimeData::Erased => Ok(LifetimeData::<I>::Erased.intern(folder.interner())),
825 LifetimeData::Error => Ok(LifetimeData::<I>::Error.intern(folder.interner())),
826 LifetimeData::Phantom(void, ..) => match *void {},
827 }
828 }
829}
830
831/// "Folding" a const invokes the `fold_const` method on the folder; this
832/// usually (in turn) invokes `super_fold_const` to fold the individual
833/// parts.
834impl<I: Interner> TypeFoldable<I> for Const<I> {
835 fn try_fold_with<E>(
836 self,
837 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
838 outer_binder: DebruijnIndex,
839 ) -> Result<Self, E> {
840 folder.try_fold_const(self, outer_binder)
841 }
842}
843
844impl<I> TypeSuperFoldable<I> for Const<I>
845where
846 I: Interner,
847{
848 fn try_super_fold_with<E>(
849 self,
850 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
851 outer_binder: DebruijnIndex,
852 ) -> Result<Const<I>, E> {
853 let interner = folder.interner();
854 let ConstData { ref ty, ref value } = self.data(interner);
855 let mut fold_ty = || ty.clone().try_fold_with(folder, outer_binder);
856 match value {
857 ConstValue::BoundVar(bound_var) => {
858 if let Some(bound_var1) = bound_var.shifted_out_to(outer_binder) {
859 folder.try_fold_free_var_const(ty.clone(), bound_var1, outer_binder)
860 } else {
861 Ok(self)
862 }
863 }
864 ConstValue::InferenceVar(var) => {
865 folder.try_fold_inference_const(ty.clone(), *var, outer_binder)
866 }
867 ConstValue::Placeholder(universe) => {
868 folder.try_fold_free_placeholder_const(ty.clone(), *universe, outer_binder)
869 }
870 ConstValue::Concrete(ev) => Ok(ConstData {
871 ty: fold_ty()?,
872 value: ConstValue::Concrete(ConcreteConst {
873 interned: ev.interned.clone(),
874 }),
875 }
876 .intern(folder.interner())),
877 }
878 }
879}
880
881/// Folding a goal invokes the `fold_goal` callback (which will, by
882/// default, invoke super-fold).
883impl<I: Interner> TypeFoldable<I> for Goal<I> {
884 fn try_fold_with<E>(
885 self,
886 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
887 outer_binder: DebruijnIndex,
888 ) -> Result<Self, E> {
889 folder.try_fold_goal(self, outer_binder)
890 }
891}
892
893/// Superfold folds recursively.
894impl<I: Interner> TypeSuperFoldable<I> for Goal<I> {
895 fn try_super_fold_with<E>(
896 self,
897 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
898 outer_binder: DebruijnIndex,
899 ) -> Result<Self, E> {
900 let interner = folder.interner();
901 Ok(Goal::new(
902 interner,
903 self.data(interner)
904 .clone()
905 .try_fold_with(folder, outer_binder)?,
906 ))
907 }
908}
909
910/// Folding a program clause invokes the `fold_program_clause`
911/// callback on the folder (which will, by default, invoke the
912/// `super_fold_with` method on the program clause).
913impl<I: Interner> TypeFoldable<I> for ProgramClause<I> {
914 fn try_fold_with<E>(
915 self,
916 folder: &mut dyn FallibleTypeFolder<I, Error = E>,
917 outer_binder: DebruijnIndex,
918 ) -> Result<Self, E> {
919 folder.try_fold_program_clause(self, outer_binder)
920 }
921}