1717
1818use infer:: canonical:: {
1919 Canonical , CanonicalTyVarKind , CanonicalVarInfo , CanonicalVarKind , Canonicalized ,
20- SmallCanonicalVarValues ,
20+ OriginalQueryValues ,
2121} ;
2222use infer:: InferCtxt ;
2323use std:: sync:: atomic:: Ordering ;
@@ -48,7 +48,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
4848 pub fn canonicalize_query < V > (
4949 & self ,
5050 value : & V ,
51- var_values : & mut SmallCanonicalVarValues < ' tcx >
51+ query_state : & mut OriginalQueryValues < ' tcx > ,
5252 ) -> Canonicalized < ' gcx , V >
5353 where
5454 V : TypeFoldable < ' tcx > + Lift < ' gcx > ,
@@ -63,11 +63,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
6363 value,
6464 Some ( self ) ,
6565 self . tcx ,
66- CanonicalizeRegionMode {
67- static_region : true ,
68- other_free_regions : true ,
69- } ,
70- var_values,
66+ & CanonicalizeAllFreeRegions ,
67+ query_state,
7168 )
7269 }
7370
@@ -96,23 +93,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
9693 /// out the [chapter in the rustc guide][c].
9794 ///
9895 /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query-result
99- pub fn canonicalize_response < V > (
100- & self ,
101- value : & V ,
102- ) -> Canonicalized < ' gcx , V >
96+ pub fn canonicalize_response < V > ( & self , value : & V ) -> Canonicalized < ' gcx , V >
10397 where
10498 V : TypeFoldable < ' tcx > + Lift < ' gcx > ,
10599 {
106- let mut var_values = SmallVec :: new ( ) ;
100+ let mut query_state = OriginalQueryValues :: default ( ) ;
107101 Canonicalizer :: canonicalize (
108102 value,
109103 Some ( self ) ,
110104 self . tcx ,
111- CanonicalizeRegionMode {
112- static_region : false ,
113- other_free_regions : false ,
114- } ,
115- & mut var_values
105+ & CanonicalizeQueryResponse ,
106+ & mut query_state,
116107 )
117108 }
118109
@@ -128,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
128119 pub fn canonicalize_hr_query_hack < V > (
129120 & self ,
130121 value : & V ,
131- var_values : & mut SmallCanonicalVarValues < ' tcx >
122+ query_state : & mut OriginalQueryValues < ' tcx > ,
132123 ) -> Canonicalized < ' gcx , V >
133124 where
134125 V : TypeFoldable < ' tcx > + Lift < ' gcx > ,
@@ -143,39 +134,99 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
143134 value,
144135 Some ( self ) ,
145136 self . tcx ,
146- CanonicalizeRegionMode {
147- static_region : false ,
148- other_free_regions : true ,
149- } ,
150- var_values
137+ & CanonicalizeFreeRegionsOtherThanStatic ,
138+ query_state,
151139 )
152140 }
153141}
154142
155- /// If this flag is true, then all free regions will be replaced with
156- /// a canonical var. This is used to make queries as generic as
157- /// possible. For example, the query `F: Foo<'static>` would be
158- /// canonicalized to `F: Foo<'0>`.
159- struct CanonicalizeRegionMode {
160- static_region : bool ,
161- other_free_regions : bool ,
143+ /// Controls how we canonicalize "free regions" that are not inference
144+ /// variables. This depends on what we are canonicalizing *for* --
145+ /// e.g., if we are canonicalizing to create a query, we want to
146+ /// replace those with inference variables, since we want to make a
147+ /// maximally general query. But if we are canonicalizing a *query
148+ /// response*, then we don't typically replace free regions, as they
149+ /// must have been introduced from other parts of the system.
150+ trait CanonicalizeRegionMode {
151+ fn canonicalize_free_region (
152+ & self ,
153+ canonicalizer : & mut Canonicalizer < ' _ , ' _ , ' tcx > ,
154+ r : ty:: Region < ' tcx > ,
155+ ) -> ty:: Region < ' tcx > ;
156+
157+ fn any ( & self ) -> bool ;
158+ }
159+
160+ struct CanonicalizeQueryResponse ;
161+
162+ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
163+ fn canonicalize_free_region (
164+ & self ,
165+ _canonicalizer : & mut Canonicalizer < ' _ , ' _ , ' tcx > ,
166+ r : ty:: Region < ' tcx > ,
167+ ) -> ty:: Region < ' tcx > {
168+ match r {
169+ ty:: ReFree ( _) | ty:: ReEmpty | ty:: ReErased | ty:: ReStatic | ty:: ReEarlyBound ( ..) => r,
170+ _ => {
171+ // Other than `'static` or `'empty`, the query
172+ // response should be executing in a fully
173+ // canonicalized environment, so there shouldn't be
174+ // any other region names it can come up.
175+ bug ! ( "unexpected region in query response: `{:?}`" , r)
176+ }
177+ }
178+ }
179+
180+ fn any ( & self ) -> bool {
181+ false
182+ }
162183}
163184
164- impl CanonicalizeRegionMode {
185+ struct CanonicalizeAllFreeRegions ;
186+
187+ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
188+ fn canonicalize_free_region (
189+ & self ,
190+ canonicalizer : & mut Canonicalizer < ' _ , ' _ , ' tcx > ,
191+ r : ty:: Region < ' tcx > ,
192+ ) -> ty:: Region < ' tcx > {
193+ canonicalizer. canonical_var_for_region ( r)
194+ }
195+
165196 fn any ( & self ) -> bool {
166- self . static_region || self . other_free_regions
197+ true
198+ }
199+ }
200+
201+ struct CanonicalizeFreeRegionsOtherThanStatic ;
202+
203+ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
204+ fn canonicalize_free_region (
205+ & self ,
206+ canonicalizer : & mut Canonicalizer < ' _ , ' _ , ' tcx > ,
207+ r : ty:: Region < ' tcx > ,
208+ ) -> ty:: Region < ' tcx > {
209+ if let ty:: ReStatic = r {
210+ r
211+ } else {
212+ canonicalizer. canonical_var_for_region ( r)
213+ }
214+ }
215+
216+ fn any ( & self ) -> bool {
217+ true
167218 }
168219}
169220
170221struct Canonicalizer < ' cx , ' gcx : ' tcx , ' tcx : ' cx > {
171222 infcx : Option < & ' cx InferCtxt < ' cx , ' gcx , ' tcx > > ,
172223 tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
173224 variables : SmallVec < [ CanonicalVarInfo ; 8 ] > ,
174- var_values : & ' cx mut SmallCanonicalVarValues < ' tcx > ,
225+ query_state : & ' cx mut OriginalQueryValues < ' tcx > ,
175226 // Note that indices is only used once `var_values` is big enough to be
176227 // heap-allocated.
177228 indices : FxHashMap < Kind < ' tcx > , CanonicalVar > ,
178- canonicalize_region_mode : CanonicalizeRegionMode ,
229+ canonicalize_region_mode : & ' cx dyn CanonicalizeRegionMode ,
179230 needs_canonical_flags : TypeFlags ,
180231}
181232
@@ -192,51 +243,25 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
192243 }
193244
194245 ty:: ReVar ( vid) => {
195- let r = self
196- . infcx
246+ let r = self . infcx
197247 . unwrap ( )
198248 . borrow_region_constraints ( )
199249 . opportunistic_resolve_var ( self . tcx , vid) ;
200- let info = CanonicalVarInfo {
201- kind : CanonicalVarKind :: Region ,
202- } ;
203250 debug ! (
204251 "canonical: region var found with vid {:?}, \
205252 opportunistically resolved to {:?}",
206253 vid, r
207254 ) ;
208- let cvar = self . canonical_var ( info, r. into ( ) ) ;
209- self . tcx ( ) . mk_region ( ty:: ReCanonical ( cvar) )
210- }
211-
212- ty:: ReStatic => {
213- if self . canonicalize_region_mode . static_region {
214- let info = CanonicalVarInfo {
215- kind : CanonicalVarKind :: Region ,
216- } ;
217- let cvar = self . canonical_var ( info, r. into ( ) ) ;
218- self . tcx ( ) . mk_region ( ty:: ReCanonical ( cvar) )
219- } else {
220- r
221- }
255+ self . canonical_var_for_region ( r)
222256 }
223257
224- ty:: ReEarlyBound ( ..)
258+ ty:: ReStatic
259+ | ty:: ReEarlyBound ( ..)
225260 | ty:: ReFree ( _)
226261 | ty:: ReScope ( _)
227262 | ty:: RePlaceholder ( ..)
228263 | ty:: ReEmpty
229- | ty:: ReErased => {
230- if self . canonicalize_region_mode . other_free_regions {
231- let info = CanonicalVarInfo {
232- kind : CanonicalVarKind :: Region ,
233- } ;
234- let cvar = self . canonical_var ( info, r. into ( ) ) ;
235- self . tcx ( ) . mk_region ( ty:: ReCanonical ( cvar) )
236- } else {
237- r
238- }
239- }
264+ | ty:: ReErased => self . canonicalize_region_mode . canonicalize_free_region ( self , r) ,
240265
241266 ty:: ReClosureBound ( ..) | ty:: ReCanonical ( _) => {
242267 bug ! ( "canonical region encountered during canonicalization" )
@@ -302,10 +327,10 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
302327 /// `canonicalize_query` and `canonicalize_response`.
303328 fn canonicalize < V > (
304329 value : & V ,
305- infcx : Option < & ' cx InferCtxt < ' cx , ' gcx , ' tcx > > ,
306- tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
307- canonicalize_region_mode : CanonicalizeRegionMode ,
308- var_values : & ' cx mut SmallCanonicalVarValues < ' tcx >
330+ infcx : Option < & InferCtxt < ' _ , ' gcx , ' tcx > > ,
331+ tcx : TyCtxt < ' _ , ' gcx , ' tcx > ,
332+ canonicalize_region_mode : & dyn CanonicalizeRegionMode ,
333+ query_state : & mut OriginalQueryValues < ' tcx > ,
309334 ) -> Canonicalized < ' gcx , V >
310335 where
311336 V : TypeFoldable < ' tcx > + Lift < ' gcx > ,
@@ -340,7 +365,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
340365 canonicalize_region_mode,
341366 needs_canonical_flags,
342367 variables : SmallVec :: new ( ) ,
343- var_values ,
368+ query_state ,
344369 indices : FxHashMap :: default ( ) ,
345370 } ;
346371 let out_value = value. fold_with ( & mut canonicalizer) ;
@@ -371,11 +396,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
371396 fn canonical_var ( & mut self , info : CanonicalVarInfo , kind : Kind < ' tcx > ) -> CanonicalVar {
372397 let Canonicalizer {
373398 variables,
374- var_values ,
399+ query_state ,
375400 indices,
376401 ..
377402 } = self ;
378403
404+ let var_values = & mut query_state. var_values ;
405+
379406 // This code is hot. `variables` and `var_values` are usually small
380407 // (fewer than 8 elements ~95% of the time). They are SmallVec's to
381408 // avoid allocations in those cases. We also don't use `indices` to
@@ -398,28 +425,34 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
398425 // fill up `indices` to facilitate subsequent lookups.
399426 if var_values. spilled ( ) {
400427 assert ! ( indices. is_empty( ) ) ;
401- * indices =
402- var_values . iter ( )
403- . enumerate ( )
404- . map ( |( i, & kind) | ( kind, CanonicalVar :: new ( i) ) )
405- . collect ( ) ;
428+ * indices = var_values
429+ . iter ( )
430+ . enumerate ( )
431+ . map ( |( i, & kind) | ( kind, CanonicalVar :: new ( i) ) )
432+ . collect ( ) ;
406433 }
407434 // The cv is the index of the appended element.
408435 CanonicalVar :: new ( var_values. len ( ) - 1 )
409436 }
410437 } else {
411438 // `var_values` is large. Do a hashmap search via `indices`.
412- * indices
413- . entry ( kind)
414- . or_insert_with ( || {
415- variables. push ( info) ;
416- var_values. push ( kind) ;
417- assert_eq ! ( variables. len( ) , var_values. len( ) ) ;
418- CanonicalVar :: new ( variables. len ( ) - 1 )
419- } )
439+ * indices. entry ( kind) . or_insert_with ( || {
440+ variables. push ( info) ;
441+ var_values. push ( kind) ;
442+ assert_eq ! ( variables. len( ) , var_values. len( ) ) ;
443+ CanonicalVar :: new ( variables. len ( ) - 1 )
444+ } )
420445 }
421446 }
422447
448+ fn canonical_var_for_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
449+ let info = CanonicalVarInfo {
450+ kind : CanonicalVarKind :: Region ,
451+ } ;
452+ let cvar = self . canonical_var ( info, r. into ( ) ) ;
453+ self . tcx ( ) . mk_region ( ty:: ReCanonical ( cvar) )
454+ }
455+
423456 /// Given a type variable `ty_var` of the given kind, first check
424457 /// if `ty_var` is bound to anything; if so, canonicalize
425458 /// *that*. Otherwise, create a new canonical variable for
0 commit comments