Skip to content

Commit 28df2bf

Browse files
committed
control canonicalization with a trait vs bools
1 parent 42a6618 commit 28df2bf

File tree

1 file changed

+83
-42
lines changed

1 file changed

+83
-42
lines changed

src/librustc/infer/canonical/canonicalizer.rs

Lines changed: 83 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,7 @@ 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-
},
66+
&CanonicalizeAllFreeRegions,
7067
var_values,
7168
)
7269
}
@@ -105,10 +102,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
105102
value,
106103
Some(self),
107104
self.tcx,
108-
CanonicalizeRegionMode {
109-
static_region: false,
110-
other_free_regions: false,
111-
},
105+
&CanonicalizeQueryResponse,
112106
&mut var_values,
113107
)
114108
}
@@ -140,27 +134,87 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
140134
value,
141135
Some(self),
142136
self.tcx,
143-
CanonicalizeRegionMode {
144-
static_region: false,
145-
other_free_regions: true,
146-
},
137+
&CanonicalizeFreeRegionsOtherThanStatic,
147138
var_values,
148139
)
149140
}
150141
}
151142

152-
/// If this flag is true, then all free regions will be replaced with
153-
/// a canonical var. This is used to make queries as generic as
154-
/// possible. For example, the query `F: Foo<'static>` would be
155-
/// canonicalized to `F: Foo<'0>`.
156-
struct CanonicalizeRegionMode {
157-
static_region: bool,
158-
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+
}
183+
}
184+
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+
196+
fn any(&self) -> bool {
197+
true
198+
}
159199
}
160200

161-
impl CanonicalizeRegionMode {
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+
162216
fn any(&self) -> bool {
163-
self.static_region || self.other_free_regions
217+
true
164218
}
165219
}
166220

@@ -172,7 +226,7 @@ struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
172226
// Note that indices is only used once `var_values` is big enough to be
173227
// heap-allocated.
174228
indices: FxHashMap<Kind<'tcx>, CanonicalVar>,
175-
canonicalize_region_mode: CanonicalizeRegionMode,
229+
canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
176230
needs_canonical_flags: TypeFlags,
177231
}
178232

@@ -201,26 +255,13 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
201255
self.canonical_var_for_region(r)
202256
}
203257

204-
ty::ReStatic => {
205-
if self.canonicalize_region_mode.static_region {
206-
self.canonical_var_for_region(r)
207-
} else {
208-
r
209-
}
210-
}
211-
212-
ty::ReEarlyBound(..)
258+
ty::ReStatic
259+
| ty::ReEarlyBound(..)
213260
| ty::ReFree(_)
214261
| ty::ReScope(_)
215262
| ty::RePlaceholder(..)
216263
| ty::ReEmpty
217-
| ty::ReErased => {
218-
if self.canonicalize_region_mode.other_free_regions {
219-
self.canonical_var_for_region(r)
220-
} else {
221-
r
222-
}
223-
}
264+
| ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
224265

225266
ty::ReClosureBound(..) | ty::ReCanonical(_) => {
226267
bug!("canonical region encountered during canonicalization")
@@ -286,10 +327,10 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
286327
/// `canonicalize_query` and `canonicalize_response`.
287328
fn canonicalize<V>(
288329
value: &V,
289-
infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
290-
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
291-
canonicalize_region_mode: CanonicalizeRegionMode,
292-
var_values: &'cx mut SmallCanonicalVarValues<'tcx>,
330+
infcx: Option<&InferCtxt<'_, 'gcx, 'tcx>>,
331+
tcx: TyCtxt<'_, 'gcx, 'tcx>,
332+
canonicalize_region_mode: &dyn CanonicalizeRegionMode,
333+
var_values: &mut SmallCanonicalVarValues<'tcx>,
293334
) -> Canonicalized<'gcx, V>
294335
where
295336
V: TypeFoldable<'tcx> + Lift<'gcx>,

0 commit comments

Comments
 (0)