Skip to main content

rustc_next_trait_solver/canonical/
canonicalizer.rs

1use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
2use rustc_type_ir::inherent::*;
3use rustc_type_ir::solve::{Goal, QueryInput};
4use rustc_type_ir::{
5    self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, Flags, InferCtxtLike,
6    Interner, PlaceholderConst, PlaceholderType, Region, TypeFlags, TypeFoldable, TypeFolder,
7    TypeSuperFoldable, TypeVisitableExt,
8};
9use thin_vec::ThinVec;
10
11use crate::delegate::SolverDelegate;
12
13/// Does this have infer/placeholder/param, free regions or ReErased?
14const NEEDS_CANONICAL: TypeFlags = TypeFlags::from_bits(
15    TypeFlags::HAS_INFER.bits()
16        | TypeFlags::HAS_PLACEHOLDER.bits()
17        | TypeFlags::HAS_PARAM.bits()
18        | TypeFlags::HAS_FREE_REGIONS.bits()
19        | TypeFlags::HAS_RE_ERASED.bits(),
20)
21.unwrap();
22
23#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CanonicalizeInputKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                CanonicalizeInputKind::ParamEnv => "ParamEnv",
                CanonicalizeInputKind::Predicate => "Predicate",
            })
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for CanonicalizeInputKind {
    #[inline]
    fn clone(&self) -> CanonicalizeInputKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CanonicalizeInputKind { }Copy)]
24enum CanonicalizeInputKind {
25    /// When canonicalizing the `param_env`, we keep `'static` as merging
26    /// trait candidates relies on it when deciding whether a where-bound
27    /// is trivial.
28    ParamEnv,
29    /// When canonicalizing predicates, we don't keep `'static`.
30    Predicate,
31}
32
33/// Whether we're canonicalizing a query input or the query response.
34///
35/// When canonicalizing an input we're in the context of the caller
36/// while canonicalizing the response happens in the context of the
37/// query.
38#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CanonicalizeMode {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            CanonicalizeMode::Input(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Input",
                    &__self_0),
            CanonicalizeMode::Response { max_input_universe: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Response", "max_input_universe", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for CanonicalizeMode {
    #[inline]
    fn clone(&self) -> CanonicalizeMode {
        let _: ::core::clone::AssertParamIsClone<CanonicalizeInputKind>;
        let _: ::core::clone::AssertParamIsClone<ty::UniverseIndex>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CanonicalizeMode { }Copy)]
39enum CanonicalizeMode {
40    Input(CanonicalizeInputKind),
41    /// FIXME: We currently return region constraints referring to
42    /// placeholders and inference variables from a binder instantiated
43    /// inside of the query.
44    ///
45    /// In the long term we should eagerly deal with these constraints
46    /// inside of the query and only propagate constraints which are
47    /// actually nameable by the caller.
48    Response {
49        /// The highest universe nameable by the caller.
50        ///
51        /// All variables in a universe nameable by the caller get mapped
52        /// to the root universe in the response and then mapped back to
53        /// their correct universe when applying the query response in the
54        /// context of the caller.
55        ///
56        /// This doesn't work for universes created inside of the query so
57        /// we do remember their universe in the response.
58        max_input_universe: ty::UniverseIndex,
59    },
60}
61
62pub(super) struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
63    delegate: &'a D,
64
65    // Immutable field.
66    canonicalize_mode: CanonicalizeMode,
67
68    // Mutable fields.
69    variables: ThinVec<I::GenericArg>,
70    var_kinds: Vec<CanonicalVarKind<I>>,
71    variable_lookup_table: HashMap<I::GenericArg, usize>,
72    /// Maps each `sub_unification_table_root_var` to the index of the first
73    /// variable which used it.
74    ///
75    /// This means in case two type variables have the same sub relations root,
76    /// we set the `sub_root` of the second variable to the position of the first.
77    /// Otherwise the `sub_root` of each type variable is just its own position.
78    sub_root_lookup_table: HashMap<ty::TyVid, usize>,
79
80    /// We can simply cache based on the ty itself, because we use
81    /// `ty::BoundVarIndexKind::Canonical`.
82    cache: HashMap<I::Ty, I::Ty>,
83}
84
85impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
86    pub(super) fn canonicalize_response<T: TypeFoldable<I>>(
87        delegate: &'a D,
88        max_input_universe: ty::UniverseIndex,
89        value: T,
90    ) -> ty::Canonical<I, T> {
91        let mut canonicalizer = Canonicalizer {
92            delegate,
93            canonicalize_mode: CanonicalizeMode::Response { max_input_universe },
94
95            variables: Default::default(),
96            variable_lookup_table: Default::default(),
97            sub_root_lookup_table: Default::default(),
98            var_kinds: Default::default(),
99
100            cache: Default::default(),
101        };
102
103        let value = if value.has_type_flags(NEEDS_CANONICAL) {
104            value.fold_with(&mut canonicalizer)
105        } else {
106            value
107        };
108        if true {
    if !!value.has_infer() {
        {
            ::core::panicking::panic_fmt(format_args!("unexpected infer in {0:?}",
                    value));
        }
    };
};debug_assert!(!value.has_infer(), "unexpected infer in {value:?}");
109        if true {
    if !!value.has_placeholders() {
        {
            ::core::panicking::panic_fmt(format_args!("unexpected placeholders in {0:?}",
                    value));
        }
    };
};debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}");
110        let (max_universe, _variables, var_kinds) = canonicalizer.finalize();
111        Canonical { max_universe, var_kinds, value }
112    }
113
114    fn canonicalize_param_env(
115        delegate: &'a D,
116        param_env: I::ParamEnv,
117    ) -> (
118        I::ParamEnv,
119        ThinVec<I::GenericArg>,
120        Vec<CanonicalVarKind<I>>,
121        HashMap<I::GenericArg, usize>,
122    ) {
123        if !param_env.has_type_flags(NEEDS_CANONICAL) {
124            return (param_env, ThinVec::new(), Vec::new(), Default::default());
125        }
126
127        // Check whether we can use the global cache for this param_env. As we only use
128        // the `param_env` itself as the cache key, considering any additional information
129        // durnig its canonicalization would be incorrect. We always canonicalize region
130        // inference variables in a separate universe, so these are fine. However, we do
131        // track the universe of type and const inference variables so these must not be
132        // globally cached. We don't rely on any additional information when canonicalizing
133        // placeholders.
134        if !param_env.has_non_region_infer() {
135            delegate.cx().canonical_param_env_cache_get_or_insert(
136                param_env,
137                || {
138                    let mut env_canonicalizer = Canonicalizer {
139                        delegate,
140                        canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv),
141
142                        variables: Default::default(),
143                        variable_lookup_table: Default::default(),
144                        sub_root_lookup_table: Default::default(),
145                        var_kinds: Default::default(),
146
147                        cache: Default::default(),
148                    };
149                    let param_env = param_env.fold_with(&mut env_canonicalizer);
150                    if true {
    if !env_canonicalizer.sub_root_lookup_table.is_empty() {
        ::core::panicking::panic("assertion failed: env_canonicalizer.sub_root_lookup_table.is_empty()")
    };
};debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
151                    CanonicalParamEnvCacheEntry {
152                        param_env,
153                        variable_lookup_table: env_canonicalizer.variable_lookup_table,
154                        var_kinds: env_canonicalizer.var_kinds,
155                        variables: env_canonicalizer.variables,
156                    }
157                },
158                |&CanonicalParamEnvCacheEntry {
159                     param_env,
160                     variables: ref cache_variables,
161                     ref variable_lookup_table,
162                     ref var_kinds,
163                 }| {
164                    // FIXME(nnethercote): for reasons I don't understand, this `new`+`extend`
165                    // combination is faster than `variables.clone()`, because it somehow avoids
166                    // some allocations.
167                    let mut variables = ThinVec::new();
168                    variables.extend(cache_variables.iter().copied());
169                    (param_env, variables, var_kinds.clone(), variable_lookup_table.clone())
170                },
171            )
172        } else {
173            let mut env_canonicalizer = Canonicalizer {
174                delegate,
175                canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv),
176
177                variables: Default::default(),
178                variable_lookup_table: Default::default(),
179                sub_root_lookup_table: Default::default(),
180                var_kinds: Default::default(),
181
182                cache: Default::default(),
183            };
184            let param_env = param_env.fold_with(&mut env_canonicalizer);
185            if true {
    if !env_canonicalizer.sub_root_lookup_table.is_empty() {
        ::core::panicking::panic("assertion failed: env_canonicalizer.sub_root_lookup_table.is_empty()")
    };
};debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
186            (
187                param_env,
188                env_canonicalizer.variables,
189                env_canonicalizer.var_kinds,
190                env_canonicalizer.variable_lookup_table,
191            )
192        }
193    }
194
195    /// When canonicalizing query inputs, we keep `'static` in the `param_env`
196    /// but erase it everywhere else. We generally don't want to depend on region
197    /// identity, so while it should not matter whether `'static` is kept in the
198    /// value or opaque type storage as well, this prevents us from accidentally
199    /// relying on it in the future.
200    ///
201    /// We want to keep the option of canonicalizing `'static` to an existential
202    /// variable in the future by changing the way we detect global where-bounds.
203    pub(super) fn canonicalize_input<P: TypeFoldable<I>>(
204        delegate: &'a D,
205        input: QueryInput<I, P>,
206    ) -> (ThinVec<I::GenericArg>, ty::Canonical<I, QueryInput<I, P>>) {
207        // First canonicalize the `param_env` while keeping `'static`
208        let (param_env, variables, var_kinds, variable_lookup_table) =
209            Canonicalizer::canonicalize_param_env(delegate, input.goal.param_env);
210        // Then canonicalize the rest of the input without keeping `'static`
211        // while *mostly* reusing the canonicalizer from above.
212        let mut rest_canonicalizer = Canonicalizer {
213            delegate,
214            canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::Predicate),
215
216            variables,
217            variable_lookup_table,
218            sub_root_lookup_table: Default::default(),
219            var_kinds,
220
221            // We do not reuse the cache as it may contain entries whose canonicalized
222            // value contains `'static`. While we could alternatively handle this by
223            // checking for `'static` when using cached entries, this does not
224            // feel worth the effort. I do not expect that a `ParamEnv` will ever
225            // contain large enough types for caching to be necessary.
226            cache: Default::default(),
227        };
228
229        let predicate = input.goal.predicate;
230        let predicate = predicate.fold_with(&mut rest_canonicalizer);
231        let goal = Goal { param_env, predicate };
232
233        let predefined_opaques_in_body = input.predefined_opaques_in_body;
234        let predefined_opaques_in_body =
235            if predefined_opaques_in_body.has_type_flags(NEEDS_CANONICAL) {
236                predefined_opaques_in_body.fold_with(&mut rest_canonicalizer)
237            } else {
238                predefined_opaques_in_body
239            };
240
241        let value = QueryInput { goal, predefined_opaques_in_body };
242
243        if true {
    if !!value.has_infer() {
        {
            ::core::panicking::panic_fmt(format_args!("unexpected infer in {0:?}",
                    value));
        }
    };
};debug_assert!(!value.has_infer(), "unexpected infer in {value:?}");
244        if true {
    if !!value.has_placeholders() {
        {
            ::core::panicking::panic_fmt(format_args!("unexpected placeholders in {0:?}",
                    value));
        }
    };
};debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}");
245        let (max_universe, variables, var_kinds) = rest_canonicalizer.finalize();
246        (variables, Canonical { max_universe, var_kinds, value })
247    }
248
249    fn get_or_insert_bound_var(
250        &mut self,
251        arg: impl Into<I::GenericArg>,
252        kind: CanonicalVarKind<I>,
253    ) -> ty::BoundVar {
254        // The exact value of 16 here doesn't matter that much (8 and 32 give extremely similar
255        // results). So long as we have protection against the rare cases where the length reaches
256        // 1000+ (e.g. `wg-grammar`).
257        let arg = arg.into();
258        let idx = if self.variables.len() > 16 {
259            if self.variable_lookup_table.is_empty() {
260                self.variable_lookup_table.extend(self.variables.iter().copied().zip(0..));
261            }
262
263            *self.variable_lookup_table.entry(arg).or_insert_with(|| {
264                let var = self.variables.len();
265                self.variables.push(arg);
266                self.var_kinds.push(kind);
267                var
268            })
269        } else {
270            self.variables.iter().position(|&v| v == arg).unwrap_or_else(|| {
271                let var = self.variables.len();
272                self.variables.push(arg);
273                self.var_kinds.push(kind);
274                var
275            })
276        };
277
278        ty::BoundVar::from(idx)
279    }
280
281    fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
282        let root_vid = self.delegate.sub_unification_table_root_var(vid);
283        let idx =
284            *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
285        ty::BoundVar::from(idx)
286    }
287
288    fn finalize(self) -> (ty::UniverseIndex, ThinVec<I::GenericArg>, I::CanonicalVarKinds) {
289        let mut var_kinds = self.var_kinds;
290        // See the rustc-dev-guide section about how we deal with universes
291        // during canonicalization in the new solver.
292        let max_universe = match self.canonicalize_mode {
293            // All placeholders and vars are canonicalized in the root universe.
294            CanonicalizeMode::Input { .. } => {
295                if true {
    if !var_kinds.iter().all(|var| var.universe() == ty::UniverseIndex::ROOT)
        {
        {
            ::core::panicking::panic_fmt(format_args!("expected all vars to be canonicalized in root universe: {0:#?}",
                    var_kinds));
        }
    };
};debug_assert!(
296                    var_kinds.iter().all(|var| var.universe() == ty::UniverseIndex::ROOT),
297                    "expected all vars to be canonicalized in root universe: {var_kinds:#?}"
298                );
299                ty::UniverseIndex::ROOT
300            }
301            // When canonicalizing a response we map a universes already entered
302            // by the caller to the root universe and only return useful universe
303            // information for placeholders and inference variables created inside
304            // of the query.
305            CanonicalizeMode::Response { max_input_universe } => {
306                for var in var_kinds.iter_mut() {
307                    let uv = var.universe();
308                    let new_uv = ty::UniverseIndex::from(
309                        uv.index().saturating_sub(max_input_universe.index()),
310                    );
311                    *var = var.with_updated_universe(new_uv);
312                }
313                var_kinds
314                    .iter()
315                    .map(|kind| kind.universe())
316                    .max()
317                    .unwrap_or(ty::UniverseIndex::ROOT)
318            }
319        };
320        let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds);
321        (max_universe, self.variables, var_kinds)
322    }
323
324    fn inner_fold_ty(&mut self, t: I::Ty) -> I::Ty {
325        let kind = match t.kind() {
326            ty::Infer(i) => match i {
327                ty::TyVar(vid) => {
328                    if true {
    {
        match (&self.delegate.opportunistic_resolve_ty_var(vid), &t) {
            (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::Some(format_args!("ty vid should have been resolved fully before canonicalization")));
                }
            }
        }
    };
};debug_assert_eq!(
329                        self.delegate.opportunistic_resolve_ty_var(vid),
330                        t,
331                        "ty vid should have been resolved fully before canonicalization"
332                    );
333
334                    let sub_root = self.get_or_insert_sub_root(vid);
335                    let ui = match self.canonicalize_mode {
336                        CanonicalizeMode::Input { .. } => ty::UniverseIndex::ROOT,
337                        CanonicalizeMode::Response { .. } => self
338                            .delegate
339                            .universe_of_ty(vid)
340                            .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("ty var should have been resolved: {0:?}",
            t));
}panic!("ty var should have been resolved: {t:?}")),
341                    };
342                    CanonicalVarKind::Ty { ui, sub_root }
343                }
344                ty::IntVar(vid) => {
345                    if true {
    {
        match (&self.delegate.opportunistic_resolve_int_var(vid), &t) {
            (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::Some(format_args!("ty vid should have been resolved fully before canonicalization")));
                }
            }
        }
    };
};debug_assert_eq!(
346                        self.delegate.opportunistic_resolve_int_var(vid),
347                        t,
348                        "ty vid should have been resolved fully before canonicalization"
349                    );
350                    CanonicalVarKind::Int
351                }
352                ty::FloatVar(vid) => {
353                    if true {
    {
        match (&self.delegate.opportunistic_resolve_float_var(vid), &t) {
            (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::Some(format_args!("ty vid should have been resolved fully before canonicalization")));
                }
            }
        }
    };
};debug_assert_eq!(
354                        self.delegate.opportunistic_resolve_float_var(vid),
355                        t,
356                        "ty vid should have been resolved fully before canonicalization"
357                    );
358                    CanonicalVarKind::Float
359                }
360                ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
361                    {
    ::core::panicking::panic_fmt(format_args!("fresh vars not expected in canonicalization"));
}panic!("fresh vars not expected in canonicalization")
362                }
363            },
364            ty::Placeholder(placeholder) => match self.canonicalize_mode {
365                CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy(
366                    PlaceholderType::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
367                ),
368                CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder),
369            },
370            ty::Param(_) => match self.canonicalize_mode {
371                CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy(
372                    PlaceholderType::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
373                ),
374                CanonicalizeMode::Response { .. } => {
    ::core::panicking::panic_fmt(format_args!("param ty in response: {0:?}",
            t));
}panic!("param ty in response: {t:?}"),
375            },
376            ty::Bool
377            | ty::Char
378            | ty::Int(_)
379            | ty::Uint(_)
380            | ty::Float(_)
381            | ty::Adt(_, _)
382            | ty::Foreign(_)
383            | ty::Str
384            | ty::Array(_, _)
385            | ty::Slice(_)
386            | ty::RawPtr(_, _)
387            | ty::Ref(_, _, _)
388            | ty::Pat(_, _)
389            | ty::FnDef(_, _)
390            | ty::FnPtr(..)
391            | ty::UnsafeBinder(_)
392            | ty::Dynamic(_, _)
393            | ty::Closure(..)
394            | ty::CoroutineClosure(..)
395            | ty::Coroutine(_, _)
396            | ty::CoroutineWitness(..)
397            | ty::Never
398            | ty::Tuple(_)
399            | ty::Alias(_, _)
400            | ty::Bound(_, _)
401            | ty::Error(_) => {
402                return ensure_sufficient_stack(|| t.super_fold_with(self));
403            }
404        };
405
406        let var = self.get_or_insert_bound_var(t, kind);
407
408        Ty::new_canonical_bound(self.cx(), var)
409    }
410}
411
412impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicalizer<'_, D, I> {
413    fn cx(&self) -> I {
414        self.delegate.cx()
415    }
416
417    fn fold_region(&mut self, r: Region<I>) -> Region<I> {
418        // We canonicalize free regions from the input into placeholder regions so that
419        // region constraints created in nested contexts can be propagated back to the
420        // caller, instead of unifying them.
421        // See the following Zulip discussion for details:
422        // https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/A.20question.20on.20.23251/near/579240238
423        let kind = match r.kind() {
424            ty::ReBound(..) => return r,
425
426            // We don't canonicalize `ReStatic` in the `param_env` as we use it
427            // when checking whether a `ParamEnv` candidate is global.
428            ty::ReStatic => match self.canonicalize_mode {
429                CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => {
430                    CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
431                        ty::UniverseIndex::ROOT,
432                        self.variables.len().into(),
433                    ))
434                }
435                CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv)
436                | CanonicalizeMode::Response { .. } => return r,
437            },
438
439            // `ReErased` should only be encountered in the hidden
440            // type of an opaque for regions that are ignored for the purposes of
441            // captures.
442            //
443            // FIXME: We should investigate the perf implications of not uniquifying
444            // `ReErased`. We may be able to short-circuit registering region
445            // obligations if we encounter a `ReErased` on one side, for example.
446            ty::ReErased | ty::ReError(_) => match self.canonicalize_mode {
447                CanonicalizeMode::Input(_) => {
448                    CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
449                        ty::UniverseIndex::ROOT,
450                        self.variables.len().into(),
451                    ))
452                }
453                CanonicalizeMode::Response { .. } => return r,
454            },
455
456            ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode {
457                CanonicalizeMode::Input(_) => {
458                    CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
459                        ty::UniverseIndex::ROOT,
460                        self.variables.len().into(),
461                    ))
462                }
463                CanonicalizeMode::Response { .. } => {
464                    {
    ::core::panicking::panic_fmt(format_args!("unexpected region in response: {0:?}",
            r));
}panic!("unexpected region in response: {r:?}")
465                }
466            },
467
468            ty::RePlaceholder(placeholder) => match self.canonicalize_mode {
469                CanonicalizeMode::Input(_) => {
470                    CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
471                        ty::UniverseIndex::ROOT,
472                        self.variables.len().into(),
473                    ))
474                }
475                CanonicalizeMode::Response { max_input_universe } => {
476                    // If we have a placeholder region inside of a query, it must be from
477                    // a new universe, unless from the root universe, which is used for
478                    // canonicalization of any free region from the input.
479                    if placeholder.universe() != ty::UniverseIndex::ROOT
480                        && max_input_universe.can_name(placeholder.universe())
481                    {
482                        {
    ::core::panicking::panic_fmt(format_args!("new placeholder in universe {0:?}: {1:?}",
            max_input_universe, r));
};panic!("new placeholder in universe {max_input_universe:?}: {r:?}");
483                    }
484                    CanonicalVarKind::PlaceholderRegion(placeholder)
485                }
486            },
487
488            ty::ReVar(vid) => {
489                if true {
    {
        match (&self.delegate.opportunistic_resolve_lt_var(vid), &r) {
            (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::Some(format_args!("region vid should have been resolved fully before canonicalization")));
                }
            }
        }
    };
};debug_assert_eq!(
490                    self.delegate.opportunistic_resolve_lt_var(vid),
491                    r,
492                    "region vid should have been resolved fully before canonicalization"
493                );
494                match self.canonicalize_mode {
495                    CanonicalizeMode::Input(_) => {
496                        CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
497                            ty::UniverseIndex::ROOT,
498                            self.variables.len().into(),
499                        ))
500                    }
501                    CanonicalizeMode::Response { .. } => {
502                        CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap())
503                    }
504                }
505            }
506        };
507
508        let var = self.get_or_insert_bound_var(r, kind);
509
510        Region::new_canonical_bound(self.cx(), var)
511    }
512
513    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
514        if !t.flags().intersects(NEEDS_CANONICAL) {
515            t
516        } else if let Some(&ty) = self.cache.get(&t) {
517            ty
518        } else {
519            let res = self.inner_fold_ty(t);
520            let old = self.cache.insert(t, res);
521            {
    match (&old, &None) {
        (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!(old, None);
522            res
523        }
524    }
525
526    fn fold_const(&mut self, c: I::Const) -> I::Const {
527        if !c.flags().intersects(NEEDS_CANONICAL) {
528            return c;
529        }
530
531        let kind = match c.kind() {
532            ty::ConstKind::Infer(i) => match i {
533                ty::InferConst::Var(vid) => {
534                    if true {
    {
        match (&self.delegate.opportunistic_resolve_ct_var(vid), &c) {
            (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::Some(format_args!("const vid should have been resolved fully before canonicalization")));
                }
            }
        }
    };
};debug_assert_eq!(
535                        self.delegate.opportunistic_resolve_ct_var(vid),
536                        c,
537                        "const vid should have been resolved fully before canonicalization"
538                    );
539
540                    match self.canonicalize_mode {
541                        CanonicalizeMode::Input { .. } => {
542                            CanonicalVarKind::Const(ty::UniverseIndex::ROOT)
543                        }
544                        CanonicalizeMode::Response { .. } => {
545                            CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap())
546                        }
547                    }
548                }
549                ty::InferConst::Fresh(_) => ::core::panicking::panic("not implemented")unimplemented!(),
550            },
551            ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
552                CanonicalizeMode::Input { .. } => {
553                    CanonicalVarKind::PlaceholderConst(PlaceholderConst::new_anon(
554                        ty::UniverseIndex::ROOT,
555                        self.variables.len().into(),
556                    ))
557                }
558                CanonicalizeMode::Response { .. } => {
559                    CanonicalVarKind::PlaceholderConst(placeholder)
560                }
561            },
562            ty::ConstKind::Param(_) => match self.canonicalize_mode {
563                CanonicalizeMode::Input { .. } => {
564                    CanonicalVarKind::PlaceholderConst(PlaceholderConst::new_anon(
565                        ty::UniverseIndex::ROOT,
566                        self.variables.len().into(),
567                    ))
568                }
569                CanonicalizeMode::Response { .. } => {
    ::core::panicking::panic_fmt(format_args!("param ty in response: {0:?}",
            c));
}panic!("param ty in response: {c:?}"),
570            },
571            // FIXME: See comment above -- we could fold the region separately or something.
572            ty::ConstKind::Bound(_, _)
573            | ty::ConstKind::Alias(_, _)
574            | ty::ConstKind::Value(_)
575            | ty::ConstKind::Error(_)
576            | ty::ConstKind::Expr(_) => return c.super_fold_with(self),
577        };
578
579        let var = self.get_or_insert_bound_var(c, kind);
580
581        Const::new_canonical_bound(self.cx(), var)
582    }
583
584    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
585        if !p.flags().intersects(NEEDS_CANONICAL) { p } else { p.super_fold_with(self) }
586    }
587
588    fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
589        match self.canonicalize_mode {
590            CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv)
591            | CanonicalizeMode::Response { max_input_universe: _ } => {}
592            CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => {
593                { ::core::panicking::panic_fmt(format_args!("erasing \'static in env")); }panic!("erasing 'static in env")
594            }
595        }
596        if !c.flags().intersects(NEEDS_CANONICAL) { c } else { c.super_fold_with(self) }
597    }
598}