@@ -4,12 +4,23 @@ 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 , 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 ,
910} ;
1011
1112use crate :: delegate:: SolverDelegate ;
1213
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+
1324/// Whether we're canonicalizing a query input or the query response.
1425///
1526/// 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> {
7990 cache : Default :: default ( ) ,
8091 } ;
8192
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+ } ;
8398 assert ! ( !value. has_infer( ) , "unexpected infer in {value:?}" ) ;
8499 assert ! ( !value. has_placeholders( ) , "unexpected placeholders in {value:?}" ) ;
85100 let ( max_universe, variables) = canonicalizer. finalize ( ) ;
86101 Canonical { max_universe, variables, value }
87102 }
88103
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+
89167 /// When canonicalizing query inputs, we keep `'static` in the `param_env`
90168 /// but erase it everywhere else. We generally don't want to depend on region
91169 /// 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> {
100178 input : QueryInput < I , P > ,
101179 ) -> ty:: Canonical < I , QueryInput < I , P > > {
102180 // 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 ) ;
116183 // Then canonicalize the rest of the input without keeping `'static`
117184 // while *mostly* reusing the canonicalizer from above.
118185 let mut rest_canonicalizer = Canonicalizer {
119186 delegate,
120187 canonicalize_mode : CanonicalizeMode :: Input { keep_static : false } ,
121188
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,
127192 binder_index : ty:: INNERMOST ,
128193
129194 // 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> {
134199 cache : Default :: default ( ) ,
135200 } ;
136201
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+ } ;
138208 let goal = Goal { param_env, predicate } ;
209+
210+ let predefined_opaques_in_body = input. predefined_opaques_in_body ;
139211 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+
141218 let value = QueryInput { goal, predefined_opaques_in_body } ;
142219
143220 assert ! ( !value. has_infer( ) , "unexpected infer in {value:?}" ) ;
@@ -387,7 +464,11 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
387464 | ty:: Alias ( _, _)
388465 | ty:: Bound ( _, _)
389466 | 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+ } ;
391472 }
392473 } ;
393474
@@ -522,11 +603,28 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
522603 | ty:: ConstKind :: Unevaluated ( _)
523604 | ty:: ConstKind :: Value ( _)
524605 | 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+ }
526609 } ;
527610
528611 let var = self . get_or_insert_bound_var ( c, kind) ;
529612
530613 Const :: new_anon_bound ( self . cx ( ) , self . binder_index , var)
531614 }
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+ }
532630}
0 commit comments