@@ -4,12 +4,23 @@ 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 , InferCtxtLike , Interner ,
8
- 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 ;
12
13
14
+ /// Does this have infer/placeholder/param, free regions or ReErased?
15
+ const NEEDS_CANONICAL : TypeFlags = TypeFlags :: from_bits (
16
+ TypeFlags :: HAS_INFER . bits ( )
17
+ | TypeFlags :: HAS_PLACEHOLDER . bits ( )
18
+ | TypeFlags :: HAS_PARAM . bits ( )
19
+ | TypeFlags :: HAS_FREE_REGIONS . bits ( )
20
+ | TypeFlags :: HAS_RE_ERASED . bits ( ) ,
21
+ )
22
+ . unwrap ( ) ;
23
+
13
24
/// Whether we're canonicalizing a query input or the query response.
14
25
///
15
26
/// When canonicalizing an input we're in the context of the caller
@@ -79,13 +90,80 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
79
90
cache : Default :: default ( ) ,
80
91
} ;
81
92
82
- let value = value. fold_with ( & mut canonicalizer) ;
93
+ let value = if value. has_type_flags ( NEEDS_CANONICAL ) {
94
+ value. fold_with ( & mut canonicalizer)
95
+ } else {
96
+ value
97
+ } ;
83
98
assert ! ( !value. has_infer( ) , "unexpected infer in {value:?}" ) ;
84
99
assert ! ( !value. has_placeholders( ) , "unexpected placeholders in {value:?}" ) ;
85
100
let ( max_universe, variables) = canonicalizer. finalize ( ) ;
86
101
Canonical { max_universe, variables, value }
87
102
}
88
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
+ if !param_env. has_non_region_infer ( ) {
114
+ delegate. cx ( ) . canonical_param_env_cache_get_or_insert (
115
+ param_env,
116
+ || {
117
+ let mut variables = Vec :: new ( ) ;
118
+ let mut env_canonicalizer = Canonicalizer {
119
+ delegate,
120
+ canonicalize_mode : CanonicalizeMode :: Input { keep_static : true } ,
121
+
122
+ variables : & mut variables,
123
+ variable_lookup_table : Default :: default ( ) ,
124
+ var_kinds : Vec :: new ( ) ,
125
+ binder_index : ty:: INNERMOST ,
126
+
127
+ cache : Default :: default ( ) ,
128
+ } ;
129
+ let param_env = param_env. fold_with ( & mut env_canonicalizer) ;
130
+ debug_assert_eq ! ( env_canonicalizer. binder_index, ty:: INNERMOST ) ;
131
+ CanonicalParamEnvCacheEntry {
132
+ param_env,
133
+ variable_lookup_table : env_canonicalizer. variable_lookup_table ,
134
+ var_kinds : env_canonicalizer. var_kinds ,
135
+ variables,
136
+ }
137
+ } ,
138
+ |& CanonicalParamEnvCacheEntry {
139
+ param_env,
140
+ variables : ref cache_variables,
141
+ ref variable_lookup_table,
142
+ ref var_kinds,
143
+ } | {
144
+ debug_assert ! ( variables. is_empty( ) ) ;
145
+ variables. extend ( cache_variables. iter ( ) . copied ( ) ) ;
146
+ ( param_env, variable_lookup_table. clone ( ) , var_kinds. clone ( ) )
147
+ } ,
148
+ )
149
+ } else {
150
+ let mut env_canonicalizer = Canonicalizer {
151
+ delegate,
152
+ canonicalize_mode : CanonicalizeMode :: Input { keep_static : true } ,
153
+
154
+ variables,
155
+ variable_lookup_table : Default :: default ( ) ,
156
+ var_kinds : Vec :: new ( ) ,
157
+ binder_index : ty:: INNERMOST ,
158
+
159
+ cache : Default :: default ( ) ,
160
+ } ;
161
+ let param_env = param_env. fold_with ( & mut env_canonicalizer) ;
162
+ debug_assert_eq ! ( env_canonicalizer. binder_index, ty:: INNERMOST ) ;
163
+ ( param_env, env_canonicalizer. variable_lookup_table , env_canonicalizer. var_kinds )
164
+ }
165
+ }
166
+
89
167
/// When canonicalizing query inputs, we keep `'static` in the `param_env`
90
168
/// but erase it everywhere else. We generally don't want to depend on region
91
169
/// identity, so while it should not matter whether `'static` is kept in the
@@ -100,30 +178,17 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
100
178
input : QueryInput < I , P > ,
101
179
) -> ty:: Canonical < I , QueryInput < I , P > > {
102
180
// First canonicalize the `param_env` while keeping `'static`
103
- let mut env_canonicalizer = Canonicalizer {
104
- delegate,
105
- canonicalize_mode : CanonicalizeMode :: Input { keep_static : true } ,
106
-
107
- variables,
108
- variable_lookup_table : Default :: default ( ) ,
109
- var_kinds : Vec :: new ( ) ,
110
- binder_index : ty:: INNERMOST ,
111
-
112
- cache : Default :: default ( ) ,
113
- } ;
114
- let param_env = input. goal . param_env . fold_with ( & mut env_canonicalizer) ;
115
- debug_assert_eq ! ( env_canonicalizer. binder_index, ty:: INNERMOST ) ;
181
+ let ( param_env, variable_lookup_table, var_kinds) =
182
+ Canonicalizer :: canonicalize_param_env ( delegate, variables, input. goal . param_env ) ;
116
183
// Then canonicalize the rest of the input without keeping `'static`
117
184
// while *mostly* reusing the canonicalizer from above.
118
185
let mut rest_canonicalizer = Canonicalizer {
119
186
delegate,
120
187
canonicalize_mode : CanonicalizeMode :: Input { keep_static : false } ,
121
188
122
- variables : env_canonicalizer. variables ,
123
- // We're able to reuse the `variable_lookup_table` as whether or not
124
- // it already contains an entry for `'static` does not matter.
125
- variable_lookup_table : env_canonicalizer. variable_lookup_table ,
126
- var_kinds : env_canonicalizer. var_kinds ,
189
+ variables,
190
+ variable_lookup_table,
191
+ var_kinds,
127
192
binder_index : ty:: INNERMOST ,
128
193
129
194
// We do not reuse the cache as it may contain entries whose canonicalized
@@ -134,10 +199,22 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
134
199
cache : Default :: default ( ) ,
135
200
} ;
136
201
137
- let predicate = input. goal . predicate . fold_with ( & mut rest_canonicalizer) ;
202
+ let predicate = input. goal . predicate ;
203
+ let predicate = if predicate. has_type_flags ( NEEDS_CANONICAL ) {
204
+ predicate. fold_with ( & mut rest_canonicalizer)
205
+ } else {
206
+ predicate
207
+ } ;
138
208
let goal = Goal { param_env, predicate } ;
209
+
210
+ let predefined_opaques_in_body = input. predefined_opaques_in_body ;
139
211
let predefined_opaques_in_body =
140
- input. predefined_opaques_in_body . fold_with ( & mut rest_canonicalizer) ;
212
+ if input. predefined_opaques_in_body . has_type_flags ( NEEDS_CANONICAL ) {
213
+ predefined_opaques_in_body. fold_with ( & mut rest_canonicalizer)
214
+ } else {
215
+ predefined_opaques_in_body
216
+ } ;
217
+
141
218
let value = QueryInput { goal, predefined_opaques_in_body } ;
142
219
143
220
assert ! ( !value. has_infer( ) , "unexpected infer in {value:?}" ) ;
@@ -387,7 +464,11 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
387
464
| ty:: Alias ( _, _)
388
465
| ty:: Bound ( _, _)
389
466
| ty:: Error ( _) => {
390
- return ensure_sufficient_stack ( || t. super_fold_with ( self ) ) ;
467
+ return if t. has_type_flags ( NEEDS_CANONICAL ) {
468
+ ensure_sufficient_stack ( || t. super_fold_with ( self ) )
469
+ } else {
470
+ t
471
+ } ;
391
472
}
392
473
} ;
393
474
@@ -522,11 +603,28 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
522
603
| ty:: ConstKind :: Unevaluated ( _)
523
604
| ty:: ConstKind :: Value ( _)
524
605
| ty:: ConstKind :: Error ( _)
525
- | ty:: ConstKind :: Expr ( _) => return c. super_fold_with ( self ) ,
606
+ | ty:: ConstKind :: Expr ( _) => {
607
+ return if c. has_type_flags ( NEEDS_CANONICAL ) { c. super_fold_with ( self ) } else { c } ;
608
+ }
526
609
} ;
527
610
528
611
let var = self . get_or_insert_bound_var ( c, kind) ;
529
612
530
613
Const :: new_anon_bound ( self . cx ( ) , self . binder_index , var)
531
614
}
615
+
616
+ fn fold_predicate ( & mut self , p : I :: Predicate ) -> I :: Predicate {
617
+ if p. flags ( ) . intersects ( NEEDS_CANONICAL ) { p. super_fold_with ( self ) } else { p }
618
+ }
619
+
620
+ fn fold_clauses ( & mut self , c : I :: Clauses ) -> I :: Clauses {
621
+ match self . canonicalize_mode {
622
+ CanonicalizeMode :: Input { keep_static : true }
623
+ | CanonicalizeMode :: Response { max_input_universe : _ } => { }
624
+ CanonicalizeMode :: Input { keep_static : false } => {
625
+ panic ! ( "erasing 'static in env" )
626
+ }
627
+ }
628
+ if c. flags ( ) . intersects ( NEEDS_CANONICAL ) { c. super_fold_with ( self ) } else { c }
629
+ }
532
630
}
0 commit comments