@@ -49,6 +49,29 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
4949 Canonicalizer :: canonicalize ( value, self , self . tcx , & CanonicalizeAllFreeRegions , query_state)
5050 }
5151
52+ /// Like [Self::canonicalize_query], but preserves distinct universes. For
53+ /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
54+ /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
55+ /// in `U2`.
56+ pub fn canonicalize_chalk_query < V > (
57+ & self ,
58+ value : V ,
59+ query_state : & mut OriginalQueryValues < ' tcx > ,
60+ ) -> Canonicalized < ' tcx , V >
61+ where
62+ V : TypeFoldable < ' tcx > ,
63+ {
64+ self . tcx . sess . perf_stats . queries_canonicalized . fetch_add ( 1 , Ordering :: Relaxed ) ;
65+
66+ Canonicalizer :: canonicalize (
67+ value,
68+ self ,
69+ self . tcx ,
70+ & CanonicalizeAllFreeRegionsPreservingUniverses ,
71+ query_state,
72+ )
73+ }
74+
5275 /// Canonicalizes a query *response* `V`. When we canonicalize a
5376 /// query response, we only canonicalize unbound inference
5477 /// variables, and we leave other free regions alone. So,
@@ -133,19 +156,22 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
133156/// maximally general query. But if we are canonicalizing a *query
134157/// response*, then we don't typically replace free regions, as they
135158/// must have been introduced from other parts of the system.
136- trait CanonicalizeRegionMode {
159+ trait CanonicalizeMode {
137160 fn canonicalize_free_region < ' tcx > (
138161 & self ,
139162 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
140163 r : ty:: Region < ' tcx > ,
141164 ) -> ty:: Region < ' tcx > ;
142165
143166 fn any ( & self ) -> bool ;
167+
168+ // Do we preserve universe of variables.
169+ fn preserve_universes ( & self ) -> bool ;
144170}
145171
146172struct CanonicalizeQueryResponse ;
147173
148- impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
174+ impl CanonicalizeMode for CanonicalizeQueryResponse {
149175 fn canonicalize_free_region < ' tcx > (
150176 & self ,
151177 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -198,11 +224,15 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
198224 fn any ( & self ) -> bool {
199225 false
200226 }
227+
228+ fn preserve_universes ( & self ) -> bool {
229+ true
230+ }
201231}
202232
203233struct CanonicalizeUserTypeAnnotation ;
204234
205- impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
235+ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
206236 fn canonicalize_free_region < ' tcx > (
207237 & self ,
208238 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -221,11 +251,15 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
221251 fn any ( & self ) -> bool {
222252 false
223253 }
254+
255+ fn preserve_universes ( & self ) -> bool {
256+ false
257+ }
224258}
225259
226260struct CanonicalizeAllFreeRegions ;
227261
228- impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
262+ impl CanonicalizeMode for CanonicalizeAllFreeRegions {
229263 fn canonicalize_free_region < ' tcx > (
230264 & self ,
231265 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -237,11 +271,39 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
237271 fn any ( & self ) -> bool {
238272 true
239273 }
274+
275+ fn preserve_universes ( & self ) -> bool {
276+ false
277+ }
278+ }
279+
280+ struct CanonicalizeAllFreeRegionsPreservingUniverses ;
281+
282+ impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
283+ fn canonicalize_free_region < ' tcx > (
284+ & self ,
285+ canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
286+ r : ty:: Region < ' tcx > ,
287+ ) -> ty:: Region < ' tcx > {
288+ let universe = canonicalizer. infcx . universe_of_region ( r) ;
289+ canonicalizer. canonical_var_for_region (
290+ CanonicalVarInfo { kind : CanonicalVarKind :: Region ( universe) } ,
291+ r,
292+ )
293+ }
294+
295+ fn any ( & self ) -> bool {
296+ true
297+ }
298+
299+ fn preserve_universes ( & self ) -> bool {
300+ true
301+ }
240302}
241303
242304struct CanonicalizeFreeRegionsOtherThanStatic ;
243305
244- impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
306+ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
245307 fn canonicalize_free_region < ' tcx > (
246308 & self ,
247309 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -257,6 +319,10 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
257319 fn any ( & self ) -> bool {
258320 true
259321 }
322+
323+ fn preserve_universes ( & self ) -> bool {
324+ false
325+ }
260326}
261327
262328struct Canonicalizer < ' cx , ' tcx > {
@@ -267,7 +333,7 @@ struct Canonicalizer<'cx, 'tcx> {
267333 // Note that indices is only used once `var_values` is big enough to be
268334 // heap-allocated.
269335 indices : FxHashMap < GenericArg < ' tcx > , BoundVar > ,
270- canonicalize_region_mode : & ' cx dyn CanonicalizeRegionMode ,
336+ canonicalize_mode : & ' cx dyn CanonicalizeMode ,
271337 needs_canonical_flags : TypeFlags ,
272338
273339 binder_index : ty:: DebruijnIndex ,
@@ -311,15 +377,15 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
311377 vid, r
312378 ) ;
313379 let r = self . tcx . reuse_or_mk_region ( r, ty:: ReVar ( resolved_vid) ) ;
314- self . canonicalize_region_mode . canonicalize_free_region ( self , r)
380+ self . canonicalize_mode . canonicalize_free_region ( self , r)
315381 }
316382
317383 ty:: ReStatic
318384 | ty:: ReEarlyBound ( ..)
319385 | ty:: ReFree ( _)
320386 | ty:: ReEmpty ( _)
321387 | ty:: RePlaceholder ( ..)
322- | ty:: ReErased => self . canonicalize_region_mode . canonicalize_free_region ( self , r) ,
388+ | ty:: ReErased => self . canonicalize_mode . canonicalize_free_region ( self , r) ,
323389 }
324390 }
325391
@@ -337,8 +403,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
337403 // `TyVar(vid)` is unresolved, track its universe index in the canonicalized
338404 // result.
339405 Err ( mut ui) => {
340- // FIXME: perf problem described in #55921.
341- ui = ty:: UniverseIndex :: ROOT ;
406+ if !self . canonicalize_mode . preserve_universes ( ) {
407+ // FIXME: perf problem described in #55921.
408+ ui = ty:: UniverseIndex :: ROOT ;
409+ }
342410 self . canonicalize_ty_var (
343411 CanonicalVarInfo {
344412 kind : CanonicalVarKind :: Ty ( CanonicalTyVarKind :: General ( ui) ) ,
@@ -422,8 +490,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
422490 // `ConstVar(vid)` is unresolved, track its universe index in the
423491 // canonicalized result
424492 Err ( mut ui) => {
425- // FIXME: perf problem described in #55921.
426- ui = ty:: UniverseIndex :: ROOT ;
493+ if !self . canonicalize_mode . preserve_universes ( ) {
494+ // FIXME: perf problem described in #55921.
495+ ui = ty:: UniverseIndex :: ROOT ;
496+ }
427497 return self . canonicalize_const_var (
428498 CanonicalVarInfo { kind : CanonicalVarKind :: Const ( ui, ct. ty ) } ,
429499 ct,
@@ -462,7 +532,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
462532 value : V ,
463533 infcx : & InferCtxt < ' _ , ' tcx > ,
464534 tcx : TyCtxt < ' tcx > ,
465- canonicalize_region_mode : & dyn CanonicalizeRegionMode ,
535+ canonicalize_region_mode : & dyn CanonicalizeMode ,
466536 query_state : & mut OriginalQueryValues < ' tcx > ,
467537 ) -> Canonicalized < ' tcx , V >
468538 where
@@ -493,7 +563,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
493563 let mut canonicalizer = Canonicalizer {
494564 infcx,
495565 tcx,
496- canonicalize_region_mode,
566+ canonicalize_mode : canonicalize_region_mode,
497567 needs_canonical_flags,
498568 variables : SmallVec :: new ( ) ,
499569 query_state,
@@ -504,10 +574,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
504574
505575 // Once we have canonicalized `out_value`, it should not
506576 // contain anything that ties it to this inference context
507- // anymore, so it should live in the global arena .
508- debug_assert ! ( !out_value. needs_infer( ) ) ;
577+ // anymore.
578+ debug_assert ! ( !out_value. needs_infer( ) && !out_value . has_placeholders ( ) ) ;
509579
510- let canonical_variables = tcx. intern_canonical_var_infos ( & canonicalizer. variables ) ;
580+ let canonical_variables =
581+ tcx. intern_canonical_var_infos ( & canonicalizer. universe_canonicalized_variables ( ) ) ;
511582
512583 let max_universe = canonical_variables
513584 . iter ( )
@@ -527,6 +598,19 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
527598
528599 let var_values = & mut query_state. var_values ;
529600
601+ let universe = info. universe ( ) ;
602+ if universe != ty:: UniverseIndex :: ROOT {
603+ assert ! ( self . canonicalize_mode. preserve_universes( ) ) ;
604+
605+ // Insert universe into the universe map. To preserve the order of the
606+ // universes in the value being canonicalized, we don't update the
607+ // universe in `info` until we have finished canonicalizing.
608+ match query_state. universe_map . binary_search ( & universe) {
609+ Err ( idx) => query_state. universe_map . insert ( idx, universe) ,
610+ Ok ( _) => { }
611+ }
612+ }
613+
530614 // This code is hot. `variables` and `var_values` are usually small
531615 // (fewer than 8 elements ~95% of the time). They are SmallVec's to
532616 // avoid allocations in those cases. We also don't use `indices` to
@@ -569,6 +653,61 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
569653 }
570654 }
571655
656+ /// Replaces the universe indexes used in `var_values` with their index in
657+ /// `query_state.universe_map`. This minimizes the maximum universe used in
658+ /// the canonicalized value.
659+ fn universe_canonicalized_variables ( self ) -> SmallVec < [ CanonicalVarInfo < ' tcx > ; 8 ] > {
660+ if self . query_state . universe_map . len ( ) == 1 {
661+ return self . variables ;
662+ }
663+
664+ let reverse_universe_map: FxHashMap < ty:: UniverseIndex , ty:: UniverseIndex > = self
665+ . query_state
666+ . universe_map
667+ . iter ( )
668+ . enumerate ( )
669+ . map ( |( idx, universe) | ( * universe, ty:: UniverseIndex :: from_usize ( idx) ) )
670+ . collect ( ) ;
671+
672+ self . variables
673+ . iter ( )
674+ . map ( |v| CanonicalVarInfo {
675+ kind : match v. kind {
676+ CanonicalVarKind :: Ty ( CanonicalTyVarKind :: Int | CanonicalTyVarKind :: Float ) => {
677+ return * v;
678+ }
679+ CanonicalVarKind :: Ty ( CanonicalTyVarKind :: General ( u) ) => {
680+ CanonicalVarKind :: Ty ( CanonicalTyVarKind :: General ( reverse_universe_map[ & u] ) )
681+ }
682+ CanonicalVarKind :: Region ( u) => {
683+ CanonicalVarKind :: Region ( reverse_universe_map[ & u] )
684+ }
685+ CanonicalVarKind :: Const ( u, t) => {
686+ CanonicalVarKind :: Const ( reverse_universe_map[ & u] , t)
687+ }
688+ CanonicalVarKind :: PlaceholderTy ( placeholder) => {
689+ CanonicalVarKind :: PlaceholderTy ( ty:: Placeholder {
690+ universe : reverse_universe_map[ & placeholder. universe ] ,
691+ ..placeholder
692+ } )
693+ }
694+ CanonicalVarKind :: PlaceholderRegion ( placeholder) => {
695+ CanonicalVarKind :: PlaceholderRegion ( ty:: Placeholder {
696+ universe : reverse_universe_map[ & placeholder. universe ] ,
697+ ..placeholder
698+ } )
699+ }
700+ CanonicalVarKind :: PlaceholderConst ( placeholder) => {
701+ CanonicalVarKind :: PlaceholderConst ( ty:: Placeholder {
702+ universe : reverse_universe_map[ & placeholder. universe ] ,
703+ ..placeholder
704+ } )
705+ }
706+ } ,
707+ } )
708+ . collect ( )
709+ }
710+
572711 /// Shorthand helper that creates a canonical region variable for
573712 /// `r` (always in the root universe). The reason that we always
574713 /// put these variables into the root universe is because this
0 commit comments