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