Skip to content

Commit 7f9ab60

Browse files
committed
extend query response to potentially contain fresh universes
The idea here is that an incoming query may refer to some universes, and they query response may contain fresh universes that go beyond those. When we instantiate the query response in the caller's scope, therefore, we map those new universes into fresh universes for the caller.
1 parent 3ef27d8 commit 7f9ab60

File tree

5 files changed

+144
-28
lines changed

5 files changed

+144
-28
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,7 @@ impl_stable_hash_for!(struct infer::canonical::CanonicalVarInfo {
12851285
impl_stable_hash_for!(enum infer::canonical::CanonicalVarKind {
12861286
Ty(k),
12871287
Region(ui),
1288+
PlaceholderRegion(placeholder),
12881289
});
12891290

12901291
impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind {

src/librustc/infer/canonical/canonicalizer.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,18 @@ struct CanonicalizeQueryResponse;
162162
impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
163163
fn canonicalize_free_region(
164164
&self,
165-
_canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
165+
canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
166166
r: ty::Region<'tcx>,
167167
) -> ty::Region<'tcx> {
168168
match r {
169169
ty::ReFree(_) | ty::ReEmpty | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
170+
ty::RePlaceholder(placeholder) => {
171+
let info = CanonicalVarInfo {
172+
kind: CanonicalVarKind::PlaceholderRegion(*placeholder),
173+
};
174+
let cvar = canonicalizer.canonical_var(info, r.into());
175+
canonicalizer.tcx.mk_region(ty::ReCanonical(cvar.var))
176+
}
170177
_ => {
171178
// Other than `'static` or `'empty`, the query
172179
// response should be executing in a fully
@@ -190,7 +197,7 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
190197
canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
191198
r: ty::Region<'tcx>,
192199
) -> ty::Region<'tcx> {
193-
canonicalizer.canonical_var_for_region(r)
200+
canonicalizer.canonical_var_for_region_in_root_universe(r)
194201
}
195202

196203
fn any(&self) -> bool {
@@ -209,7 +216,7 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
209216
if let ty::ReStatic = r {
210217
r
211218
} else {
212-
canonicalizer.canonical_var_for_region(r)
219+
canonicalizer.canonical_var_for_region_in_root_universe(r)
213220
}
214221
}
215222

@@ -252,7 +259,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
252259
opportunistically resolved to {:?}",
253260
vid, r
254261
);
255-
self.canonical_var_for_region(r)
262+
self.canonical_var_for_region_in_root_universe(r)
256263
}
257264

258265
ty::ReStatic
@@ -459,9 +466,23 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
459466
}
460467
}
461468

462-
fn canonical_var_for_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
463-
// TODO: root is not always what we want here, but we'll
464-
// address that in a later commit.
469+
/// Shorthand helper that creates a canonical region variable for
470+
/// `r` (always in the root universe). The reason that we always
471+
/// put these variables into the root universe is because this
472+
/// method is used during **query construction:** in that case, we
473+
/// are taking all the regions and just putting them into the most
474+
/// generic context we can. This may generate solutions that don't
475+
/// fit (e.g., that equate some region variable with a placeholder
476+
/// it can't name) on the caller side, but that's ok, the caller
477+
/// can figure that out. In the meantime, it maximizes our
478+
/// caching.
479+
///
480+
/// (This works because unification never fails -- and hence trait
481+
/// selection is never affected -- due to a universe mismatch.)
482+
fn canonical_var_for_region_in_root_universe(
483+
&mut self,
484+
r: ty::Region<'tcx>,
485+
) -> ty::Region<'tcx> {
465486
let info = CanonicalVarInfo {
466487
kind: CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
467488
};

src/librustc/infer/canonical/mod.rs

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@
3333
3434
use infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin};
3535
use rustc_data_structures::indexed_vec::IndexVec;
36-
use smallvec::SmallVec;
3736
use rustc_data_structures::sync::Lrc;
3837
use serialize::UseSpecializedDecodable;
38+
use smallvec::SmallVec;
3939
use std::ops::Index;
4040
use syntax::source_map::Span;
4141
use ty::fold::TypeFoldable;
4242
use ty::subst::Kind;
43-
use ty::{self, BoundTyIndex, Lift, Region, List, TyCtxt};
43+
use ty::{self, BoundTyIndex, Lift, List, Region, TyCtxt};
4444

4545
mod canonicalizer;
4646

@@ -80,13 +80,31 @@ pub struct CanonicalVarValues<'tcx> {
8080
/// various parts of it with canonical variables. This struct stores
8181
/// those replaced bits to remember for when we process the query
8282
/// result.
83-
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
83+
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
8484
pub struct OriginalQueryValues<'tcx> {
85+
/// Map from the universes that appear in the query to the
86+
/// universes in the caller context. For the time being, we only
87+
/// ever put ROOT values into the query, so this map is very
88+
/// simple.
89+
pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
90+
8591
/// This is equivalent to `CanonicalVarValues`, but using a
8692
/// `SmallVec` yields a significant performance win.
8793
pub var_values: SmallVec<[Kind<'tcx>; 8]>,
8894
}
8995

96+
impl Default for OriginalQueryValues<'tcx> {
97+
fn default() -> Self {
98+
let mut universe_map = SmallVec::default();
99+
universe_map.push(ty::UniverseIndex::ROOT);
100+
101+
Self {
102+
universe_map,
103+
var_values: SmallVec::default(),
104+
}
105+
}
106+
}
107+
90108
/// Information about a canonical variable that is included with the
91109
/// canonical value. This is sufficient information for code to create
92110
/// a copy of the canonical value in some other inference context,
@@ -97,9 +115,17 @@ pub struct CanonicalVarInfo {
97115
}
98116

99117
impl CanonicalVarInfo {
100-
pub fn universe(self) -> ty::UniverseIndex {
118+
pub fn universe(&self) -> ty::UniverseIndex {
101119
self.kind.universe()
102120
}
121+
122+
pub fn is_existential(&self) -> bool {
123+
match self.kind {
124+
CanonicalVarKind::Ty(_) => true,
125+
CanonicalVarKind::Region(_) => true,
126+
CanonicalVarKind::PlaceholderRegion(..) => false,
127+
}
128+
}
103129
}
104130

105131
/// Describes the "kind" of the canonical variable. This is a "kind"
@@ -112,8 +138,12 @@ pub enum CanonicalVarKind {
112138

113139
/// Region variable `'?R`.
114140
Region(ty::UniverseIndex),
115-
}
116141

142+
/// A "placeholder" that represents "any region". Created when you
143+
/// are solving a goal like `for<'a> T: Foo<'a>` to represent the
144+
/// bound region `'a`.
145+
PlaceholderRegion(ty::Placeholder),
146+
}
117147

118148
impl CanonicalVarKind {
119149
pub fn universe(self) -> ty::UniverseIndex {
@@ -125,6 +155,7 @@ impl CanonicalVarKind {
125155

126156
// Region variables can be created in sub-universes.
127157
CanonicalVarKind::Region(ui) => ui,
158+
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
128159
}
129160
}
130161
}
@@ -242,8 +273,16 @@ impl<'gcx, V> Canonical<'gcx, V> {
242273
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
243274
/// ```
244275
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> {
245-
let Canonical { max_universe, variables, value } = self;
246-
Canonical { max_universe, variables, value: map_op(value) }
276+
let Canonical {
277+
max_universe,
278+
variables,
279+
value,
280+
} = self;
281+
Canonical {
282+
max_universe,
283+
variables,
284+
value: map_op(value),
285+
}
247286
}
248287
}
249288

@@ -271,35 +310,50 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
271310
where
272311
T: TypeFoldable<'tcx>,
273312
{
313+
// For each universe that is referred to in the incoming
314+
// query, create a universe in our local inference context. In
315+
// practice, as of this writing, all queries have no universes
316+
// in them, so this code has no effect, but it is looking
317+
// forward to the day when we *do* want to carry universes
318+
// through into queries.
319+
let universes: IndexVec<ty::UniverseIndex, _> = std::iter::once(ty::UniverseIndex::ROOT)
320+
.chain((0..canonical.max_universe.as_u32()).map(|_| self.create_next_universe()))
321+
.collect();
322+
274323
let canonical_inference_vars =
275-
self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
324+
self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
276325
let result = canonical.substitute(self.tcx, &canonical_inference_vars);
277326
(result, canonical_inference_vars)
278327
}
279328

280329
/// Given the "infos" about the canonical variables from some
281-
/// canonical, creates fresh inference variables with the same
282-
/// characteristics. You can then use `substitute` to instantiate
283-
/// the canonical variable with these inference variables.
284-
fn fresh_inference_vars_for_canonical_vars(
330+
/// canonical, creates fresh variables with the same
331+
/// characteristics (see `instantiate_canonical_var` for
332+
/// details). You can then use `substitute` to instantiate the
333+
/// canonical variable with these inference variables.
334+
fn instantiate_canonical_vars(
285335
&self,
286336
span: Span,
287337
variables: &List<CanonicalVarInfo>,
338+
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
288339
) -> CanonicalVarValues<'tcx> {
289340
let var_values: IndexVec<BoundTyIndex, Kind<'tcx>> = variables
290341
.iter()
291-
.map(|info| self.fresh_inference_var_for_canonical_var(span, *info))
342+
.map(|info| self.instantiate_canonical_var(span, *info, &universe_map))
292343
.collect();
293344

294345
CanonicalVarValues { var_values }
295346
}
296347

297348
/// Given the "info" about a canonical variable, creates a fresh
298-
/// inference variable with the same characteristics.
299-
fn fresh_inference_var_for_canonical_var(
349+
/// variable for it. If this is an existentially quantified
350+
/// variable, then you'll get a new inference variable; if it is a
351+
/// universally quantified variable, you get a placeholder.
352+
fn instantiate_canonical_var(
300353
&self,
301354
span: Span,
302355
cv_info: CanonicalVarInfo,
356+
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
303357
) -> Kind<'tcx> {
304358
match cv_info.kind {
305359
CanonicalVarKind::Ty(ty_kind) => {
@@ -315,9 +369,21 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
315369
ty.into()
316370
}
317371

318-
CanonicalVarKind::Region(ui) => self
319-
.next_region_var_in_universe(RegionVariableOrigin::MiscVariable(span), ui)
320-
.into(),
372+
CanonicalVarKind::Region(ui) => self.next_region_var_in_universe(
373+
RegionVariableOrigin::MiscVariable(span),
374+
universe_map(ui),
375+
).into(),
376+
377+
CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe, name }) => {
378+
let universe_mapped = universe_map(universe);
379+
let placeholder_mapped = ty::Placeholder {
380+
universe: universe_mapped,
381+
name,
382+
};
383+
self.tcx
384+
.mk_region(ty::RePlaceholder(placeholder_mapped))
385+
.into()
386+
}
321387
}
322388
}
323389
}

src/librustc/infer/canonical/query_response.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,21 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
394394
original_values, query_response,
395395
);
396396

397+
// For each new universe created in the query result that did
398+
// not appear in the original query, create a local
399+
// superuniverse.
400+
let mut universe_map = original_values.universe_map.clone();
401+
let num_universes_in_query = original_values.universe_map.len();
402+
let num_universes_in_response = query_response.max_universe.as_usize() + 1;
403+
for _ in num_universes_in_query..num_universes_in_response {
404+
universe_map.push(self.create_next_universe());
405+
}
406+
assert!(universe_map.len() >= 1); // always have the root universe
407+
assert_eq!(
408+
universe_map[ty::UniverseIndex::ROOT.as_usize()],
409+
ty::UniverseIndex::ROOT
410+
);
411+
397412
// Every canonical query result includes values for each of
398413
// the inputs to the query. Therefore, we begin by unifying
399414
// these values with the original inputs that were
@@ -440,9 +455,20 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
440455
.variables
441456
.iter()
442457
.enumerate()
443-
.map(|(index, info)| opt_values[BoundTyIndex::new(index)].unwrap_or_else(||
444-
self.fresh_inference_var_for_canonical_var(cause.span, *info)
445-
))
458+
.map(|(index, info)| {
459+
if info.is_existential() {
460+
match opt_values[BoundTyIndex::new(index)] {
461+
Some(k) => k,
462+
None => self.instantiate_canonical_var(cause.span, *info, |u| {
463+
universe_map[u.as_usize()]
464+
}),
465+
}
466+
} else {
467+
self.instantiate_canonical_var(cause.span, *info, |u| {
468+
universe_map[u.as_usize()]
469+
})
470+
}
471+
})
446472
.collect(),
447473
};
448474

src/librustc/ty/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,8 @@ pub struct Placeholder {
15401540
pub name: BoundRegion,
15411541
}
15421542

1543+
impl_stable_hash_for!(struct Placeholder { universe, name });
1544+
15431545
/// When type checking, we use the `ParamEnv` to track
15441546
/// details about the set of where-clauses that are in scope at this
15451547
/// particular point.

0 commit comments

Comments
 (0)