17
17
18
18
use infer:: canonical:: {
19
19
Canonical , CanonicalTyVarKind , CanonicalVarInfo , CanonicalVarKind , Canonicalized ,
20
- SmallCanonicalVarValues ,
20
+ OriginalQueryValues ,
21
21
} ;
22
22
use infer:: InferCtxt ;
23
23
use std:: sync:: atomic:: Ordering ;
@@ -48,7 +48,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
48
48
pub fn canonicalize_query < V > (
49
49
& self ,
50
50
value : & V ,
51
- var_values : & mut SmallCanonicalVarValues < ' tcx >
51
+ query_state : & mut OriginalQueryValues < ' tcx > ,
52
52
) -> Canonicalized < ' gcx , V >
53
53
where
54
54
V : TypeFoldable < ' tcx > + Lift < ' gcx > ,
@@ -63,11 +63,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
63
63
value,
64
64
Some ( self ) ,
65
65
self . tcx ,
66
- CanonicalizeRegionMode {
67
- static_region : true ,
68
- other_free_regions : true ,
69
- } ,
70
- var_values,
66
+ & CanonicalizeAllFreeRegions ,
67
+ query_state,
71
68
)
72
69
}
73
70
@@ -96,23 +93,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
96
93
/// out the [chapter in the rustc guide][c].
97
94
///
98
95
/// [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 >
103
97
where
104
98
V : TypeFoldable < ' tcx > + Lift < ' gcx > ,
105
99
{
106
- let mut var_values = SmallVec :: new ( ) ;
100
+ let mut query_state = OriginalQueryValues :: default ( ) ;
107
101
Canonicalizer :: canonicalize (
108
102
value,
109
103
Some ( self ) ,
110
104
self . tcx ,
111
- CanonicalizeRegionMode {
112
- static_region : false ,
113
- other_free_regions : false ,
114
- } ,
115
- & mut var_values
105
+ & CanonicalizeQueryResponse ,
106
+ & mut query_state,
116
107
)
117
108
}
118
109
@@ -128,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
128
119
pub fn canonicalize_hr_query_hack < V > (
129
120
& self ,
130
121
value : & V ,
131
- var_values : & mut SmallCanonicalVarValues < ' tcx >
122
+ query_state : & mut OriginalQueryValues < ' tcx > ,
132
123
) -> Canonicalized < ' gcx , V >
133
124
where
134
125
V : TypeFoldable < ' tcx > + Lift < ' gcx > ,
@@ -143,39 +134,99 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
143
134
value,
144
135
Some ( self ) ,
145
136
self . tcx ,
146
- CanonicalizeRegionMode {
147
- static_region : false ,
148
- other_free_regions : true ,
149
- } ,
150
- var_values
137
+ & CanonicalizeFreeRegionsOtherThanStatic ,
138
+ query_state,
151
139
)
152
140
}
153
141
}
154
142
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
+ }
162
183
}
163
184
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
+
165
196
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
167
218
}
168
219
}
169
220
170
221
struct Canonicalizer < ' cx , ' gcx : ' tcx , ' tcx : ' cx > {
171
222
infcx : Option < & ' cx InferCtxt < ' cx , ' gcx , ' tcx > > ,
172
223
tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
173
224
variables : SmallVec < [ CanonicalVarInfo ; 8 ] > ,
174
- var_values : & ' cx mut SmallCanonicalVarValues < ' tcx > ,
225
+ query_state : & ' cx mut OriginalQueryValues < ' tcx > ,
175
226
// Note that indices is only used once `var_values` is big enough to be
176
227
// heap-allocated.
177
228
indices : FxHashMap < Kind < ' tcx > , CanonicalVar > ,
178
- canonicalize_region_mode : CanonicalizeRegionMode ,
229
+ canonicalize_region_mode : & ' cx dyn CanonicalizeRegionMode ,
179
230
needs_canonical_flags : TypeFlags ,
180
231
}
181
232
@@ -192,51 +243,25 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
192
243
}
193
244
194
245
ty:: ReVar ( vid) => {
195
- let r = self
196
- . infcx
246
+ let r = self . infcx
197
247
. unwrap ( )
198
248
. borrow_region_constraints ( )
199
249
. opportunistic_resolve_var ( self . tcx , vid) ;
200
- let info = CanonicalVarInfo {
201
- kind : CanonicalVarKind :: Region ,
202
- } ;
203
250
debug ! (
204
251
"canonical: region var found with vid {:?}, \
205
252
opportunistically resolved to {:?}",
206
253
vid, r
207
254
) ;
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)
222
256
}
223
257
224
- ty:: ReEarlyBound ( ..)
258
+ ty:: ReStatic
259
+ | ty:: ReEarlyBound ( ..)
225
260
| ty:: ReFree ( _)
226
261
| ty:: ReScope ( _)
227
262
| ty:: RePlaceholder ( ..)
228
263
| 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) ,
240
265
241
266
ty:: ReClosureBound ( ..) | ty:: ReCanonical ( _) => {
242
267
bug ! ( "canonical region encountered during canonicalization" )
@@ -302,10 +327,10 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
302
327
/// `canonicalize_query` and `canonicalize_response`.
303
328
fn canonicalize < V > (
304
329
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 > ,
309
334
) -> Canonicalized < ' gcx , V >
310
335
where
311
336
V : TypeFoldable < ' tcx > + Lift < ' gcx > ,
@@ -340,7 +365,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
340
365
canonicalize_region_mode,
341
366
needs_canonical_flags,
342
367
variables : SmallVec :: new ( ) ,
343
- var_values ,
368
+ query_state ,
344
369
indices : FxHashMap :: default ( ) ,
345
370
} ;
346
371
let out_value = value. fold_with ( & mut canonicalizer) ;
@@ -371,11 +396,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
371
396
fn canonical_var ( & mut self , info : CanonicalVarInfo , kind : Kind < ' tcx > ) -> CanonicalVar {
372
397
let Canonicalizer {
373
398
variables,
374
- var_values ,
399
+ query_state ,
375
400
indices,
376
401
..
377
402
} = self ;
378
403
404
+ let var_values = & mut query_state. var_values ;
405
+
379
406
// This code is hot. `variables` and `var_values` are usually small
380
407
// (fewer than 8 elements ~95% of the time). They are SmallVec's to
381
408
// avoid allocations in those cases. We also don't use `indices` to
@@ -398,28 +425,34 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
398
425
// fill up `indices` to facilitate subsequent lookups.
399
426
if var_values. spilled ( ) {
400
427
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 ( ) ;
406
433
}
407
434
// The cv is the index of the appended element.
408
435
CanonicalVar :: new ( var_values. len ( ) - 1 )
409
436
}
410
437
} else {
411
438
// `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
+ } )
420
445
}
421
446
}
422
447
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
+
423
456
/// Given a type variable `ty_var` of the given kind, first check
424
457
/// if `ty_var` is bound to anything; if so, canonicalize
425
458
/// *that*. Otherwise, create a new canonical variable for
0 commit comments