@@ -4,8 +4,9 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
4
4
use rustc_type_ir:: inherent:: * ;
5
5
use rustc_type_ir:: solve:: { Goal , QueryInput } ;
6
6
use 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 ,
9
10
} ;
10
11
11
12
use crate :: delegate:: SolverDelegate ;
@@ -100,6 +101,76 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
100
101
Canonical { max_universe, variables, value }
101
102
}
102
103
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
+
103
174
/// When canonicalizing query inputs, we keep `'static` in the `param_env`
104
175
/// but erase it everywhere else. We generally don't want to depend on region
105
176
/// 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> {
114
185
input : QueryInput < I , P > ,
115
186
) -> ty:: Canonical < I , QueryInput < I , P > > {
116
187
// 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 ) ;
137
190
// Then canonicalize the rest of the input without keeping `'static`
138
191
// while *mostly* reusing the canonicalizer from above.
139
192
let mut rest_canonicalizer = Canonicalizer {
140
193
delegate,
141
194
canonicalize_mode : CanonicalizeMode :: Input { keep_static : false } ,
142
195
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,
148
199
binder_index : ty:: INNERMOST ,
149
200
150
201
// We do not reuse the cache as it may contain entries whose canonicalized
0 commit comments