hir_ty/next_solver/infer/canonical/
canonicalizer.rs

1//! This module contains code to canonicalize values into a `Canonical<'db, T>`.
2//!
3//! For an overview of what canonicalization is and how it fits into
4//! rustc, check out the [chapter in the rustc dev guide][c].
5//!
6//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
7
8use rustc_hash::FxHashMap;
9use rustc_index::Idx;
10use rustc_type_ir::InferTy::{self, FloatVar, IntVar, TyVar};
11use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _};
12use rustc_type_ir::{
13    BoundVar, BoundVarIndexKind, DebruijnIndex, Flags, InferConst, RegionKind, TyVid, TypeFlags,
14    TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex,
15};
16use smallvec::SmallVec;
17use tracing::debug;
18
19use crate::next_solver::infer::InferCtxt;
20use crate::next_solver::{
21    Binder, Canonical, CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, GenericArg,
22    Placeholder, Region, Ty, TyKind,
23};
24
25/// When we canonicalize a value to form a query, we wind up replacing
26/// various parts of it with canonical variables. This struct stores
27/// those replaced bits to remember for when we process the query
28/// result.
29#[derive(Clone, Debug)]
30pub struct OriginalQueryValues<'db> {
31    /// Map from the universes that appear in the query to the universes in the
32    /// caller context. For all queries except `evaluate_goal` (used by Chalk),
33    /// we only ever put ROOT values into the query, so this map is very
34    /// simple.
35    pub universe_map: SmallVec<[UniverseIndex; 4]>,
36
37    /// This is equivalent to `CanonicalVarValues`, but using a
38    /// `SmallVec` yields a significant performance win.
39    pub var_values: SmallVec<[GenericArg<'db>; 8]>,
40}
41
42impl<'db> Default for OriginalQueryValues<'db> {
43    fn default() -> Self {
44        let mut universe_map = SmallVec::default();
45        universe_map.push(UniverseIndex::ROOT);
46
47        Self { universe_map, var_values: SmallVec::default() }
48    }
49}
50
51impl<'db> InferCtxt<'db> {
52    /// Canonicalizes a query value `V`. When we canonicalize a query,
53    /// we not only canonicalize unbound inference variables, but we
54    /// *also* replace all free regions whatsoever. So for example a
55    /// query like `T: Trait<'static>` would be canonicalized to
56    ///
57    /// ```text
58    /// T: Trait<'?0>
59    /// ```
60    ///
61    /// with a mapping M that maps `'?0` to `'static`.
62    ///
63    /// To get a good understanding of what is happening here, check
64    /// out the [chapter in the rustc dev guide][c].
65    ///
66    /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
67    pub fn canonicalize_query<V>(
68        &self,
69        value: V,
70        query_state: &mut OriginalQueryValues<'db>,
71    ) -> Canonical<'db, V>
72    where
73        V: TypeFoldable<DbInterner<'db>>,
74    {
75        Canonicalizer::canonicalize(
76            value,
77            self,
78            self.interner,
79            &CanonicalizeAllFreeRegions,
80            query_state,
81        )
82    }
83
84    /// Canonicalizes a query *response* `V`. When we canonicalize a
85    /// query response, we only canonicalize unbound inference
86    /// variables, and we leave other free regions alone. So,
87    /// continuing with the example from `canonicalize_query`, if
88    /// there was an input query `T: Trait<'static>`, it would have
89    /// been canonicalized to
90    ///
91    /// ```text
92    /// T: Trait<'?0>
93    /// ```
94    ///
95    /// with a mapping M that maps `'?0` to `'static`. But if we found that there
96    /// exists only one possible impl of `Trait`, and it looks like
97    /// ```ignore (illustrative)
98    /// impl<T> Trait<'static> for T { .. }
99    /// ```
100    /// then we would prepare a query result R that (among other
101    /// things) includes a mapping to `'?0 := 'static`. When
102    /// canonicalizing this query result R, we would leave this
103    /// reference to `'static` alone.
104    ///
105    /// To get a good understanding of what is happening here, check
106    /// out the [chapter in the rustc dev guide][c].
107    ///
108    /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
109    pub fn canonicalize_response<V>(&self, value: V) -> Canonical<'db, V>
110    where
111        V: TypeFoldable<DbInterner<'db>>,
112    {
113        let mut query_state = OriginalQueryValues::default();
114        Canonicalizer::canonicalize(
115            value,
116            self,
117            self.interner,
118            &CanonicalizeQueryResponse,
119            &mut query_state,
120        )
121    }
122
123    pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonical<'db, V>
124    where
125        V: TypeFoldable<DbInterner<'db>>,
126    {
127        let mut query_state = OriginalQueryValues::default();
128        Canonicalizer::canonicalize(
129            value,
130            self,
131            self.interner,
132            &CanonicalizeUserTypeAnnotation,
133            &mut query_state,
134        )
135    }
136}
137
138/// Controls how we canonicalize "free regions" that are not inference
139/// variables. This depends on what we are canonicalizing *for* --
140/// e.g., if we are canonicalizing to create a query, we want to
141/// replace those with inference variables, since we want to make a
142/// maximally general query. But if we are canonicalizing a *query
143/// response*, then we don't typically replace free regions, as they
144/// must have been introduced from other parts of the system.
145trait CanonicalizeMode {
146    fn canonicalize_free_region<'db>(
147        &self,
148        canonicalizer: &mut Canonicalizer<'_, 'db>,
149        r: Region<'db>,
150    ) -> Region<'db>;
151
152    fn any(&self) -> bool;
153
154    // Do we preserve universe of variables.
155    fn preserve_universes(&self) -> bool;
156}
157
158struct CanonicalizeQueryResponse;
159
160impl CanonicalizeMode for CanonicalizeQueryResponse {
161    fn canonicalize_free_region<'db>(
162        &self,
163        canonicalizer: &mut Canonicalizer<'_, 'db>,
164        mut r: Region<'db>,
165    ) -> Region<'db> {
166        let infcx = canonicalizer.infcx;
167
168        if let RegionKind::ReVar(vid) = r.kind() {
169            r = infcx
170                .inner
171                .borrow_mut()
172                .unwrap_region_constraints()
173                .opportunistic_resolve_var(canonicalizer.tcx, vid);
174            debug!(
175                "canonical: region var found with vid {vid:?}, \
176                     opportunistically resolved to {r:?}",
177            );
178        };
179
180        match r.kind() {
181            RegionKind::ReLateParam(_)
182            | RegionKind::ReErased
183            | RegionKind::ReStatic
184            | RegionKind::ReEarlyParam(..)
185            | RegionKind::ReError(..) => r,
186
187            RegionKind::RePlaceholder(placeholder) => canonicalizer
188                .canonical_var_for_region(CanonicalVarKind::PlaceholderRegion(placeholder), r),
189
190            RegionKind::ReVar(vid) => {
191                let universe = infcx
192                    .inner
193                    .borrow_mut()
194                    .unwrap_region_constraints()
195                    .probe_value(vid)
196                    .unwrap_err();
197                canonicalizer.canonical_var_for_region(CanonicalVarKind::Region(universe), r)
198            }
199
200            _ => {
201                // Other than `'static` or `'empty`, the query
202                // response should be executing in a fully
203                // canonicalized environment, so there shouldn't be
204                // any other region names it can come up.
205                //
206                // rust-lang/rust#57464: `impl Trait` can leak local
207                // scopes (in manner violating typeck). Therefore, use
208                // `delayed_bug` to allow type error over an ICE.
209                panic!("unexpected region in query response: `{r:?}`");
210            }
211        }
212    }
213
214    fn any(&self) -> bool {
215        false
216    }
217
218    fn preserve_universes(&self) -> bool {
219        true
220    }
221}
222
223struct CanonicalizeUserTypeAnnotation;
224
225impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
226    fn canonicalize_free_region<'db>(
227        &self,
228        canonicalizer: &mut Canonicalizer<'_, 'db>,
229        r: Region<'db>,
230    ) -> Region<'db> {
231        match r.kind() {
232            RegionKind::ReEarlyParam(_)
233            | RegionKind::ReLateParam(_)
234            | RegionKind::ReErased
235            | RegionKind::ReStatic
236            | RegionKind::ReError(_) => r,
237            RegionKind::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
238            RegionKind::RePlaceholder(..) | RegionKind::ReBound(..) => {
239                // We only expect region names that the user can type.
240                panic!("unexpected region in query response: `{r:?}`")
241            }
242        }
243    }
244
245    fn any(&self) -> bool {
246        false
247    }
248
249    fn preserve_universes(&self) -> bool {
250        false
251    }
252}
253
254struct CanonicalizeAllFreeRegions;
255
256impl CanonicalizeMode for CanonicalizeAllFreeRegions {
257    fn canonicalize_free_region<'db>(
258        &self,
259        canonicalizer: &mut Canonicalizer<'_, 'db>,
260        r: Region<'db>,
261    ) -> Region<'db> {
262        canonicalizer.canonical_var_for_region_in_root_universe(r)
263    }
264
265    fn any(&self) -> bool {
266        true
267    }
268
269    fn preserve_universes(&self) -> bool {
270        false
271    }
272}
273
274struct Canonicalizer<'cx, 'db> {
275    /// Set to `None` to disable the resolution of inference variables.
276    infcx: &'cx InferCtxt<'db>,
277    tcx: DbInterner<'db>,
278    variables: SmallVec<[CanonicalVarKind<'db>; 8]>,
279    query_state: &'cx mut OriginalQueryValues<'db>,
280    // Note that indices is only used once `var_values` is big enough to be
281    // heap-allocated.
282    indices: FxHashMap<GenericArg<'db>, BoundVar>,
283    /// Maps each `sub_unification_table_root_var` to the index of the first
284    /// variable which used it.
285    ///
286    /// This means in case two type variables have the same sub relations root,
287    /// we set the `sub_root` of the second variable to the position of the first.
288    /// Otherwise the `sub_root` of each type variable is just its own position.
289    sub_root_lookup_table: FxHashMap<TyVid, usize>,
290    canonicalize_mode: &'cx dyn CanonicalizeMode,
291    needs_canonical_flags: TypeFlags,
292
293    binder_index: DebruijnIndex,
294}
295
296impl<'cx, 'db> TypeFolder<DbInterner<'db>> for Canonicalizer<'cx, 'db> {
297    fn cx(&self) -> DbInterner<'db> {
298        self.tcx
299    }
300
301    fn fold_binder<T>(&mut self, t: Binder<'db, T>) -> Binder<'db, T>
302    where
303        T: TypeFoldable<DbInterner<'db>>,
304    {
305        self.binder_index.shift_in(1);
306        let t = t.super_fold_with(self);
307        self.binder_index.shift_out(1);
308        t
309    }
310
311    fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
312        match r.kind() {
313            RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => r,
314            RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => {
315                panic!("canonicalized bound var found during canonicalization");
316            }
317
318            RegionKind::ReStatic
319            | RegionKind::ReEarlyParam(..)
320            | RegionKind::ReError(_)
321            | RegionKind::ReLateParam(_)
322            | RegionKind::RePlaceholder(..)
323            | RegionKind::ReVar(_)
324            | RegionKind::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
325        }
326    }
327
328    fn fold_ty(&mut self, mut t: Ty<'db>) -> Ty<'db> {
329        match t.kind() {
330            TyKind::Infer(TyVar(mut vid)) => {
331                // We need to canonicalize the *root* of our ty var.
332                // This is so that our canonical response correctly reflects
333                // any equated inference vars correctly!
334                let root_vid = self.infcx.root_var(vid);
335                if root_vid != vid {
336                    t = Ty::new_var(self.tcx, root_vid);
337                    vid = root_vid;
338                }
339
340                debug!("canonical: type var found with vid {:?}", vid);
341                match self.infcx.probe_ty_var(vid) {
342                    // `t` could be a float / int variable; canonicalize that instead.
343                    Ok(t) => {
344                        debug!("(resolved to {:?})", t);
345                        self.fold_ty(t)
346                    }
347
348                    // `TyVar(vid)` is unresolved, track its universe index in the canonicalized
349                    // result.
350                    Err(mut ui) => {
351                        if !self.canonicalize_mode.preserve_universes() {
352                            // FIXME: perf problem described in #55921.
353                            ui = UniverseIndex::ROOT;
354                        }
355
356                        let sub_root = self.get_or_insert_sub_root(vid);
357                        self.canonicalize_ty_var(CanonicalVarKind::Ty { ui, sub_root }, t)
358                    }
359                }
360            }
361
362            TyKind::Infer(IntVar(vid)) => {
363                let nt = self.infcx.opportunistic_resolve_int_var(vid);
364                if nt != t {
365                    self.fold_ty(nt)
366                } else {
367                    self.canonicalize_ty_var(CanonicalVarKind::Int, t)
368                }
369            }
370            TyKind::Infer(FloatVar(vid)) => {
371                let nt = self.infcx.opportunistic_resolve_float_var(vid);
372                if nt != t {
373                    self.fold_ty(nt)
374                } else {
375                    self.canonicalize_ty_var(CanonicalVarKind::Float, t)
376                }
377            }
378
379            TyKind::Infer(
380                InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_),
381            ) => {
382                panic!("encountered a fresh type during canonicalization")
383            }
384
385            TyKind::Placeholder(mut placeholder) => {
386                if !self.canonicalize_mode.preserve_universes() {
387                    placeholder.universe = UniverseIndex::ROOT;
388                }
389                self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t)
390            }
391
392            TyKind::Bound(BoundVarIndexKind::Bound(..), _) => t,
393            TyKind::Bound(BoundVarIndexKind::Canonical, ..) => {
394                panic!("canonicalized bound var found during canonicalization");
395            }
396
397            TyKind::Closure(..)
398            | TyKind::CoroutineClosure(..)
399            | TyKind::Coroutine(..)
400            | TyKind::CoroutineWitness(..)
401            | TyKind::Bool
402            | TyKind::Char
403            | TyKind::Int(..)
404            | TyKind::Uint(..)
405            | TyKind::Float(..)
406            | TyKind::Adt(..)
407            | TyKind::Str
408            | TyKind::Error(_)
409            | TyKind::Array(..)
410            | TyKind::Slice(..)
411            | TyKind::RawPtr(..)
412            | TyKind::Ref(..)
413            | TyKind::FnDef(..)
414            | TyKind::FnPtr(..)
415            | TyKind::Dynamic(..)
416            | TyKind::UnsafeBinder(_)
417            | TyKind::Never
418            | TyKind::Tuple(..)
419            | TyKind::Alias(..)
420            | TyKind::Foreign(..)
421            | TyKind::Pat(..)
422            | TyKind::Param(..) => {
423                if t.flags().intersects(self.needs_canonical_flags) {
424                    t.super_fold_with(self)
425                } else {
426                    t
427                }
428            }
429        }
430    }
431
432    fn fold_const(&mut self, mut ct: Const<'db>) -> Const<'db> {
433        match ct.kind() {
434            ConstKind::Infer(InferConst::Var(mut vid)) => {
435                // We need to canonicalize the *root* of our const var.
436                // This is so that our canonical response correctly reflects
437                // any equated inference vars correctly!
438                let root_vid = self.infcx.root_const_var(vid);
439                if root_vid != vid {
440                    ct = Const::new_var(self.tcx, root_vid);
441                    vid = root_vid;
442                }
443
444                debug!("canonical: const var found with vid {:?}", vid);
445                match self.infcx.probe_const_var(vid) {
446                    Ok(c) => {
447                        debug!("(resolved to {:?})", c);
448                        return self.fold_const(c);
449                    }
450
451                    // `ConstVar(vid)` is unresolved, track its universe index in the
452                    // canonicalized result
453                    Err(mut ui) => {
454                        if !self.canonicalize_mode.preserve_universes() {
455                            // FIXME: perf problem described in #55921.
456                            ui = UniverseIndex::ROOT;
457                        }
458                        return self.canonicalize_const_var(CanonicalVarKind::Const(ui), ct);
459                    }
460                }
461            }
462            ConstKind::Infer(InferConst::Fresh(_)) => {
463                panic!("encountered a fresh const during canonicalization")
464            }
465            ConstKind::Bound(BoundVarIndexKind::Bound(..), _) => {
466                return ct;
467            }
468            ConstKind::Bound(BoundVarIndexKind::Canonical, ..) => {
469                panic!("canonicalized bound var found during canonicalization");
470            }
471            ConstKind::Placeholder(placeholder) => {
472                return self
473                    .canonicalize_const_var(CanonicalVarKind::PlaceholderConst(placeholder), ct);
474            }
475            _ => {}
476        }
477
478        if ct.flags().intersects(self.needs_canonical_flags) {
479            ct.super_fold_with(self)
480        } else {
481            ct
482        }
483    }
484}
485
486impl<'cx, 'db> Canonicalizer<'cx, 'db> {
487    /// The main `canonicalize` method, shared impl of
488    /// `canonicalize_query` and `canonicalize_response`.
489    fn canonicalize<V>(
490        value: V,
491        infcx: &InferCtxt<'db>,
492        tcx: DbInterner<'db>,
493        canonicalize_region_mode: &dyn CanonicalizeMode,
494        query_state: &mut OriginalQueryValues<'db>,
495    ) -> Canonical<'db, V>
496    where
497        V: TypeFoldable<DbInterner<'db>>,
498    {
499        let base = Canonical {
500            max_universe: UniverseIndex::ROOT,
501            variables: CanonicalVars::new_from_iter(tcx, []),
502            value: (),
503        };
504        Canonicalizer::canonicalize_with_base(
505            base,
506            value,
507            infcx,
508            tcx,
509            canonicalize_region_mode,
510            query_state,
511        )
512        .unchecked_map(|((), val)| val)
513    }
514
515    fn canonicalize_with_base<U, V>(
516        base: Canonical<'db, U>,
517        value: V,
518        infcx: &InferCtxt<'db>,
519        tcx: DbInterner<'db>,
520        canonicalize_region_mode: &dyn CanonicalizeMode,
521        query_state: &mut OriginalQueryValues<'db>,
522    ) -> Canonical<'db, (U, V)>
523    where
524        V: TypeFoldable<DbInterner<'db>>,
525    {
526        let needs_canonical_flags = if canonicalize_region_mode.any() {
527            TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS
528        } else {
529            TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER
530        };
531
532        // Fast path: nothing that needs to be canonicalized.
533        if !value.has_type_flags(needs_canonical_flags) {
534            return base.unchecked_map(|b| (b, value));
535        }
536
537        let mut canonicalizer = Canonicalizer {
538            infcx,
539            tcx,
540            canonicalize_mode: canonicalize_region_mode,
541            needs_canonical_flags,
542            variables: SmallVec::from_slice(base.variables.as_slice()),
543            query_state,
544            indices: FxHashMap::default(),
545            sub_root_lookup_table: Default::default(),
546            binder_index: DebruijnIndex::ZERO,
547        };
548        if canonicalizer.query_state.var_values.spilled() {
549            canonicalizer.indices = canonicalizer
550                .query_state
551                .var_values
552                .iter()
553                .enumerate()
554                .map(|(i, &kind)| (kind, BoundVar::from(i)))
555                .collect();
556        }
557        let out_value = value.fold_with(&mut canonicalizer);
558
559        // Once we have canonicalized `out_value`, it should not
560        // contain anything that ties it to this inference context
561        // anymore.
562        debug_assert!(!out_value.has_infer() && !out_value.has_placeholders());
563
564        let canonical_variables =
565            CanonicalVars::new_from_iter(tcx, canonicalizer.universe_canonicalized_variables());
566
567        let max_universe = canonical_variables
568            .iter()
569            .map(|cvar| cvar.universe())
570            .max()
571            .unwrap_or(UniverseIndex::ROOT);
572
573        Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) }
574    }
575
576    /// Creates a canonical variable replacing `kind` from the input,
577    /// or returns an existing variable if `kind` has already been
578    /// seen. `kind` is expected to be an unbound variable (or
579    /// potentially a free region).
580    fn canonical_var(&mut self, info: CanonicalVarKind<'db>, kind: GenericArg<'db>) -> BoundVar {
581        let Canonicalizer { variables, query_state, indices, .. } = self;
582
583        let var_values = &mut query_state.var_values;
584
585        let universe = info.universe();
586        if universe != UniverseIndex::ROOT {
587            assert!(self.canonicalize_mode.preserve_universes());
588
589            // Insert universe into the universe map. To preserve the order of the
590            // universes in the value being canonicalized, we don't update the
591            // universe in `info` until we have finished canonicalizing.
592            match query_state.universe_map.binary_search(&universe) {
593                Err(idx) => query_state.universe_map.insert(idx, universe),
594                Ok(_) => {}
595            }
596        }
597
598        // This code is hot. `variables` and `var_values` are usually small
599        // (fewer than 8 elements ~95% of the time). They are SmallVec's to
600        // avoid allocations in those cases. We also don't use `indices` to
601        // determine if a kind has been seen before until the limit of 8 has
602        // been exceeded, to also avoid allocations for `indices`.
603        if !var_values.spilled() {
604            // `var_values` is stack-allocated. `indices` isn't used yet. Do a
605            // direct linear search of `var_values`.
606            if let Some(idx) = var_values.iter().position(|&k| k == kind) {
607                // `kind` is already present in `var_values`.
608                BoundVar::new(idx)
609            } else {
610                // `kind` isn't present in `var_values`. Append it. Likewise
611                // for `info` and `variables`.
612                variables.push(info);
613                var_values.push(kind);
614                assert_eq!(variables.len(), var_values.len());
615
616                // If `var_values` has become big enough to be heap-allocated,
617                // fill up `indices` to facilitate subsequent lookups.
618                if var_values.spilled() {
619                    assert!(indices.is_empty());
620                    *indices = var_values
621                        .iter()
622                        .enumerate()
623                        .map(|(i, &kind)| (kind, BoundVar::new(i)))
624                        .collect();
625                }
626                // The cv is the index of the appended element.
627                BoundVar::new(var_values.len() - 1)
628            }
629        } else {
630            // `var_values` is large. Do a hashmap search via `indices`.
631            *indices.entry(kind).or_insert_with(|| {
632                variables.push(info);
633                var_values.push(kind);
634                assert_eq!(variables.len(), var_values.len());
635                BoundVar::new(variables.len() - 1)
636            })
637        }
638    }
639
640    fn get_or_insert_sub_root(&mut self, vid: TyVid) -> BoundVar {
641        let root_vid = self.infcx.sub_unification_table_root_var(vid);
642        let idx =
643            *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
644        BoundVar::from(idx)
645    }
646
647    /// Replaces the universe indexes used in `var_values` with their index in
648    /// `query_state.universe_map`. This minimizes the maximum universe used in
649    /// the canonicalized value.
650    fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarKind<'db>; 8]> {
651        if self.query_state.universe_map.len() == 1 {
652            return self.variables;
653        }
654
655        let reverse_universe_map: FxHashMap<UniverseIndex, UniverseIndex> = self
656            .query_state
657            .universe_map
658            .iter()
659            .enumerate()
660            .map(|(idx, universe)| (*universe, UniverseIndex::from_usize(idx)))
661            .collect();
662
663        self.variables
664            .iter()
665            .map(|v| match *v {
666                CanonicalVarKind::Int | CanonicalVarKind::Float => *v,
667                CanonicalVarKind::Ty { ui, sub_root } => {
668                    CanonicalVarKind::Ty { ui: reverse_universe_map[&ui], sub_root }
669                }
670                CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
671                CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
672                CanonicalVarKind::PlaceholderTy(placeholder) => {
673                    CanonicalVarKind::PlaceholderTy(Placeholder {
674                        universe: reverse_universe_map[&placeholder.universe],
675                        ..placeholder
676                    })
677                }
678                CanonicalVarKind::PlaceholderRegion(placeholder) => {
679                    CanonicalVarKind::PlaceholderRegion(Placeholder {
680                        universe: reverse_universe_map[&placeholder.universe],
681                        ..placeholder
682                    })
683                }
684                CanonicalVarKind::PlaceholderConst(placeholder) => {
685                    CanonicalVarKind::PlaceholderConst(Placeholder {
686                        universe: reverse_universe_map[&placeholder.universe],
687                        ..placeholder
688                    })
689                }
690            })
691            .collect()
692    }
693
694    /// Shorthand helper that creates a canonical region variable for
695    /// `r` (always in the root universe). The reason that we always
696    /// put these variables into the root universe is because this
697    /// method is used during **query construction:** in that case, we
698    /// are taking all the regions and just putting them into the most
699    /// generic context we can. This may generate solutions that don't
700    /// fit (e.g., that equate some region variable with a placeholder
701    /// it can't name) on the caller side, but that's ok, the caller
702    /// can figure that out. In the meantime, it maximizes our
703    /// caching.
704    ///
705    /// (This works because unification never fails -- and hence trait
706    /// selection is never affected -- due to a universe mismatch.)
707    fn canonical_var_for_region_in_root_universe(&mut self, r: Region<'db>) -> Region<'db> {
708        self.canonical_var_for_region(CanonicalVarKind::Region(UniverseIndex::ROOT), r)
709    }
710
711    /// Creates a canonical variable (with the given `info`)
712    /// representing the region `r`; return a region referencing it.
713    fn canonical_var_for_region(
714        &mut self,
715        info: CanonicalVarKind<'db>,
716        r: Region<'db>,
717    ) -> Region<'db> {
718        let var = self.canonical_var(info, r.into());
719        Region::new_canonical_bound(self.cx(), var)
720    }
721
722    /// Given a type variable `ty_var` of the given kind, first check
723    /// if `ty_var` is bound to anything; if so, canonicalize
724    /// *that*. Otherwise, create a new canonical variable for
725    /// `ty_var`.
726    fn canonicalize_ty_var(&mut self, info: CanonicalVarKind<'db>, ty_var: Ty<'db>) -> Ty<'db> {
727        debug_assert_eq!(ty_var, self.infcx.shallow_resolve(ty_var));
728        let var = self.canonical_var(info, ty_var.into());
729        Ty::new_canonical_bound(self.cx(), var)
730    }
731
732    /// Given a type variable `const_var` of the given kind, first check
733    /// if `const_var` is bound to anything; if so, canonicalize
734    /// *that*. Otherwise, create a new canonical variable for
735    /// `const_var`.
736    fn canonicalize_const_var(
737        &mut self,
738        info: CanonicalVarKind<'db>,
739        const_var: Const<'db>,
740    ) -> Const<'db> {
741        debug_assert_eq!(const_var, self.infcx.shallow_resolve_const(const_var));
742        let var = self.canonical_var(info, const_var.into());
743        Const::new_canonical_bound(self.cx(), var)
744    }
745}