@@ -49,6 +49,31 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
49
49
Canonicalizer :: canonicalize ( value, self , self . tcx , & CanonicalizeAllFreeRegions , query_state)
50
50
}
51
51
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
+
52
77
/// Canonicalizes a query *response* `V`. When we canonicalize a
53
78
/// query response, we only canonicalize unbound inference
54
79
/// variables, and we leave other free regions alone. So,
@@ -133,19 +158,22 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
133
158
/// maximally general query. But if we are canonicalizing a *query
134
159
/// response*, then we don't typically replace free regions, as they
135
160
/// must have been introduced from other parts of the system.
136
- trait CanonicalizeRegionMode {
161
+ trait CanonicalizeMode {
137
162
fn canonicalize_free_region < ' tcx > (
138
163
& self ,
139
164
canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
140
165
r : ty:: Region < ' tcx > ,
141
166
) -> ty:: Region < ' tcx > ;
142
167
143
168
fn any ( & self ) -> bool ;
169
+
170
+ // Do we preserve universe of variables.
171
+ fn preserve_universes ( & self ) -> bool ;
144
172
}
145
173
146
174
struct CanonicalizeQueryResponse ;
147
175
148
- impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
176
+ impl CanonicalizeMode for CanonicalizeQueryResponse {
149
177
fn canonicalize_free_region < ' tcx > (
150
178
& self ,
151
179
canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -198,11 +226,15 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
198
226
fn any ( & self ) -> bool {
199
227
false
200
228
}
229
+
230
+ fn preserve_universes ( & self ) -> bool {
231
+ true
232
+ }
201
233
}
202
234
203
235
struct CanonicalizeUserTypeAnnotation ;
204
236
205
- impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
237
+ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
206
238
fn canonicalize_free_region < ' tcx > (
207
239
& self ,
208
240
canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -221,11 +253,15 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
221
253
fn any ( & self ) -> bool {
222
254
false
223
255
}
256
+
257
+ fn preserve_universes ( & self ) -> bool {
258
+ false
259
+ }
224
260
}
225
261
226
262
struct CanonicalizeAllFreeRegions ;
227
263
228
- impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
264
+ impl CanonicalizeMode for CanonicalizeAllFreeRegions {
229
265
fn canonicalize_free_region < ' tcx > (
230
266
& self ,
231
267
canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -237,11 +273,39 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
237
273
fn any ( & self ) -> bool {
238
274
true
239
275
}
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
+ }
240
304
}
241
305
242
306
struct CanonicalizeFreeRegionsOtherThanStatic ;
243
307
244
- impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
308
+ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
245
309
fn canonicalize_free_region < ' tcx > (
246
310
& self ,
247
311
canonicalizer : & mut Canonicalizer < ' _ , ' tcx > ,
@@ -257,6 +321,10 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
257
321
fn any ( & self ) -> bool {
258
322
true
259
323
}
324
+
325
+ fn preserve_universes ( & self ) -> bool {
326
+ false
327
+ }
260
328
}
261
329
262
330
struct Canonicalizer < ' cx , ' tcx > {
@@ -267,7 +335,7 @@ struct Canonicalizer<'cx, 'tcx> {
267
335
// Note that indices is only used once `var_values` is big enough to be
268
336
// heap-allocated.
269
337
indices : FxHashMap < GenericArg < ' tcx > , BoundVar > ,
270
- canonicalize_region_mode : & ' cx dyn CanonicalizeRegionMode ,
338
+ canonicalize_mode : & ' cx dyn CanonicalizeMode ,
271
339
needs_canonical_flags : TypeFlags ,
272
340
273
341
binder_index : ty:: DebruijnIndex ,
@@ -311,15 +379,15 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
311
379
vid, r
312
380
) ;
313
381
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)
315
383
}
316
384
317
385
ty:: ReStatic
318
386
| ty:: ReEarlyBound ( ..)
319
387
| ty:: ReFree ( _)
320
388
| ty:: ReEmpty ( _)
321
389
| 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) ,
323
391
}
324
392
}
325
393
@@ -337,8 +405,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
337
405
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
338
406
// result.
339
407
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
+ }
342
412
self . canonicalize_ty_var (
343
413
CanonicalVarInfo {
344
414
kind : CanonicalVarKind :: Ty ( CanonicalTyVarKind :: General ( ui) ) ,
@@ -422,8 +492,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
422
492
// `ConstVar(vid)` is unresolved, track its universe index in the
423
493
// canonicalized result
424
494
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
+ }
427
499
return self . canonicalize_const_var (
428
500
CanonicalVarInfo { kind : CanonicalVarKind :: Const ( ui, ct. ty ) } ,
429
501
ct,
@@ -462,7 +534,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
462
534
value : V ,
463
535
infcx : & InferCtxt < ' _ , ' tcx > ,
464
536
tcx : TyCtxt < ' tcx > ,
465
- canonicalize_region_mode : & dyn CanonicalizeRegionMode ,
537
+ canonicalize_region_mode : & dyn CanonicalizeMode ,
466
538
query_state : & mut OriginalQueryValues < ' tcx > ,
467
539
) -> Canonicalized < ' tcx , V >
468
540
where
@@ -493,7 +565,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
493
565
let mut canonicalizer = Canonicalizer {
494
566
infcx,
495
567
tcx,
496
- canonicalize_region_mode,
568
+ canonicalize_mode : canonicalize_region_mode,
497
569
needs_canonical_flags,
498
570
variables : SmallVec :: new ( ) ,
499
571
query_state,
@@ -504,10 +576,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
504
576
505
577
// Once we have canonicalized `out_value`, it should not
506
578
// 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 ( ) ) ;
509
581
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 ( ) ) ;
511
584
512
585
let max_universe = canonical_variables
513
586
. iter ( )
@@ -527,6 +600,19 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
527
600
528
601
let var_values = & mut query_state. var_values ;
529
602
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
+
530
616
// This code is hot. `variables` and `var_values` are usually small
531
617
// (fewer than 8 elements ~95% of the time). They are SmallVec's to
532
618
// avoid allocations in those cases. We also don't use `indices` to
@@ -569,6 +655,61 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
569
655
}
570
656
}
571
657
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
+
572
713
/// Shorthand helper that creates a canonical region variable for
573
714
/// `r` (always in the root universe). The reason that we always
574
715
/// put these variables into the root universe is because this
0 commit comments