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