@@ -49,6 +49,31 @@ 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+ ///
57+ /// This is used for Chalk integration.
58+ pub fn canonicalize_query_preserving_universes < V > (
59+ & self ,
60+ value : V ,
61+ query_state : & mut OriginalQueryValues < ' tcx > ,
62+ ) -> Canonicalized < ' tcx , V >
63+ where
64+ V : TypeFoldable < ' tcx > ,
65+ {
66+ self . tcx . sess . perf_stats . queries_canonicalized . fetch_add ( 1 , Ordering :: Relaxed ) ;
67+
68+ Canonicalizer :: canonicalize (
69+ value,
70+ self ,
71+ self . tcx ,
72+ & CanonicalizeAllFreeRegionsPreservingUniverses ,
73+ query_state,
74+ )
75+ }
76+
5277 /// Canonicalizes a query *response* `V`. When we canonicalize a
5378 /// query response, we only canonicalize unbound inference
5479 /// variables, and we leave other free regions alone. So,
@@ -133,19 +158,22 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
133158/// maximally general query. But if we are canonicalizing a *query
134159/// response*, then we don't typically replace free regions, as they
135160/// must have been introduced from other parts of the system.
136- trait CanonicalizeRegionMode {
161+ trait CanonicalizeMode {
137162 fn canonicalize_free_region < ' tcx > (
138163 & self ,
139164 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
140165 r : ty:: Region < ' tcx > ,
141166 ) -> ty:: Region < ' tcx > ;
142167
143168 fn any ( & self ) -> bool ;
169+
170+ // Do we preserve universe of variables.
171+ fn preserve_universes ( & self ) -> bool ;
144172}
145173
146174struct CanonicalizeQueryResponse ;
147175
148- impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
176+ impl CanonicalizeMode for CanonicalizeQueryResponse {
149177 fn canonicalize_free_region < ' tcx > (
150178 & self ,
151179 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -198,11 +226,15 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
198226 fn any ( & self ) -> bool {
199227 false
200228 }
229+
230+ fn preserve_universes ( & self ) -> bool {
231+ true
232+ }
201233}
202234
203235struct CanonicalizeUserTypeAnnotation ;
204236
205- impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
237+ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
206238 fn canonicalize_free_region < ' tcx > (
207239 & self ,
208240 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -221,11 +253,15 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
221253 fn any ( & self ) -> bool {
222254 false
223255 }
256+
257+ fn preserve_universes ( & self ) -> bool {
258+ false
259+ }
224260}
225261
226262struct CanonicalizeAllFreeRegions ;
227263
228- impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
264+ impl CanonicalizeMode for CanonicalizeAllFreeRegions {
229265 fn canonicalize_free_region < ' tcx > (
230266 & self ,
231267 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -237,11 +273,39 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
237273 fn any ( & self ) -> bool {
238274 true
239275 }
276+
277+ fn preserve_universes ( & self ) -> bool {
278+ false
279+ }
280+ }
281+
282+ struct CanonicalizeAllFreeRegionsPreservingUniverses ;
283+
284+ impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
285+ fn canonicalize_free_region < ' tcx > (
286+ & self ,
287+ canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
288+ r : ty:: Region < ' tcx > ,
289+ ) -> ty:: Region < ' tcx > {
290+ let universe = canonicalizer. infcx . universe_of_region ( r) ;
291+ canonicalizer. canonical_var_for_region (
292+ CanonicalVarInfo { kind : CanonicalVarKind :: Region ( universe) } ,
293+ r,
294+ )
295+ }
296+
297+ fn any ( & self ) -> bool {
298+ true
299+ }
300+
301+ fn preserve_universes ( & self ) -> bool {
302+ true
303+ }
240304}
241305
242306struct CanonicalizeFreeRegionsOtherThanStatic ;
243307
244- impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
308+ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
245309 fn canonicalize_free_region < ' tcx > (
246310 & self ,
247311 canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -257,6 +321,10 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
257321 fn any ( & self ) -> bool {
258322 true
259323 }
324+
325+ fn preserve_universes ( & self ) -> bool {
326+ false
327+ }
260328}
261329
262330struct Canonicalizer < ' cx , ' tcx > {
@@ -267,7 +335,7 @@ struct Canonicalizer<'cx, 'tcx> {
267335 // Note that indices is only used once `var_values` is big enough to be
268336 // heap-allocated.
269337 indices : FxHashMap < GenericArg < ' tcx > , BoundVar > ,
270- canonicalize_region_mode : & ' cx dyn CanonicalizeRegionMode ,
338+ canonicalize_mode : & ' cx dyn CanonicalizeMode ,
271339 needs_canonical_flags : TypeFlags ,
272340
273341 binder_index : ty:: DebruijnIndex ,
@@ -311,15 +379,15 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
311379 vid, r
312380 ) ;
313381 let r = self . tcx . reuse_or_mk_region ( r, ty:: ReVar ( resolved_vid) ) ;
314- self . canonicalize_region_mode . canonicalize_free_region ( self , r)
382+ self . canonicalize_mode . canonicalize_free_region ( self , r)
315383 }
316384
317385 ty:: ReStatic
318386 | ty:: ReEarlyBound ( ..)
319387 | ty:: ReFree ( _)
320388 | ty:: ReEmpty ( _)
321389 | ty:: RePlaceholder ( ..)
322- | ty:: ReErased => self . canonicalize_region_mode . canonicalize_free_region ( self , r) ,
390+ | ty:: ReErased => self . canonicalize_mode . canonicalize_free_region ( self , r) ,
323391 }
324392 }
325393
@@ -337,8 +405,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
337405 // `TyVar(vid)` is unresolved, track its universe index in the canonicalized
338406 // result.
339407 Err ( mut ui) => {
340- // FIXME: perf problem described in #55921.
341- ui = ty:: UniverseIndex :: ROOT ;
408+ if !self . canonicalize_mode . preserve_universes ( ) {
409+ // FIXME: perf problem described in #55921.
410+ ui = ty:: UniverseIndex :: ROOT ;
411+ }
342412 self . canonicalize_ty_var (
343413 CanonicalVarInfo {
344414 kind : CanonicalVarKind :: Ty ( CanonicalTyVarKind :: General ( ui) ) ,
@@ -422,8 +492,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
422492 // `ConstVar(vid)` is unresolved, track its universe index in the
423493 // canonicalized result
424494 Err ( mut ui) => {
425- // FIXME: perf problem described in #55921.
426- ui = ty:: UniverseIndex :: ROOT ;
495+ if !self . canonicalize_mode . preserve_universes ( ) {
496+ // FIXME: perf problem described in #55921.
497+ ui = ty:: UniverseIndex :: ROOT ;
498+ }
427499 return self . canonicalize_const_var (
428500 CanonicalVarInfo { kind : CanonicalVarKind :: Const ( ui, ct. ty ) } ,
429501 ct,
@@ -462,7 +534,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
462534 value : V ,
463535 infcx : & InferCtxt < ' _ , ' tcx > ,
464536 tcx : TyCtxt < ' tcx > ,
465- canonicalize_region_mode : & dyn CanonicalizeRegionMode ,
537+ canonicalize_region_mode : & dyn CanonicalizeMode ,
466538 query_state : & mut OriginalQueryValues < ' tcx > ,
467539 ) -> Canonicalized < ' tcx , V >
468540 where
@@ -493,7 +565,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
493565 let mut canonicalizer = Canonicalizer {
494566 infcx,
495567 tcx,
496- canonicalize_region_mode,
568+ canonicalize_mode : canonicalize_region_mode,
497569 needs_canonical_flags,
498570 variables : SmallVec :: new ( ) ,
499571 query_state,
@@ -504,10 +576,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
504576
505577 // Once we have canonicalized `out_value`, it should not
506578 // 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( ) ) ;
579+ // anymore.
580+ debug_assert ! ( !out_value. needs_infer( ) && !out_value . has_placeholders ( ) ) ;
509581
510- let canonical_variables = tcx. intern_canonical_var_infos ( & canonicalizer. variables ) ;
582+ let canonical_variables =
583+ tcx. intern_canonical_var_infos ( & canonicalizer. universe_canonicalized_variables ( ) ) ;
511584
512585 let max_universe = canonical_variables
513586 . iter ( )
@@ -527,6 +600,19 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
527600
528601 let var_values = & mut query_state. var_values ;
529602
603+ let universe = info. universe ( ) ;
604+ if universe != ty:: UniverseIndex :: ROOT {
605+ assert ! ( self . canonicalize_mode. preserve_universes( ) ) ;
606+
607+ // Insert universe into the universe map. To preserve the order of the
608+ // universes in the value being canonicalized, we don't update the
609+ // universe in `info` until we have finished canonicalizing.
610+ match query_state. universe_map . binary_search ( & universe) {
611+ Err ( idx) => query_state. universe_map . insert ( idx, universe) ,
612+ Ok ( _) => { }
613+ }
614+ }
615+
530616 // This code is hot. `variables` and `var_values` are usually small
531617 // (fewer than 8 elements ~95% of the time). They are SmallVec's to
532618 // avoid allocations in those cases. We also don't use `indices` to
@@ -569,6 +655,61 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
569655 }
570656 }
571657
658+ /// Replaces the universe indexes used in `var_values` with their index in
659+ /// `query_state.universe_map`. This minimizes the maximum universe used in
660+ /// the canonicalized value.
661+ fn universe_canonicalized_variables ( self ) -> SmallVec < [ CanonicalVarInfo < ' tcx > ; 8 ] > {
662+ if self . query_state . universe_map . len ( ) == 1 {
663+ return self . variables ;
664+ }
665+
666+ let reverse_universe_map: FxHashMap < ty:: UniverseIndex , ty:: UniverseIndex > = self
667+ . query_state
668+ . universe_map
669+ . iter ( )
670+ . enumerate ( )
671+ . map ( |( idx, universe) | ( * universe, ty:: UniverseIndex :: from_usize ( idx) ) )
672+ . collect ( ) ;
673+
674+ self . variables
675+ . iter ( )
676+ . map ( |v| CanonicalVarInfo {
677+ kind : match v. kind {
678+ CanonicalVarKind :: Ty ( CanonicalTyVarKind :: Int | CanonicalTyVarKind :: Float ) => {
679+ return * v;
680+ }
681+ CanonicalVarKind :: Ty ( CanonicalTyVarKind :: General ( u) ) => {
682+ CanonicalVarKind :: Ty ( CanonicalTyVarKind :: General ( reverse_universe_map[ & u] ) )
683+ }
684+ CanonicalVarKind :: Region ( u) => {
685+ CanonicalVarKind :: Region ( reverse_universe_map[ & u] )
686+ }
687+ CanonicalVarKind :: Const ( u, t) => {
688+ CanonicalVarKind :: Const ( reverse_universe_map[ & u] , t)
689+ }
690+ CanonicalVarKind :: PlaceholderTy ( placeholder) => {
691+ CanonicalVarKind :: PlaceholderTy ( ty:: Placeholder {
692+ universe : reverse_universe_map[ & placeholder. universe ] ,
693+ ..placeholder
694+ } )
695+ }
696+ CanonicalVarKind :: PlaceholderRegion ( placeholder) => {
697+ CanonicalVarKind :: PlaceholderRegion ( ty:: Placeholder {
698+ universe : reverse_universe_map[ & placeholder. universe ] ,
699+ ..placeholder
700+ } )
701+ }
702+ CanonicalVarKind :: PlaceholderConst ( placeholder) => {
703+ CanonicalVarKind :: PlaceholderConst ( ty:: Placeholder {
704+ universe : reverse_universe_map[ & placeholder. universe ] ,
705+ ..placeholder
706+ } )
707+ }
708+ } ,
709+ } )
710+ . collect ( )
711+ }
712+
572713 /// Shorthand helper that creates a canonical region variable for
573714 /// `r` (always in the root universe). The reason that we always
574715 /// put these variables into the root universe is because this
0 commit comments