11use std:: cmp:: Ordering ;
22
3+ use rustc_type_ir:: data_structures:: HashMap ;
34use rustc_type_ir:: fold:: { TypeFoldable , TypeFolder , TypeSuperFoldable } ;
45use rustc_type_ir:: inherent:: * ;
56use rustc_type_ir:: visit:: TypeVisitableExt ;
@@ -44,6 +45,8 @@ pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
4445 canonicalize_mode : CanonicalizeMode ,
4546
4647 variables : & ' a mut Vec < I :: GenericArg > ,
48+ variable_lookup_table : HashMap < I :: GenericArg , usize > ,
49+
4750 primitive_var_infos : Vec < CanonicalVarInfo < I > > ,
4851 binder_index : ty:: DebruijnIndex ,
4952}
@@ -60,6 +63,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
6063 canonicalize_mode,
6164
6265 variables,
66+ variable_lookup_table : Default :: default ( ) ,
6367 primitive_var_infos : Vec :: new ( ) ,
6468 binder_index : ty:: INNERMOST ,
6569 } ;
@@ -75,6 +79,37 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
7579 Canonical { defining_opaque_types, max_universe, variables, value }
7680 }
7781
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+
78113 fn finalize ( self ) -> ( ty:: UniverseIndex , I :: CanonicalVars ) {
79114 let mut var_infos = self . primitive_var_infos ;
80115 // 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> {
124159 // - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
125160 // - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
126161 //
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.
129164 let mut curr_compressed_uv = ty:: UniverseIndex :: ROOT ;
130165 let mut existential_in_new_uv = None ;
131166 let mut next_orig_uv = Some ( ty:: UniverseIndex :: ROOT ) ;
@@ -279,20 +314,20 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
279314 }
280315 } ;
281316
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+ }
284326 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 } )
286328 }
287329 } ;
288330
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-
296331 Region :: new_anon_bound ( self . cx ( ) , self . binder_index , var)
297332 }
298333
@@ -373,14 +408,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
373408 | ty:: Error ( _) => return t. super_fold_with ( self ) ,
374409 } ;
375410
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 } ) ;
384412
385413 Ty :: new_anon_bound ( self . cx ( ) , self . binder_index , var)
386414 }
@@ -421,14 +449,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
421449 | ty:: ConstKind :: Expr ( _) => return c. super_fold_with ( self ) ,
422450 } ;
423451
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 } ) ;
432453
433454 Const :: new_anon_bound ( self . cx ( ) , self . binder_index , var)
434455 }
0 commit comments