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