Skip to main content

rustc_type_ir/
fold.rs

1//! A folding traversal mechanism for complex data structures that contain type
2//! information.
3//!
4//! This is a modifying traversal. It consumes the data structure, producing a
5//! (possibly) modified version of it. Both fallible and infallible versions are
6//! available. The name is potentially confusing, because this traversal is more
7//! like `Iterator::map` than `Iterator::fold`.
8//!
9//! This traversal has limited flexibility. Only a small number of "types of
10//! interest" within the complex data structures can receive custom
11//! modification. These are the ones containing the most important type-related
12//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
13//!
14//! There are three traits involved in each traversal.
15//! - `TypeFoldable`. This is implemented once for many types, including:
16//!   - Types of interest, for which the methods delegate to the folder.
17//!   - All other types, including generic containers like `Vec` and `Option`.
18//!     It defines a "skeleton" of how they should be folded.
19//! - `TypeSuperFoldable`. This is implemented only for recursive types of
20//!   interest, and defines the folding "skeleton" for these types. (This
21//!   excludes `Region` because it is non-recursive, i.e. it never contains
22//!   other types of interest.)
23//! - `TypeFolder`/`FallibleTypeFolder`. One of these is implemented for each
24//!   folder. This defines how types of interest are folded.
25//!
26//! This means each fold is a mixture of (a) generic folding operations, and (b)
27//! custom fold operations that are specific to the folder.
28//! - The `TypeFoldable` impls handle most of the traversal, and call into
29//!   `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest.
30//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable`
31//!   impl, because some of the types of interest are recursive and can contain
32//!   other types of interest.
33//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable`
34//!   impl, because each folder might provide custom handling only for some types
35//!   of interest, or only for some variants of each type of interest, and then
36//!   use default traversal for the remaining cases.
37//!
38//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
39//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so:
40//! ```text
41//! s.fold_with(folder) calls
42//! - ty.fold_with(folder) calls
43//!   - folder.fold_ty(ty) may call
44//!     - ty.super_fold_with(folder)
45//! - u.fold_with(folder)
46//! ```
47
48use std::convert::Infallible;
49use std::mem;
50use std::sync::Arc;
51
52use rustc_index::{Idx, IndexVec};
53use smallvec::SmallVec;
54use thin_vec::ThinVec;
55use tracing::{debug, instrument};
56
57use crate::data_structures::DelayedMap;
58use crate::inherent::*;
59use crate::visit::{TypeVisitable, TypeVisitableExt as _};
60use crate::{
61    self as ty, Binder, BoundVarIndexKind, ClauseKind, Const, Flags, Interner, ProjectionClause,
62    Region, TypeSuperVisitable,
63};
64
65/// This trait is implemented for every type that can be folded,
66/// providing the skeleton of the traversal.
67///
68/// To implement this conveniently, use the derive macro located in
69/// `rustc_macros`.
70///
71/// This trait is a sub-trait of `TypeVisitable`. This is because many
72/// `TypeFolder` instances use the methods in `TypeVisitableExt` while folding,
73/// which means in practice almost every foldable type needs to also be
74/// visitable. (However, there are some types that are visitable without being
75/// foldable.)
76pub trait TypeFoldable<I: Interner>: TypeVisitable<I> + Clone {
77    /// The entry point for folding. To fold a value `t` with a folder `f`
78    /// call: `t.try_fold_with(f)`.
79    ///
80    /// For most types, this just traverses the value, calling `try_fold_with`
81    /// on each field/element.
82    ///
83    /// For types of interest (such as `Ty`), the implementation of this method
84    /// calls a folder method specifically for that type (such as
85    /// `F::try_fold_ty`). This is where control transfers from [`TypeFoldable`]
86    /// to [`FallibleTypeFolder`].
87    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error>;
88
89    /// The entry point for folding. To fold a value `t` with a folder `f`
90    /// call: `t.fold_with(f)`.
91    ///
92    /// For most types, this just traverses the value, calling `fold_with`
93    /// on each field/element.
94    ///
95    /// For types of interest (such as `Ty`), the implementation of this method
96    /// calls a folder method specifically for that type (such as
97    /// `F::fold_ty`). This is where control transfers from `TypeFoldable`
98    /// to `TypeFolder`.
99    ///
100    /// Same as [`TypeFoldable::try_fold_with`], but not fallible. Make sure to keep
101    /// the behavior in sync across functions.
102    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self;
103}
104
105// This trait is implemented for types of interest.
106pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
107    /// Provides a default fold for a recursive type of interest. This should
108    /// only be called within `TypeFolder` methods, when a non-custom traversal
109    /// is desired for the value of the type of interest passed to that method.
110    /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
111    /// `ty.try_super_fold_with(self)`, but any other folding should be done
112    /// with `xyz.try_fold_with(self)`.
113    fn try_super_fold_with<F: FallibleTypeFolder<I>>(
114        self,
115        folder: &mut F,
116    ) -> Result<Self, F::Error>;
117
118    /// A convenient alternative to `try_super_fold_with` for use with
119    /// infallible folders. Do not override this method, to ensure coherence
120    /// with `try_super_fold_with`.
121    fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self;
122}
123
124/// This trait is implemented for every infallible folding traversal. There is
125/// a fold method defined for every type of interest. Each such method has a
126/// default that does an "identity" fold. Implementations of these methods
127/// often fall back to a `super_fold_with` method if the primary argument
128/// doesn't satisfy a particular condition.
129pub trait TypeFolder<I: Interner>: Sized {
130    fn cx(&self) -> I;
131
132    fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
133    where
134        T: TypeFoldable<I>,
135    {
136        t.super_fold_with(self)
137    }
138
139    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
140        t.super_fold_with(self)
141    }
142
143    // The default region folder is a no-op because `Region` is non-recursive
144    // and has no `super_fold_with` method to call.
145    fn fold_region(&mut self, r: Region<I>) -> Region<I> {
146        r
147    }
148
149    fn fold_const(&mut self, c: Const<I>) -> Const<I> {
150        c.super_fold_with(self)
151    }
152
153    fn fold_predicate<P: PredicateProxy<I>>(&mut self, p: P) -> P {
154        p.super_fold_with(self)
155    }
156
157    fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
158        c.super_fold_with(self)
159    }
160}
161
162/// [Fold predicate](TypeFolder::fold_predicate) deliberately doesn't get access
163/// to an actual predicate. This way, we can compress lists of predicates, and hide
164/// this detail to folders. Instead, some type implementing this trait, [`PredicateProxy`]
165/// is passed, with its limited API.
166///
167/// Most [`TypeFolder`]s only use `fold_predicate` to inspect type flags.
168pub trait PredicateProxy<I: Interner>:
169    TypeSuperFoldable<I> + TypeSuperVisitable<I> + Flags + Copy
170{
171    fn allow_normalization(&self) -> bool;
172
173    /// Gets the underlying clause kind (if this predicate is a clause, otherwise `None`).
174    /// The fact that it's `unchecked`, is because no attempt is made to hide implementation
175    /// details. For example, in the future we may compress clauses together. Code calling
176    /// `clause_kind_unchecked` will have to correctly deal with these implementation details,
177    /// and have code handling any edgecase arising as a result.
178    fn clause_kind_unchecked(&self) -> Option<Binder<I, ClauseKind<I>>>;
179
180    /// If self is a projection clause, call `f` with it. The result will be rebound and returned as `Some`.
181    /// Otherwise, when self is not a projection clause, `None` is returned.
182    fn map_projection(
183        self,
184        cx: I,
185        f: impl FnOnce(Binder<I, ProjectionClause<I>>) -> Binder<I, ProjectionClause<I>>,
186    ) -> Option<Self>;
187}
188
189/// This trait is implemented for every folding traversal. There is a fold
190/// method defined for every type of interest. Each such method has a default
191/// that does an "identity" fold.
192///
193/// A blanket implementation of this trait (that defers to the relevant
194/// method of [`TypeFolder`]) is provided for all infallible folders in
195/// order to ensure the two APIs are coherent.
196pub trait FallibleTypeFolder<I: Interner>: Sized {
197    type Error;
198
199    fn cx(&self) -> I;
200
201    fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Self::Error>
202    where
203        T: TypeFoldable<I>,
204    {
205        t.try_super_fold_with(self)
206    }
207
208    fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error> {
209        t.try_super_fold_with(self)
210    }
211
212    // The default region folder is a no-op because `Region` is non-recursive
213    // and has no `super_fold_with` method to call.
214    fn try_fold_region(&mut self, r: Region<I>) -> Result<Region<I>, Self::Error> {
215        Ok(r)
216    }
217
218    fn try_fold_const(&mut self, c: Const<I>) -> Result<Const<I>, Self::Error> {
219        c.try_super_fold_with(self)
220    }
221
222    fn try_fold_predicate<P: PredicateProxy<I>>(&mut self, p: P) -> Result<P, Self::Error> {
223        p.try_super_fold_with(self)
224    }
225
226    fn try_fold_clauses(&mut self, c: I::Clauses) -> Result<I::Clauses, Self::Error> {
227        c.try_super_fold_with(self)
228    }
229}
230
231///////////////////////////////////////////////////////////////////////////
232// Traversal implementations.
233
234impl<I: Interner, T: TypeFoldable<I>, U: TypeFoldable<I>> TypeFoldable<I> for (T, U) {
235    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
236        Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
237    }
238
239    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
240        (self.0.fold_with(folder), self.1.fold_with(folder))
241    }
242}
243
244impl<I: Interner, A: TypeFoldable<I>, B: TypeFoldable<I>, C: TypeFoldable<I>> TypeFoldable<I>
245    for (A, B, C)
246{
247    fn try_fold_with<F: FallibleTypeFolder<I>>(
248        self,
249        folder: &mut F,
250    ) -> Result<(A, B, C), F::Error> {
251        Ok((
252            self.0.try_fold_with(folder)?,
253            self.1.try_fold_with(folder)?,
254            self.2.try_fold_with(folder)?,
255        ))
256    }
257
258    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
259        (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
260    }
261}
262
263impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Option<T> {
264    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
265        Ok(match self {
266            Some(v) => Some(v.try_fold_with(folder)?),
267            None => None,
268        })
269    }
270
271    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
272        Some(self?.fold_with(folder))
273    }
274}
275
276impl<I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>> TypeFoldable<I> for Result<T, E> {
277    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
278        Ok(match self {
279            Ok(v) => Ok(v.try_fold_with(folder)?),
280            Err(e) => Err(e.try_fold_with(folder)?),
281        })
282    }
283
284    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
285        match self {
286            Ok(v) => Ok(v.fold_with(folder)),
287            Err(e) => Err(e.fold_with(folder)),
288        }
289    }
290}
291
292fn fold_arc<T: Clone, E>(
293    mut arc: Arc<T>,
294    fold: impl FnOnce(T) -> Result<T, E>,
295) -> Result<Arc<T>, E> {
296    // We merely want to replace the contained `T`, if at all possible,
297    // so that we don't needlessly allocate a new `Arc` or indeed clone
298    // the contained type.
299    unsafe {
300        // First step is to ensure that we have a unique reference to
301        // the contained type, which `Arc::make_mut` will accomplish (by
302        // allocating a new `Arc` and cloning the `T` only if required).
303        // This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
304        // panicking during `make_mut` does not leak the `T`.
305        Arc::make_mut(&mut arc);
306
307        // Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
308        // is `repr(transparent)`.
309        let ptr = Arc::into_raw(arc).cast::<mem::ManuallyDrop<T>>();
310        let mut unique = Arc::from_raw(ptr);
311
312        // Call to `Arc::make_mut` above guarantees that `unique` is the
313        // sole reference to the contained value, so we can avoid doing
314        // a checked `get_mut` here.
315        let slot = Arc::get_mut(&mut unique).unwrap_unchecked();
316
317        // Semantically move the contained type out from `unique`, fold
318        // it, then move the folded value back into `unique`. Should
319        // folding fail, `ManuallyDrop` ensures that the "moved-out"
320        // value is not re-dropped.
321        let owned = mem::ManuallyDrop::take(slot);
322        let folded = fold(owned)?;
323        *slot = mem::ManuallyDrop::new(folded);
324
325        // Cast back to `Arc<T>`.
326        Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
327    }
328}
329
330impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Arc<T> {
331    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
332        fold_arc(self, |t| t.try_fold_with(folder))
333    }
334
335    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
336        match fold_arc::<T, Infallible>(self, |t| Ok(t.fold_with(folder))) {
337            Ok(t) => t,
338        }
339    }
340}
341
342impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<T> {
343    fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
344        *self = (*self).try_fold_with(folder)?;
345        Ok(self)
346    }
347
348    fn fold_with<F: TypeFolder<I>>(mut self, folder: &mut F) -> Self {
349        *self = (*self).fold_with(folder);
350        self
351    }
352}
353
354impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
355    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
356        self.into_iter().map(|t| t.try_fold_with(folder)).collect()
357    }
358
359    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
360        self.into_iter().map(|t| t.fold_with(folder)).collect()
361    }
362}
363
364impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for ThinVec<T> {
365    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
366        self.into_iter().map(|t| t.try_fold_with(folder)).collect()
367    }
368
369    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
370        self.into_iter().map(|t| t.fold_with(folder)).collect()
371    }
372}
373
374impl<I: Interner, T: TypeFoldable<I>, const N: usize> TypeFoldable<I> for SmallVec<[T; N]> {
375    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
376        self.into_iter().map(|t| t.try_fold_with(folder)).collect()
377    }
378
379    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
380        self.into_iter().map(|t| t.fold_with(folder)).collect()
381    }
382}
383
384impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> {
385    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
386        Vec::from(self).try_fold_with(folder).map(Vec::into_boxed_slice)
387    }
388
389    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
390        Vec::into_boxed_slice(Vec::from(self).fold_with(folder))
391    }
392}
393
394impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> {
395    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
396        self.raw.try_fold_with(folder).map(IndexVec::from_raw)
397    }
398
399    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
400        IndexVec::from_raw(self.raw.fold_with(folder))
401    }
402}
403
404///////////////////////////////////////////////////////////////////////////
405// Shifter
406//
407// Shifts the De Bruijn indices on all escaping bound vars by a
408// fixed amount. Useful in instantiation or when otherwise introducing
409// a binding level that is not intended to capture the existing bound
410// vars. See comment on `shift_vars_through_binders` method in
411// `rustc_middle/src/ty/generic_args.rs` for more details.
412
413struct Shifter<I: Interner> {
414    cx: I,
415    current_index: ty::DebruijnIndex,
416    amount: u32,
417}
418
419impl<I: Interner> Shifter<I> {
420    fn new(cx: I, amount: u32) -> Self {
421        Shifter { cx, current_index: ty::INNERMOST, amount }
422    }
423}
424
425impl<I: Interner> TypeFolder<I> for Shifter<I> {
426    fn cx(&self) -> I {
427        self.cx
428    }
429
430    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
431        self.current_index.shift_in(1);
432        let t = t.super_fold_with(self);
433        self.current_index.shift_out(1);
434        t
435    }
436
437    fn fold_region(&mut self, r: Region<I>) -> Region<I> {
438        match r.kind() {
439            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
440                if debruijn >= self.current_index =>
441            {
442                let debruijn = debruijn.shifted_in(self.amount);
443                Region::new_bound(self.cx, debruijn, br)
444            }
445            _ => r,
446        }
447    }
448
449    fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
450        match ty.kind() {
451            ty::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty)
452                if debruijn >= self.current_index =>
453            {
454                let debruijn = debruijn.shifted_in(self.amount);
455                Ty::new_bound(self.cx, debruijn, bound_ty)
456            }
457
458            _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self),
459            _ => ty,
460        }
461    }
462
463    fn fold_const(&mut self, ct: Const<I>) -> Const<I> {
464        match ct.kind() {
465            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ct)
466                if debruijn >= self.current_index =>
467            {
468                let debruijn = debruijn.shifted_in(self.amount);
469                Const::new_bound(self.cx, debruijn, bound_ct)
470            }
471            _ => ct.super_fold_with(self),
472        }
473    }
474
475    fn fold_predicate<P: PredicateProxy<I>>(&mut self, p: P) -> P {
476        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
477    }
478
479    fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
480        if c.has_vars_bound_at_or_above(self.current_index) { c.super_fold_with(self) } else { c }
481    }
482}
483
484pub fn shift_region<I: Interner>(cx: I, region: Region<I>, amount: u32) -> Region<I> {
485    match region.kind() {
486        ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) if amount > 0 => {
487            Region::new_bound(cx, debruijn.shifted_in(amount), br)
488        }
489        _ => region,
490    }
491}
492
493{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::TRACE <=
                ::tracing::level_filters::LevelFilter::current() || { false }
    {
    __tracing_attr_span =
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("shift_vars",
                                "rustc_type_ir::fold", ::tracing::Level::TRACE,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs"),
                                ::tracing_core::__macro_support::Option::Some(493u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_type_ir::fold"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("value")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("value");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("amount")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("amount");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        { interest = __CALLSITE.interest(); !interest.is_never() }
                    &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest) {
                let meta = __CALLSITE.metadata();
                ::tracing::Span::new(meta,
                    &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&value)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&amount as
                                                        &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return: T = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        if amount == 0 || !value.has_escaping_bound_vars() {
                            value
                        } else { value.fold_with(&mut Shifter::new(cx, amount)) }
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs:493",
                        "rustc_type_ir::fold", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs"),
                        ::tracing_core::__macro_support::Option::Some(493u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::fold"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "trace", skip(cx), ret)]
494pub fn shift_vars<I: Interner, T>(cx: I, value: T, amount: u32) -> T
495where
496    T: TypeFoldable<I>,
497{
498    if amount == 0 || !value.has_escaping_bound_vars() {
499        value
500    } else {
501        value.fold_with(&mut Shifter::new(cx, amount))
502    }
503}
504
505///////////////////////////////////////////////////////////////////////////
506// Bound variable replacer
507
508/// A delegate used when instantiating bound vars.
509///
510/// Each bound variable must always map to the same result. `BoundVarReplacer`
511/// caches folded types and may not call the delegate on every visit.
512pub trait BoundVarReplacerDelegate<I: Interner> {
513    fn replace_region(&mut self, br: ty::BoundRegion<I>) -> Region<I>;
514    fn replace_ty(&mut self, bt: ty::BoundTy<I>) -> I::Ty;
515    fn replace_const(&mut self, bc: ty::BoundConst<I>) -> Const<I>;
516}
517
518/// A simple delegate taking three mutable functions.
519pub struct FnMutDelegate<'a, I: Interner> {
520    pub regions: &'a mut (dyn FnMut(ty::BoundRegion<I>) -> Region<I> + 'a),
521    pub types: &'a mut (dyn FnMut(ty::BoundTy<I>) -> I::Ty + 'a),
522    pub consts: &'a mut (dyn FnMut(ty::BoundConst<I>) -> Const<I> + 'a),
523}
524
525impl<I: Interner> BoundVarReplacerDelegate<I> for FnMutDelegate<'_, I> {
526    fn replace_region(&mut self, br: ty::BoundRegion<I>) -> Region<I> {
527        (self.regions)(br)
528    }
529
530    fn replace_ty(&mut self, bt: ty::BoundTy<I>) -> I::Ty {
531        (self.types)(bt)
532    }
533
534    fn replace_const(&mut self, bc: ty::BoundConst<I>) -> Const<I> {
535        (self.consts)(bc)
536    }
537}
538
539/// Replaces escaping bound vars in a value.
540pub struct BoundVarReplacer<I: Interner, D> {
541    cx: I,
542    /// As with `RegionFolder`, represents the index of a binder *just outside*
543    /// the ones we have visited.
544    current_index: ty::DebruijnIndex,
545    delegate: D,
546    // Types can appear at different binder depths, so include the depth
547    // in the cache key.
548    cache: DelayedMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
549}
550
551impl<I: Interner, D: BoundVarReplacerDelegate<I>> BoundVarReplacer<I, D> {
552    pub fn new(cx: I, delegate: D) -> Self {
553        Self { cx, current_index: ty::INNERMOST, delegate, cache: Default::default() }
554    }
555}
556
557impl<I: Interner, D: BoundVarReplacerDelegate<I>> TypeFolder<I> for BoundVarReplacer<I, D> {
558    fn cx(&self) -> I {
559        self.cx
560    }
561
562    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
563        self.current_index.shift_in(1);
564        let t = t.super_fold_with(self);
565        self.current_index.shift_out(1);
566        t
567    }
568
569    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
570        match t.kind() {
571            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
572                if debruijn == self.current_index =>
573            {
574                let ty = self.delegate.replace_ty(bound_ty);
575                if true {
    if !!ty.has_vars_bound_above(ty::INNERMOST) {
        ::core::panicking::panic("assertion failed: !ty.has_vars_bound_above(ty::INNERMOST)")
    };
};debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST));
576                shift_vars(self.cx, ty, self.current_index.as_u32())
577            }
578            _ => {
579                if !t.has_vars_bound_at_or_above(self.current_index) {
580                    t
581                } else if let Some(&t) = self.cache.get(&(self.current_index, t)) {
582                    t
583                } else {
584                    let res = t.super_fold_with(self);
585                    if !self.cache.insert((self.current_index, t), res) {
    ::core::panicking::panic("assertion failed: self.cache.insert((self.current_index, t), res)")
};assert!(self.cache.insert((self.current_index, t), res));
586                    res
587                }
588            }
589        }
590    }
591
592    fn fold_region(&mut self, r: Region<I>) -> Region<I> {
593        match r.kind() {
594            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
595                if debruijn == self.current_index =>
596            {
597                let region = self.delegate.replace_region(br);
598                if let ty::ReBound(ty::BoundVarIndexKind::Bound(inner), br) = region.kind() {
599                    // Bound regions returned by the delegate use INNERMOST.
600                    // Adjust them to the current binder depth.
601                    {
    match (&inner, &ty::INNERMOST) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(inner, ty::INNERMOST);
602                    Region::new_bound(self.cx, debruijn, br)
603                } else {
604                    region
605                }
606            }
607            _ => r,
608        }
609    }
610
611    fn fold_const(&mut self, ct: Const<I>) -> Const<I> {
612        match ct.kind() {
613            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
614                if debruijn == self.current_index =>
615            {
616                let ct = self.delegate.replace_const(bound_const);
617                if true {
    if !!ct.has_vars_bound_above(ty::INNERMOST) {
        ::core::panicking::panic("assertion failed: !ct.has_vars_bound_above(ty::INNERMOST)")
    };
};debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST));
618                shift_vars(self.cx, ct, self.current_index.as_u32())
619            }
620            _ => ct.super_fold_with(self),
621        }
622    }
623
624    fn fold_predicate<P: PredicateProxy<I>>(&mut self, p: P) -> P {
625        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
626    }
627
628    fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
629        if c.has_vars_bound_at_or_above(self.current_index) { c.super_fold_with(self) } else { c }
630    }
631}
632
633/// Replaces escaping bound vars using `delegate`.
634pub fn replace_escaping_bound_vars_uncached<I: Interner, T: TypeFoldable<I>>(
635    cx: I,
636    value: T,
637    delegate: impl BoundVarReplacerDelegate<I>,
638) -> T {
639    if !value.has_escaping_bound_vars() {
640        value
641    } else {
642        value.fold_with(&mut BoundVarReplacer::new(cx, delegate))
643    }
644}
645
646/// Shifts escaping bound-variable indices by `bound_vars` without changing
647/// their De Bruijn depth.
648pub fn shift_bound_var_indices<I: Interner, T: TypeFoldable<I>>(
649    cx: I,
650    bound_vars: usize,
651    value: T,
652) -> T {
653    if bound_vars == 0 || !value.has_escaping_bound_vars() {
654        return value;
655    }
656
657    let shift_bv = |bv: ty::BoundVar| bv + bound_vars;
658    replace_escaping_bound_vars_uncached(
659        cx,
660        value,
661        FnMutDelegate {
662            regions: &mut |r: ty::BoundRegion<I>| {
663                Region::new_bound(
664                    cx,
665                    ty::INNERMOST,
666                    ty::BoundRegion { var: shift_bv(r.var), kind: r.kind },
667                )
668            },
669            types: &mut |t: ty::BoundTy<I>| {
670                Ty::new_bound(cx, ty::INNERMOST, ty::BoundTy { var: shift_bv(t.var), kind: t.kind })
671            },
672            consts: &mut |c: ty::BoundConst<I>| {
673                Const::new_bound(cx, ty::INNERMOST, ty::BoundConst::new(shift_bv(c.var)))
674            },
675        },
676    )
677}
678
679///////////////////////////////////////////////////////////////////////////
680// Region folder
681
682pub fn fold_regions<I: Interner, T>(
683    cx: I,
684    value: T,
685    f: impl FnMut(Region<I>, ty::DebruijnIndex) -> Region<I>,
686) -> T
687where
688    T: TypeFoldable<I>,
689{
690    value.fold_with(&mut RegionFolder::new(cx, f))
691}
692
693/// Folds over the substructure of a type, visiting its component
694/// types and all regions that occur *free* within it.
695///
696/// That is, function pointer types and trait objects can introduce
697/// new bound regions which are not visited by this visitor as
698/// they are not free; only regions that occur free will be
699/// visited by `fold_region_fn`.
700pub struct RegionFolder<I, F> {
701    cx: I,
702
703    /// Stores the index of a binder *just outside* the stuff we have
704    /// visited. So this begins as INNERMOST; when we pass through a
705    /// binder, it is incremented (via `shift_in`).
706    current_index: ty::DebruijnIndex,
707
708    /// Callback invoked for each free region. The `DebruijnIndex`
709    /// points to the binder *just outside* the ones we have passed
710    /// through.
711    fold_region_fn: F,
712}
713
714impl<I, F> RegionFolder<I, F> {
715    #[inline]
716    pub fn new(cx: I, fold_region_fn: F) -> RegionFolder<I, F> {
717        RegionFolder { cx, current_index: ty::INNERMOST, fold_region_fn }
718    }
719}
720
721impl<I, F> TypeFolder<I> for RegionFolder<I, F>
722where
723    I: Interner,
724    F: FnMut(Region<I>, ty::DebruijnIndex) -> Region<I>,
725{
726    fn cx(&self) -> I {
727        self.cx
728    }
729
730    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
731        self.current_index.shift_in(1);
732        let t = t.super_fold_with(self);
733        self.current_index.shift_out(1);
734        t
735    }
736
737    {}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::DEBUG <=
                ::tracing::level_filters::LevelFilter::current() || { false }
    {
    __tracing_attr_span =
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("fold_region",
                                "rustc_type_ir::fold", ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs"),
                                ::tracing_core::__macro_support::Option::Some(737u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_type_ir::fold"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("r")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("r");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        { interest = __CALLSITE.interest(); !interest.is_never() }
                    &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest) {
                let meta = __CALLSITE.metadata();
                ::tracing::Span::new(meta,
                    &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&r)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return: Region<I> = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        match r.kind() {
                            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) if
                                debruijn < self.current_index => {
                                {
                                    use ::tracing::__macro_support::Callsite as _;
                                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                        {
                                            static META: ::tracing::Metadata<'static> =
                                                {
                                                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs:743",
                                                        "rustc_type_ir::fold", ::tracing::Level::DEBUG,
                                                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs"),
                                                        ::tracing_core::__macro_support::Option::Some(743u32),
                                                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::fold"),
                                                        ::tracing_core::field::FieldSet::new(&["message",
                                                                        {
                                                                            const NAME:
                                                                                ::tracing::__macro_support::FieldName<{
                                                                                    ::tracing::__macro_support::FieldName::len("self.current_index")
                                                                                }> =
                                                                                ::tracing::__macro_support::FieldName::new("self.current_index");
                                                                            NAME.as_str()
                                                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                        ::tracing::metadata::Kind::EVENT)
                                                };
                                            ::tracing::callsite::DefaultCallsite::new(&META)
                                        };
                                    let enabled =
                                        ::tracing::Level::DEBUG <=
                                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                                ::tracing::Level::DEBUG <=
                                                    ::tracing::level_filters::LevelFilter::current() &&
                                            {
                                                let interest = __CALLSITE.interest();
                                                !interest.is_never() &&
                                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                        interest)
                                            };
                                    if enabled {
                                        (|value_set: ::tracing::field::ValueSet|
                                                    {
                                                        let meta = __CALLSITE.metadata();
                                                        ::tracing::Event::dispatch(meta, &value_set);
                                                        ;
                                                    })({
                                                #[allow(unused_imports)]
                                                use ::tracing::field::{debug, display, Value};
                                                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("skipped bound region")
                                                                            as &dyn ::tracing::field::Value)),
                                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.current_index)
                                                                            as &dyn ::tracing::field::Value))])
                                            });
                                    } else { ; }
                                };
                                r
                            }
                            ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
                                {
                                    use ::tracing::__macro_support::Callsite as _;
                                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                        {
                                            static META: ::tracing::Metadata<'static> =
                                                {
                                                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs:747",
                                                        "rustc_type_ir::fold", ::tracing::Level::DEBUG,
                                                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs"),
                                                        ::tracing_core::__macro_support::Option::Some(747u32),
                                                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::fold"),
                                                        ::tracing_core::field::FieldSet::new(&["message",
                                                                        {
                                                                            const NAME:
                                                                                ::tracing::__macro_support::FieldName<{
                                                                                    ::tracing::__macro_support::FieldName::len("self.current_index")
                                                                                }> =
                                                                                ::tracing::__macro_support::FieldName::new("self.current_index");
                                                                            NAME.as_str()
                                                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                        ::tracing::metadata::Kind::EVENT)
                                                };
                                            ::tracing::callsite::DefaultCallsite::new(&META)
                                        };
                                    let enabled =
                                        ::tracing::Level::DEBUG <=
                                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                                ::tracing::Level::DEBUG <=
                                                    ::tracing::level_filters::LevelFilter::current() &&
                                            {
                                                let interest = __CALLSITE.interest();
                                                !interest.is_never() &&
                                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                        interest)
                                            };
                                    if enabled {
                                        (|value_set: ::tracing::field::ValueSet|
                                                    {
                                                        let meta = __CALLSITE.metadata();
                                                        ::tracing::Event::dispatch(meta, &value_set);
                                                        ;
                                                    })({
                                                #[allow(unused_imports)]
                                                use ::tracing::field::{debug, display, Value};
                                                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("skipped bound region")
                                                                            as &dyn ::tracing::field::Value)),
                                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.current_index)
                                                                            as &dyn ::tracing::field::Value))])
                                            });
                                    } else { ; }
                                };
                                r
                            }
                            _ => {
                                {
                                    use ::tracing::__macro_support::Callsite as _;
                                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                        {
                                            static META: ::tracing::Metadata<'static> =
                                                {
                                                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs:751",
                                                        "rustc_type_ir::fold", ::tracing::Level::DEBUG,
                                                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs"),
                                                        ::tracing_core::__macro_support::Option::Some(751u32),
                                                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::fold"),
                                                        ::tracing_core::field::FieldSet::new(&["message",
                                                                        {
                                                                            const NAME:
                                                                                ::tracing::__macro_support::FieldName<{
                                                                                    ::tracing::__macro_support::FieldName::len("self.current_index")
                                                                                }> =
                                                                                ::tracing::__macro_support::FieldName::new("self.current_index");
                                                                            NAME.as_str()
                                                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                        ::tracing::metadata::Kind::EVENT)
                                                };
                                            ::tracing::callsite::DefaultCallsite::new(&META)
                                        };
                                    let enabled =
                                        ::tracing::Level::DEBUG <=
                                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                                ::tracing::Level::DEBUG <=
                                                    ::tracing::level_filters::LevelFilter::current() &&
                                            {
                                                let interest = __CALLSITE.interest();
                                                !interest.is_never() &&
                                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                        interest)
                                            };
                                    if enabled {
                                        (|value_set: ::tracing::field::ValueSet|
                                                    {
                                                        let meta = __CALLSITE.metadata();
                                                        ::tracing::Event::dispatch(meta, &value_set);
                                                        ;
                                                    })({
                                                #[allow(unused_imports)]
                                                use ::tracing::field::{debug, display, Value};
                                                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("folding free region")
                                                                            as &dyn ::tracing::field::Value)),
                                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.current_index)
                                                                            as &dyn ::tracing::field::Value))])
                                            });
                                    } else { ; }
                                };
                                (self.fold_region_fn)(r, self.current_index)
                            }
                        }
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs:737",
                        "rustc_type_ir::fold", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_type_ir/src/fold.rs"),
                        ::tracing_core::__macro_support::Option::Some(737u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::fold"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(skip(self), level = "debug", ret)]
738    fn fold_region(&mut self, r: Region<I>) -> Region<I> {
739        match r.kind() {
740            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
741                if debruijn < self.current_index =>
742            {
743                debug!(?self.current_index, "skipped bound region");
744                r
745            }
746            ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
747                debug!(?self.current_index, "skipped bound region");
748                r
749            }
750            _ => {
751                debug!(?self.current_index, "folding free region");
752                (self.fold_region_fn)(r, self.current_index)
753            }
754        }
755    }
756
757    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
758        if t.has_regions() { t.super_fold_with(self) } else { t }
759    }
760
761    fn fold_const(&mut self, ct: Const<I>) -> Const<I> {
762        if ct.has_regions() { ct.super_fold_with(self) } else { ct }
763    }
764
765    fn fold_predicate<P: PredicateProxy<I>>(&mut self, p: P) -> P {
766        if p.has_regions() { p.super_fold_with(self) } else { p }
767    }
768
769    fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
770        if c.has_regions() { c.super_fold_with(self) } else { c }
771    }
772}
773
774/// This function should ideally only be used if either the `TypingMode`
775/// or the `ParamEnv` differs from the environment the aliases were normalized
776/// in.
777///
778/// Cases outside these two should consider whether the problem can be
779/// fixed at the root instead.
780pub fn set_aliases_to_non_rigid<I: Interner, T>(cx: I, value: T) -> ty::Unnormalized<I, T>
781where
782    T: TypeFoldable<I>,
783{
784    let folded = set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::AllToNonRigid);
785    ty::Unnormalized::new(folded)
786}
787
788pub fn set_opaques_to_non_rigid<I: Interner, T>(cx: I, value: T) -> ty::Unnormalized<I, T>
789where
790    T: TypeFoldable<I>,
791{
792    let folded = set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::OpaqueToNonRigid);
793    ty::Unnormalized::new(folded)
794}
795
796pub fn set_aliases_to_rigid<I: Interner, T>(cx: I, value: T) -> T
797where
798    T: TypeFoldable<I>,
799{
800    set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::AllToRigid)
801}
802
803pub fn set_type_aliases_to_rigid<I: Interner, T>(cx: I, value: T) -> T
804where
805    T: TypeFoldable<I>,
806{
807    set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::TypeToRigid)
808}
809
810fn set_aliases_rigidness_with_mode<I: Interner, T>(cx: I, value: T, mode: RigidnessFoldMode) -> T
811where
812    T: TypeFoldable<I>,
813{
814    if !mode.needs_change(&value) {
815        return value;
816    }
817
818    let mut folder = RigidnessFolder { cx, mode };
819    value.fold_with(&mut folder)
820}
821
822enum RigidnessFoldMode {
823    AllToRigid,
824    AllToNonRigid,
825    TypeToRigid,
826    OpaqueToNonRigid,
827}
828
829impl RigidnessFoldMode {
830    fn needs_change<I: Interner, T: TypeVisitable<I>>(&self, v: &T) -> bool {
831        match self {
832            RigidnessFoldMode::AllToRigid => v.has_non_rigid_aliases(),
833            RigidnessFoldMode::AllToNonRigid => v.has_rigid_aliases(),
834            RigidnessFoldMode::TypeToRigid => {
835                v.has_non_rigid_aliases()
836                    && v.has_type_flags(ty::TypeFlags::HAS_ALIAS - ty::TypeFlags::HAS_CONST_ALIAS)
837            }
838            RigidnessFoldMode::OpaqueToNonRigid => v.has_rigid_aliases() && v.has_opaque_types(),
839        }
840    }
841}
842
843// Set aliases to be rigid or non-rigid according to the mode.
844struct RigidnessFolder<I: Interner> {
845    cx: I,
846    mode: RigidnessFoldMode,
847}
848
849impl<I: Interner> TypeFolder<I> for RigidnessFolder<I> {
850    #[inline]
851    fn cx(&self) -> I {
852        self.cx
853    }
854
855    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
856        if self.mode.needs_change(&t) { t.super_fold_with(self) } else { t }
857    }
858
859    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
860        if !self.mode.needs_change(&t) {
861            return t;
862        }
863
864        match t.kind() {
865            ty::Alias(is_rigid, alias_ty) => {
866                let alias_ty = alias_ty.fold_with(self);
867                match self.mode {
868                    RigidnessFoldMode::AllToRigid | RigidnessFoldMode::TypeToRigid => {
869                        I::Ty::new_alias(self.cx(), ty::IsRigid::Yes, alias_ty)
870                    }
871                    RigidnessFoldMode::AllToNonRigid => {
872                        I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty)
873                    }
874                    RigidnessFoldMode::OpaqueToNonRigid => {
875                        if let ty::AliasTyKind::Opaque { .. } = alias_ty.kind {
876                            I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty)
877                        } else {
878                            I::Ty::new_alias(self.cx(), is_rigid, alias_ty)
879                        }
880                    }
881                }
882            }
883            _ => t.super_fold_with(self),
884        }
885    }
886
887    fn fold_const(&mut self, c: Const<I>) -> Const<I> {
888        if !self.mode.needs_change(&c) {
889            return c;
890        }
891
892        match c.kind() {
893            ty::ConstKind::Alias(is_rigid, alias_const) => {
894                let alias_const = alias_const.fold_with(self);
895                match self.mode {
896                    RigidnessFoldMode::AllToRigid => {
897                        Const::new_alias(self.cx, ty::IsRigid::Yes, alias_const)
898                    }
899                    RigidnessFoldMode::AllToNonRigid => {
900                        Const::new_alias(self.cx(), ty::IsRigid::No, alias_const)
901                    }
902                    RigidnessFoldMode::OpaqueToNonRigid | RigidnessFoldMode::TypeToRigid => {
903                        Const::new_alias(self.cx(), is_rigid, alias_const)
904                    }
905                }
906            }
907            _ => c.super_fold_with(self),
908        }
909    }
910
911    fn fold_predicate<P: PredicateProxy<I>>(&mut self, p: P) -> P {
912        if self.mode.needs_change(&p) { p.super_fold_with(self) } else { p }
913    }
914
915    fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
916        if self.mode.needs_change(&c) { c.super_fold_with(self) } else { c }
917    }
918}