@@ -4,8 +4,9 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
44use rustc_type_ir:: inherent:: * ;
55use rustc_type_ir:: solve:: { Goal , QueryInput } ;
66use rustc_type_ir:: {
7- self as ty, Canonical , CanonicalTyVarKind , CanonicalVarKind , Flags , InferCtxtLike , Interner ,
8- TypeFlags , TypeFoldable , TypeFolder , TypeSuperFoldable , TypeVisitableExt ,
7+ self as ty, Canonical , CanonicalParamEnvCacheEntry , CanonicalTyVarKind , CanonicalVarKind ,
8+ Flags , InferCtxtLike , Interner , TypeFlags , TypeFoldable , TypeFolder , TypeSuperFoldable ,
9+ TypeVisitableExt ,
910} ;
1011
1112use crate :: delegate:: SolverDelegate ;
@@ -100,6 +101,76 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
100101 Canonical { max_universe, variables, value }
101102 }
102103
104+ fn canonicalize_param_env (
105+ delegate : & ' a D ,
106+ variables : & ' a mut Vec < I :: GenericArg > ,
107+ param_env : I :: ParamEnv ,
108+ ) -> ( I :: ParamEnv , HashMap < I :: GenericArg , usize > , Vec < CanonicalVarKind < I > > ) {
109+ if !param_env. has_type_flags ( NEEDS_CANONICAL ) {
110+ return ( param_env, Default :: default ( ) , Vec :: new ( ) ) ;
111+ }
112+
113+ // Check whether we can use the global cache for this param_env. As we only use
114+ // the `param_env` itself as the cache key, considering any additional information
115+ // durnig its canonicalization would be incorrect. We always canonicalize region
116+ // inference variables in a separate universe, so these are fine. However, we do
117+ // track the universe of type and const inference variables so these must not be
118+ // globally cached. We don't rely on any additional information when canonicalizing
119+ // placeholders.
120+ if !param_env. has_non_region_infer ( ) {
121+ delegate. cx ( ) . canonical_param_env_cache_get_or_insert (
122+ param_env,
123+ || {
124+ let mut variables = Vec :: new ( ) ;
125+ let mut env_canonicalizer = Canonicalizer {
126+ delegate,
127+ canonicalize_mode : CanonicalizeMode :: Input { keep_static : true } ,
128+
129+ variables : & mut variables,
130+ variable_lookup_table : Default :: default ( ) ,
131+ var_kinds : Vec :: new ( ) ,
132+ binder_index : ty:: INNERMOST ,
133+
134+ cache : Default :: default ( ) ,
135+ } ;
136+ let param_env = param_env. fold_with ( & mut env_canonicalizer) ;
137+ debug_assert_eq ! ( env_canonicalizer. binder_index, ty:: INNERMOST ) ;
138+ CanonicalParamEnvCacheEntry {
139+ param_env,
140+ variable_lookup_table : env_canonicalizer. variable_lookup_table ,
141+ var_kinds : env_canonicalizer. var_kinds ,
142+ variables,
143+ }
144+ } ,
145+ |& CanonicalParamEnvCacheEntry {
146+ param_env,
147+ variables : ref cache_variables,
148+ ref variable_lookup_table,
149+ ref var_kinds,
150+ } | {
151+ debug_assert ! ( variables. is_empty( ) ) ;
152+ variables. extend ( cache_variables. iter ( ) . copied ( ) ) ;
153+ ( param_env, variable_lookup_table. clone ( ) , var_kinds. clone ( ) )
154+ } ,
155+ )
156+ } else {
157+ let mut env_canonicalizer = Canonicalizer {
158+ delegate,
159+ canonicalize_mode : CanonicalizeMode :: Input { keep_static : true } ,
160+
161+ variables,
162+ variable_lookup_table : Default :: default ( ) ,
163+ var_kinds : Vec :: new ( ) ,
164+ binder_index : ty:: INNERMOST ,
165+
166+ cache : Default :: default ( ) ,
167+ } ;
168+ let param_env = param_env. fold_with ( & mut env_canonicalizer) ;
169+ debug_assert_eq ! ( env_canonicalizer. binder_index, ty:: INNERMOST ) ;
170+ ( param_env, env_canonicalizer. variable_lookup_table , env_canonicalizer. var_kinds )
171+ }
172+ }
173+
103174 /// When canonicalizing query inputs, we keep `'static` in the `param_env`
104175 /// but erase it everywhere else. We generally don't want to depend on region
105176 /// identity, so while it should not matter whether `'static` is kept in the
@@ -114,37 +185,17 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
114185 input : QueryInput < I , P > ,
115186 ) -> ty:: Canonical < I , QueryInput < I , P > > {
116187 // First canonicalize the `param_env` while keeping `'static`
117- let mut env_canonicalizer = Canonicalizer {
118- delegate,
119- canonicalize_mode : CanonicalizeMode :: Input { keep_static : true } ,
120-
121- variables,
122- variable_lookup_table : Default :: default ( ) ,
123- var_kinds : Vec :: new ( ) ,
124- binder_index : ty:: INNERMOST ,
125-
126- cache : Default :: default ( ) ,
127- } ;
128-
129- let param_env = input. goal . param_env ;
130- let param_env = if param_env. has_type_flags ( NEEDS_CANONICAL ) {
131- param_env. fold_with ( & mut env_canonicalizer)
132- } else {
133- param_env
134- } ;
135-
136- debug_assert_eq ! ( env_canonicalizer. binder_index, ty:: INNERMOST ) ;
188+ let ( param_env, variable_lookup_table, var_kinds) =
189+ Canonicalizer :: canonicalize_param_env ( delegate, variables, input. goal . param_env ) ;
137190 // Then canonicalize the rest of the input without keeping `'static`
138191 // while *mostly* reusing the canonicalizer from above.
139192 let mut rest_canonicalizer = Canonicalizer {
140193 delegate,
141194 canonicalize_mode : CanonicalizeMode :: Input { keep_static : false } ,
142195
143- variables : env_canonicalizer. variables ,
144- // We're able to reuse the `variable_lookup_table` as whether or not
145- // it already contains an entry for `'static` does not matter.
146- variable_lookup_table : env_canonicalizer. variable_lookup_table ,
147- var_kinds : env_canonicalizer. var_kinds ,
196+ variables,
197+ variable_lookup_table,
198+ var_kinds,
148199 binder_index : ty:: INNERMOST ,
149200
150201 // We do not reuse the cache as it may contain entries whose canonicalized
0 commit comments