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}