@@ -35,13 +35,35 @@ impl<'tcx> InferCtxt<'tcx> {
35
35
/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
36
36
pub fn canonicalize_query < V > (
37
37
& self ,
38
- value : V ,
38
+ value : ty :: ParamEnvAnd < ' tcx , V > ,
39
39
query_state : & mut OriginalQueryValues < ' tcx > ,
40
- ) -> Canonical < ' tcx , V >
40
+ ) -> Canonical < ' tcx , ty :: ParamEnvAnd < ' tcx , V > >
41
41
where
42
42
V : TypeFoldable < TyCtxt < ' tcx > > ,
43
43
{
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) )
45
67
}
46
68
47
69
/// Like [Self::canonicalize_query], but preserves distinct universes. For
@@ -126,19 +148,35 @@ impl<'tcx> InferCtxt<'tcx> {
126
148
/// handling of `'static` regions (e.g. trait evaluation).
127
149
pub fn canonicalize_query_keep_static < V > (
128
150
& self ,
129
- value : V ,
151
+ value : ty :: ParamEnvAnd < ' tcx , V > ,
130
152
query_state : & mut OriginalQueryValues < ' tcx > ,
131
- ) -> Canonical < ' tcx , V >
153
+ ) -> Canonical < ' tcx , ty :: ParamEnvAnd < ' tcx , V > >
132
154
where
133
155
V : TypeFoldable < TyCtxt < ' tcx > > ,
134
156
{
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,
136
173
value,
137
174
self ,
138
175
self . tcx ,
139
176
& CanonicalizeFreeRegionsOtherThanStatic ,
140
177
query_state,
141
178
)
179
+ . unchecked_map ( |( param_env, value) | param_env. and ( value) )
142
180
}
143
181
}
144
182
@@ -615,6 +653,66 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
615
653
Canonical { max_universe, variables : canonical_variables, value : out_value }
616
654
}
617
655
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
+
618
716
/// Creates a canonical variable replacing `kind` from the input,
619
717
/// or returns an existing variable if `kind` has already been
620
718
/// seen. `kind` is expected to be an unbound variable (or
0 commit comments