1
1
use std:: cmp:: Ordering ;
2
2
3
+ use rustc_data_structures:: fx:: FxHashMap ;
3
4
use rustc_type_ir:: fold:: { TypeFoldable , TypeFolder , TypeSuperFoldable } ;
4
5
use rustc_type_ir:: inherent:: * ;
5
6
use rustc_type_ir:: visit:: TypeVisitableExt ;
@@ -42,6 +43,8 @@ pub struct Canonicalizer<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
42
43
canonicalize_mode : CanonicalizeMode ,
43
44
44
45
variables : & ' a mut Vec < I :: GenericArg > ,
46
+ variable_lookup_table : FxHashMap < I :: GenericArg , usize > ,
47
+
45
48
primitive_var_infos : Vec < CanonicalVarInfo < I > > ,
46
49
binder_index : ty:: DebruijnIndex ,
47
50
}
@@ -58,6 +61,7 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc
58
61
canonicalize_mode,
59
62
60
63
variables,
64
+ variable_lookup_table : Default :: default ( ) ,
61
65
primitive_var_infos : Vec :: new ( ) ,
62
66
binder_index : ty:: INNERMOST ,
63
67
} ;
@@ -73,6 +77,37 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc
73
77
Canonical { defining_opaque_types, max_universe, variables, value }
74
78
}
75
79
80
+ fn get_or_insert_bound_var (
81
+ & mut self ,
82
+ arg : impl Into < I :: GenericArg > ,
83
+ canonical_var_info : CanonicalVarInfo < I > ,
84
+ ) -> ty:: BoundVar {
85
+ // FIXME: 16 is made up and arbitrary. We should look at some
86
+ // perf data here.
87
+ let arg = arg. into ( ) ;
88
+ let idx = if self . variables . len ( ) > 16 {
89
+ if self . variable_lookup_table . is_empty ( ) {
90
+ self . variable_lookup_table . extend ( self . variables . iter ( ) . copied ( ) . zip ( 0 ..) ) ;
91
+ }
92
+
93
+ * self . variable_lookup_table . entry ( arg) . or_insert_with ( || {
94
+ let var = self . variables . len ( ) ;
95
+ self . variables . push ( arg) ;
96
+ self . primitive_var_infos . push ( canonical_var_info) ;
97
+ var
98
+ } )
99
+ } else {
100
+ self . variables . iter ( ) . position ( |& v| v == arg) . unwrap_or_else ( || {
101
+ let var = self . variables . len ( ) ;
102
+ self . variables . push ( arg) ;
103
+ self . primitive_var_infos . push ( canonical_var_info) ;
104
+ var
105
+ } )
106
+ } ;
107
+
108
+ ty:: BoundVar :: from ( idx)
109
+ }
110
+
76
111
fn finalize ( self ) -> ( ty:: UniverseIndex , I :: CanonicalVars ) {
77
112
let mut var_infos = self . primitive_var_infos ;
78
113
// See the rustc-dev-guide section about how we deal with universes
@@ -122,8 +157,8 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc
122
157
// - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
123
158
// - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
124
159
//
125
- // This algorithm runs in `O(n² )` where `n` is the number of different universe
126
- // indices in the input . This should be fine as `n` is expected to be small.
160
+ // This algorithm runs in `O(mn )` where `n` is the number of different universes and
161
+ // `m` the number of variables . This should be fine as both are expected to be small.
127
162
let mut curr_compressed_uv = ty:: UniverseIndex :: ROOT ;
128
163
let mut existential_in_new_uv = None ;
129
164
let mut next_orig_uv = Some ( ty:: UniverseIndex :: ROOT ) ;
@@ -279,20 +314,20 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
279
314
}
280
315
} ;
281
316
282
- let existing_bound_var = match self . canonicalize_mode {
283
- CanonicalizeMode :: Input => None ,
317
+ let var = match self . canonicalize_mode {
318
+ CanonicalizeMode :: Input => {
319
+ // It's fine to not add `r` to the lookup table, as we will
320
+ // never lookup regions when canonicalizing inputs.
321
+ let var = ty:: BoundVar :: from ( self . variables . len ( ) ) ;
322
+ self . variables . push ( r. into ( ) ) ;
323
+ self . primitive_var_infos . push ( CanonicalVarInfo { kind } ) ;
324
+ var
325
+ }
284
326
CanonicalizeMode :: Response { .. } => {
285
- self . variables . iter ( ) . position ( | & v| v == r . into ( ) ) . map ( ty :: BoundVar :: from )
327
+ self . get_or_insert_bound_var ( r , CanonicalVarInfo { kind } )
286
328
}
287
329
} ;
288
330
289
- let var = existing_bound_var. unwrap_or_else ( || {
290
- let var = ty:: BoundVar :: from ( self . variables . len ( ) ) ;
291
- self . variables . push ( r. into ( ) ) ;
292
- self . primitive_var_infos . push ( CanonicalVarInfo { kind } ) ;
293
- var
294
- } ) ;
295
-
296
331
Region :: new_anon_bound ( self . interner ( ) , self . binder_index , var)
297
332
}
298
333
@@ -373,14 +408,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
373
408
| ty:: Error ( _) => return t. super_fold_with ( self ) ,
374
409
} ;
375
410
376
- let var = ty:: BoundVar :: from (
377
- self . variables . iter ( ) . position ( |& v| v == t. into ( ) ) . unwrap_or_else ( || {
378
- let var = self . variables . len ( ) ;
379
- self . variables . push ( t. into ( ) ) ;
380
- self . primitive_var_infos . push ( CanonicalVarInfo { kind } ) ;
381
- var
382
- } ) ,
383
- ) ;
411
+ let var = self . get_or_insert_bound_var ( t, CanonicalVarInfo { kind } ) ;
384
412
385
413
Ty :: new_anon_bound ( self . interner ( ) , self . binder_index , var)
386
414
}
@@ -431,14 +459,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
431
459
| ty:: ConstKind :: Expr ( _) => return c. super_fold_with ( self ) ,
432
460
} ;
433
461
434
- let var = ty:: BoundVar :: from (
435
- self . variables . iter ( ) . position ( |& v| v == c. into ( ) ) . unwrap_or_else ( || {
436
- let var = self . variables . len ( ) ;
437
- self . variables . push ( c. into ( ) ) ;
438
- self . primitive_var_infos . push ( CanonicalVarInfo { kind } ) ;
439
- var
440
- } ) ,
441
- ) ;
462
+ let var = self . get_or_insert_bound_var ( c, CanonicalVarInfo { kind } ) ;
442
463
443
464
Const :: new_anon_bound ( self . interner ( ) , self . binder_index , var, ty)
444
465
}
0 commit comments