1
1
use std:: cmp:: Ordering ;
2
2
3
+ use rustc_type_ir:: data_structures:: HashMap ;
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 ;
@@ -44,6 +45,8 @@ pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
44
45
canonicalize_mode : CanonicalizeMode ,
45
46
46
47
variables : & ' a mut Vec < I :: GenericArg > ,
48
+ variable_lookup_table : HashMap < I :: GenericArg , usize > ,
49
+
47
50
primitive_var_infos : Vec < CanonicalVarInfo < I > > ,
48
51
binder_index : ty:: DebruijnIndex ,
49
52
}
@@ -60,6 +63,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
60
63
canonicalize_mode,
61
64
62
65
variables,
66
+ variable_lookup_table : Default :: default ( ) ,
63
67
primitive_var_infos : Vec :: new ( ) ,
64
68
binder_index : ty:: INNERMOST ,
65
69
} ;
@@ -75,6 +79,37 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
75
79
Canonical { defining_opaque_types, max_universe, variables, value }
76
80
}
77
81
82
+ fn get_or_insert_bound_var (
83
+ & mut self ,
84
+ arg : impl Into < I :: GenericArg > ,
85
+ canonical_var_info : CanonicalVarInfo < I > ,
86
+ ) -> ty:: BoundVar {
87
+ // FIXME: 16 is made up and arbitrary. We should look at some
88
+ // perf data here.
89
+ let arg = arg. into ( ) ;
90
+ let idx = if self . variables . len ( ) > 16 {
91
+ if self . variable_lookup_table . is_empty ( ) {
92
+ self . variable_lookup_table . extend ( self . variables . iter ( ) . copied ( ) . zip ( 0 ..) ) ;
93
+ }
94
+
95
+ * self . variable_lookup_table . entry ( arg) . or_insert_with ( || {
96
+ let var = self . variables . len ( ) ;
97
+ self . variables . push ( arg) ;
98
+ self . primitive_var_infos . push ( canonical_var_info) ;
99
+ var
100
+ } )
101
+ } else {
102
+ self . variables . iter ( ) . position ( |& v| v == arg) . unwrap_or_else ( || {
103
+ let var = self . variables . len ( ) ;
104
+ self . variables . push ( arg) ;
105
+ self . primitive_var_infos . push ( canonical_var_info) ;
106
+ var
107
+ } )
108
+ } ;
109
+
110
+ ty:: BoundVar :: from ( idx)
111
+ }
112
+
78
113
fn finalize ( self ) -> ( ty:: UniverseIndex , I :: CanonicalVars ) {
79
114
let mut var_infos = self . primitive_var_infos ;
80
115
// See the rustc-dev-guide section about how we deal with universes
@@ -124,8 +159,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
124
159
// - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
125
160
// - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
126
161
//
127
- // This algorithm runs in `O(n² )` where `n` is the number of different universe
128
- // indices in the input . This should be fine as `n` is expected to be small.
162
+ // This algorithm runs in `O(mn )` where `n` is the number of different universes and
163
+ // `m` the number of variables . This should be fine as both are expected to be small.
129
164
let mut curr_compressed_uv = ty:: UniverseIndex :: ROOT ;
130
165
let mut existential_in_new_uv = None ;
131
166
let mut next_orig_uv = Some ( ty:: UniverseIndex :: ROOT ) ;
@@ -279,20 +314,20 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
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 . cx ( ) , self . binder_index , var)
297
332
}
298
333
@@ -373,14 +408,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
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 . cx ( ) , self . binder_index , var)
386
414
}
@@ -421,14 +449,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
421
449
| ty:: ConstKind :: Expr ( _) => return c. super_fold_with ( self ) ,
422
450
} ;
423
451
424
- let var = ty:: BoundVar :: from (
425
- self . variables . iter ( ) . position ( |& v| v == c. into ( ) ) . unwrap_or_else ( || {
426
- let var = self . variables . len ( ) ;
427
- self . variables . push ( c. into ( ) ) ;
428
- self . primitive_var_infos . push ( CanonicalVarInfo { kind } ) ;
429
- var
430
- } ) ,
431
- ) ;
452
+ let var = self . get_or_insert_bound_var ( c, CanonicalVarInfo { kind } ) ;
432
453
433
454
Const :: new_anon_bound ( self . cx ( ) , self . binder_index , var)
434
455
}
0 commit comments