@@ -35,13 +35,35 @@ impl<'tcx> InferCtxt<'tcx> {
3535 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
3636 pub fn canonicalize_query < V > (
3737 & self ,
38- value : V ,
38+ value : ty :: ParamEnvAnd < ' tcx , V > ,
3939 query_state : & mut OriginalQueryValues < ' tcx > ,
40- ) -> Canonical < ' tcx , V >
40+ ) -> Canonical < ' tcx , ty :: ParamEnvAnd < ' tcx , V > >
4141 where
4242 V : TypeFoldable < TyCtxt < ' tcx > > ,
4343 {
44- Canonicalizer :: canonicalize ( value, self , self . tcx , & CanonicalizeAllFreeRegions , query_state)
44+ let ( param_env, value) = value. into_parts ( ) ;
45+ let base = self . tcx . canonical_param_env_cache . get_or_insert (
46+ param_env,
47+ query_state,
48+ |query_state| {
49+ Canonicalizer :: canonicalize (
50+ param_env,
51+ self ,
52+ self . tcx ,
53+ & CanonicalizeFreeRegionsOtherThanStatic ,
54+ query_state,
55+ )
56+ } ,
57+ ) ;
58+ Canonicalizer :: canonicalize_continue (
59+ base,
60+ value,
61+ self ,
62+ self . tcx ,
63+ & CanonicalizeAllFreeRegions ,
64+ query_state,
65+ )
66+ . unchecked_map ( |( param_env, value) | param_env. and ( value) )
4567 }
4668
4769 /// Like [Self::canonicalize_query], but preserves distinct universes. For
@@ -126,19 +148,35 @@ impl<'tcx> InferCtxt<'tcx> {
126148 /// handling of `'static` regions (e.g. trait evaluation).
127149 pub fn canonicalize_query_keep_static < V > (
128150 & self ,
129- value : V ,
151+ value : ty :: ParamEnvAnd < ' tcx , V > ,
130152 query_state : & mut OriginalQueryValues < ' tcx > ,
131- ) -> Canonical < ' tcx , V >
153+ ) -> Canonical < ' tcx , ty :: ParamEnvAnd < ' tcx , V > >
132154 where
133155 V : TypeFoldable < TyCtxt < ' tcx > > ,
134156 {
135- Canonicalizer :: canonicalize (
157+ let ( param_env, value) = value. into_parts ( ) ;
158+ let base = self . tcx . canonical_param_env_cache . get_or_insert (
159+ param_env,
160+ query_state,
161+ |query_state| {
162+ Canonicalizer :: canonicalize (
163+ param_env,
164+ self ,
165+ self . tcx ,
166+ & CanonicalizeFreeRegionsOtherThanStatic ,
167+ query_state,
168+ )
169+ } ,
170+ ) ;
171+ Canonicalizer :: canonicalize_continue (
172+ base,
136173 value,
137174 self ,
138175 self . tcx ,
139176 & CanonicalizeFreeRegionsOtherThanStatic ,
140177 query_state,
141178 )
179+ . unchecked_map ( |( param_env, value) | param_env. and ( value) )
142180 }
143181}
144182
@@ -615,6 +653,66 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
615653 Canonical { max_universe, variables : canonical_variables, value : out_value }
616654 }
617655
656+ fn canonicalize_continue < U , V > (
657+ base : Canonical < ' tcx , U > ,
658+ value : V ,
659+ infcx : & InferCtxt < ' tcx > ,
660+ tcx : TyCtxt < ' tcx > ,
661+ canonicalize_region_mode : & dyn CanonicalizeMode ,
662+ query_state : & mut OriginalQueryValues < ' tcx > ,
663+ ) -> Canonical < ' tcx , ( U , V ) >
664+ where
665+ V : TypeFoldable < TyCtxt < ' tcx > > ,
666+ {
667+ let needs_canonical_flags = if canonicalize_region_mode. any ( ) {
668+ TypeFlags :: HAS_INFER | TypeFlags :: HAS_PLACEHOLDER | TypeFlags :: HAS_FREE_REGIONS
669+ } else {
670+ TypeFlags :: HAS_INFER | TypeFlags :: HAS_PLACEHOLDER
671+ } ;
672+
673+ // Fast path: nothing that needs to be canonicalized.
674+ if !value. has_type_flags ( needs_canonical_flags) {
675+ return base. unchecked_map ( |b| ( b, value) ) ;
676+ }
677+
678+ let mut canonicalizer = Canonicalizer {
679+ infcx,
680+ tcx,
681+ canonicalize_mode : canonicalize_region_mode,
682+ needs_canonical_flags,
683+ variables : SmallVec :: from_slice ( base. variables ) ,
684+ query_state,
685+ indices : FxHashMap :: default ( ) ,
686+ binder_index : ty:: INNERMOST ,
687+ } ;
688+ if canonicalizer. query_state . var_values . spilled ( ) {
689+ canonicalizer. indices = canonicalizer
690+ . query_state
691+ . var_values
692+ . iter ( )
693+ . enumerate ( )
694+ . map ( |( i, & kind) | ( kind, BoundVar :: new ( i) ) )
695+ . collect ( ) ;
696+ }
697+ let out_value = value. fold_with ( & mut canonicalizer) ;
698+
699+ // Once we have canonicalized `out_value`, it should not
700+ // contain anything that ties it to this inference context
701+ // anymore.
702+ debug_assert ! ( !out_value. has_infer( ) && !out_value. has_placeholders( ) ) ;
703+
704+ let canonical_variables =
705+ tcx. mk_canonical_var_infos ( & canonicalizer. universe_canonicalized_variables ( ) ) ;
706+
707+ let max_universe = canonical_variables
708+ . iter ( )
709+ . map ( |cvar| cvar. universe ( ) )
710+ . max ( )
711+ . unwrap_or ( ty:: UniverseIndex :: ROOT ) ;
712+
713+ Canonical { max_universe, variables : canonical_variables, value : ( base. value , out_value) }
714+ }
715+
618716 /// Creates a canonical variable replacing `kind` from the input,
619717 /// or returns an existing variable if `kind` has already been
620718 /// seen. `kind` is expected to be an unbound variable (or
0 commit comments