Skip to content

Commit dd8e744

Browse files
committed
introduce canonicalize_hr_query_hack
As the comment explains, this is needed to prevent subtype from going awry in higher-ranked cases, due to rust-lang#33684. The proper fix here is introducing universes (rust-lang#48536).
1 parent 9b5dcbe commit dd8e744

File tree

2 files changed

+74
-11
lines changed

2 files changed

+74
-11
lines changed

src/librustc/infer/canonical/canonicalizer.rs

+69-10
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
6161
value,
6262
Some(self),
6363
self.tcx,
64-
CanonicalizeAllFreeRegions(true),
64+
CanonicalizeRegionMode {
65+
static_region: true,
66+
other_free_regions: true,
67+
},
6568
)
6669
}
6770

@@ -101,7 +104,43 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
101104
value,
102105
Some(self),
103106
self.tcx,
104-
CanonicalizeAllFreeRegions(false),
107+
CanonicalizeRegionMode {
108+
static_region: false,
109+
other_free_regions: false,
110+
},
111+
)
112+
}
113+
114+
/// A hacky variant of `canonicalize_query` that does not
115+
/// canonicalize `'static`. Unfortunately, the existing leak
116+
/// check treaks `'static` differently in some cases (see also
117+
/// #33684), so if we are performing an operation that may need to
118+
/// prove "leak-check" related things, we leave `'static`
119+
/// alone.
120+
///
121+
/// FIXME(#48536) -- once we have universes, we can remove this and just use
122+
/// `canonicalize_query`.
123+
pub fn canonicalize_hr_query_hack<V>(
124+
&self,
125+
value: &V,
126+
) -> (Canonicalized<'gcx, V>, CanonicalVarValues<'tcx>)
127+
where
128+
V: TypeFoldable<'tcx> + Lift<'gcx>,
129+
{
130+
self.tcx
131+
.sess
132+
.perf_stats
133+
.queries_canonicalized
134+
.fetch_add(1, Ordering::Relaxed);
135+
136+
Canonicalizer::canonicalize(
137+
value,
138+
Some(self),
139+
self.tcx,
140+
CanonicalizeRegionMode {
141+
static_region: false,
142+
other_free_regions: true,
143+
},
105144
)
106145
}
107146
}
@@ -110,15 +149,24 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
110149
/// a canonical var. This is used to make queries as generic as
111150
/// possible. For example, the query `F: Foo<'static>` would be
112151
/// canonicalized to `F: Foo<'0>`.
113-
struct CanonicalizeAllFreeRegions(pub bool);
152+
struct CanonicalizeRegionMode {
153+
static_region: bool,
154+
other_free_regions: bool,
155+
}
156+
157+
impl CanonicalizeRegionMode {
158+
fn any(&self) -> bool {
159+
self.static_region || self.other_free_regions
160+
}
161+
}
114162

115163
struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
116164
infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
117165
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
118166
variables: IndexVec<CanonicalVar, CanonicalVarInfo>,
119167
indices: FxHashMap<Kind<'tcx>, CanonicalVar>,
120168
var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
121-
canonicalize_all_free_regions: CanonicalizeAllFreeRegions,
169+
canonicalize_region_mode: CanonicalizeRegionMode,
122170
needs_canonical_flags: TypeFlags,
123171
}
124172

@@ -152,14 +200,25 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
152200
self.tcx().mk_region(ty::ReCanonical(cvar))
153201
}
154202

155-
ty::ReStatic
156-
| ty::ReEarlyBound(..)
203+
ty::ReStatic => {
204+
if self.canonicalize_region_mode.static_region {
205+
let info = CanonicalVarInfo {
206+
kind: CanonicalVarKind::Region,
207+
};
208+
let cvar = self.canonical_var(info, r.into());
209+
self.tcx().mk_region(ty::ReCanonical(cvar))
210+
} else {
211+
r
212+
}
213+
}
214+
215+
ty::ReEarlyBound(..)
157216
| ty::ReFree(_)
158217
| ty::ReScope(_)
159218
| ty::ReSkolemized(..)
160219
| ty::ReEmpty
161220
| ty::ReErased => {
162-
if self.canonicalize_all_free_regions.0 {
221+
if self.canonicalize_region_mode.other_free_regions {
163222
let info = CanonicalVarInfo {
164223
kind: CanonicalVarKind::Region,
165224
};
@@ -235,7 +294,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
235294
value: &V,
236295
infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
237296
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
238-
canonicalize_all_free_regions: CanonicalizeAllFreeRegions,
297+
canonicalize_region_mode: CanonicalizeRegionMode,
239298
) -> (Canonicalized<'gcx, V>, CanonicalVarValues<'tcx>)
240299
where
241300
V: TypeFoldable<'tcx> + Lift<'gcx>,
@@ -246,7 +305,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
246305
value,
247306
);
248307

249-
let needs_canonical_flags = if canonicalize_all_free_regions.0 {
308+
let needs_canonical_flags = if canonicalize_region_mode.any() {
250309
TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX
251310
} else {
252311
TypeFlags::KEEP_IN_LOCAL_TCX
@@ -270,7 +329,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
270329
let mut canonicalizer = Canonicalizer {
271330
infcx,
272331
tcx,
273-
canonicalize_all_free_regions,
332+
canonicalize_region_mode,
274333
needs_canonical_flags,
275334
variables: IndexVec::default(),
276335
indices: FxHashMap::default(),

src/librustc/traits/query/type_op/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,11 @@ where
132132
fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
133133
let param_env = self.param_env();
134134

135-
let (canonical_self, canonical_var_values) = infcx.canonicalize_query(&self);
135+
// FIXME(#33684) -- We need to use
136+
// `canonicalize_hr_query_hack` here because of things like
137+
// the subtype query, which go awry around `'static`
138+
// otherwise.
139+
let (canonical_self, canonical_var_values) = infcx.canonicalize_hr_query_hack(&self);
136140
let canonical_result = Q::perform_query(infcx.tcx, canonical_self);
137141

138142
// FIXME: This is not the most efficient setup. The

0 commit comments

Comments
 (0)