Skip to content

Commit

Permalink
Auto merge of #55921 - scalexm:placeholders, r=nikomatsakis
Browse files Browse the repository at this point in the history
Add placeholder types

Fixes #48696 (handle universes in canonicalization of type inference vars), and fixes #55098.
  • Loading branch information
bors committed Nov 25, 2018
2 parents 37961db + b8a30f0 commit abe19a7
Show file tree
Hide file tree
Showing 52 changed files with 414 additions and 212 deletions.
9 changes: 7 additions & 2 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,9 +684,13 @@ for ty::TyKind<'gcx>
Param(param_ty) => {
param_ty.hash_stable(hcx, hasher);
}
Bound(bound_ty) => {
Bound(debruijn, bound_ty) => {
debruijn.hash_stable(hcx, hasher);
bound_ty.hash_stable(hcx, hasher);
}
ty::Placeholder(placeholder_ty) => {
placeholder_ty.hash_stable(hcx, hasher);
}
Foreign(def_id) => {
def_id.hash_stable(hcx, hasher);
}
Expand Down Expand Up @@ -1096,12 +1100,13 @@ impl_stable_hash_for!(struct infer::canonical::CanonicalVarInfo {

impl_stable_hash_for!(enum infer::canonical::CanonicalVarKind {
Ty(k),
PlaceholderTy(placeholder),
Region(ui),
PlaceholderRegion(placeholder),
});

impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind {
General,
General(ui),
Int,
Float
});
Expand Down
58 changes: 45 additions & 13 deletions src/librustc/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use infer::InferCtxt;
use std::sync::atomic::Ordering;
use ty::fold::{TypeFoldable, TypeFolder};
use ty::subst::Kind;
use ty::{self, BoundTy, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};
use ty::{self, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};

use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
Expand Down Expand Up @@ -339,20 +339,51 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match t.sty {
ty::Infer(ty::TyVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::General, t),
ty::Infer(ty::TyVar(vid)) => {
match self.infcx.unwrap().probe_ty_var(vid) {
// `t` could be a float / int variable: canonicalize that instead
Ok(t) => self.fold_ty(t),

// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
// result
Err(ui) => self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
},
t
)
}
}

ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Int, t),
ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
},
t
),

ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Float, t),
ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
},
t
),

ty::Infer(ty::FreshTy(_))
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")
}

ty::Bound(bound_ty) => {
if bound_ty.index >= self.binder_index {
ty::Placeholder(placeholder) => self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::PlaceholderTy(placeholder)
},
t
),

ty::Bound(debruijn, _) => {
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
t
Expand Down Expand Up @@ -408,9 +439,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
V: TypeFoldable<'tcx> + Lift<'gcx>,
{
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX
TypeFlags::KEEP_IN_LOCAL_TCX |
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
TypeFlags::HAS_TY_PLACEHOLDER
} else {
TypeFlags::KEEP_IN_LOCAL_TCX
TypeFlags::KEEP_IN_LOCAL_TCX |
TypeFlags::HAS_RE_PLACEHOLDER |
TypeFlags::HAS_TY_PLACEHOLDER
};

let gcx = tcx.global_tcx();
Expand Down Expand Up @@ -574,17 +609,14 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
/// if `ty_var` is bound to anything; if so, canonicalize
/// *that*. Otherwise, create a new canonical variable for
/// `ty_var`.
fn canonicalize_ty_var(&mut self, ty_kind: CanonicalTyVarKind, ty_var: Ty<'tcx>) -> Ty<'tcx> {
fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> {
let infcx = self.infcx.expect("encountered ty-var without infcx");
let bound_to = infcx.shallow_resolve(ty_var);
if bound_to != ty_var {
self.fold_ty(bound_to)
} else {
let info = CanonicalVarInfo {
kind: CanonicalVarKind::Ty(ty_kind),
};
let var = self.canonical_var(info, ty_var.into());
self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var)))
self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
}
}
}
42 changes: 28 additions & 14 deletions src/librustc/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ impl CanonicalVarInfo {
pub fn is_existential(&self) -> bool {
match self.kind {
CanonicalVarKind::Ty(_) => true,
CanonicalVarKind::PlaceholderTy(_) => false,
CanonicalVarKind::Region(_) => true,
CanonicalVarKind::PlaceholderRegion(..) => false,
}
Expand All @@ -136,24 +137,27 @@ pub enum CanonicalVarKind {
/// Some kind of type inference variable.
Ty(CanonicalTyVarKind),

/// A "placeholder" that represents "any type".
PlaceholderTy(ty::PlaceholderType),

/// Region variable `'?R`.
Region(ty::UniverseIndex),

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

impl CanonicalVarKind {
pub fn universe(self) -> ty::UniverseIndex {
match self {
// At present, we don't support higher-ranked
// quantification over types, so all type variables are in
// the root universe.
CanonicalVarKind::Ty(_) => ty::UniverseIndex::ROOT,
CanonicalVarKind::Ty(kind) => match kind {
CanonicalTyVarKind::General(ui) => ui,
CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
}

// Region variables can be created in sub-universes.
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
}
Expand All @@ -168,7 +172,7 @@ impl CanonicalVarKind {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub enum CanonicalTyVarKind {
/// General type variable `?T` that can be unified with arbitrary types.
General,
General(ty::UniverseIndex),

/// Integral type variable `?I` (that can only be unified with integral types).
Int,
Expand Down Expand Up @@ -358,8 +362,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
match cv_info.kind {
CanonicalVarKind::Ty(ty_kind) => {
let ty = match ty_kind {
CanonicalTyVarKind::General => {
self.next_ty_var(TypeVariableOrigin::MiscVariable(span))
CanonicalTyVarKind::General(ui) => {
self.next_ty_var_in_universe(
TypeVariableOrigin::MiscVariable(span),
universe_map(ui)
)
}

CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()),
Expand All @@ -369,20 +376,27 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
ty.into()
}

CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, name }) => {
let universe_mapped = universe_map(universe);
let placeholder_mapped = ty::PlaceholderType {
universe: universe_mapped,
name,
};
self.tcx.mk_ty(ty::Placeholder(placeholder_mapped)).into()
}

CanonicalVarKind::Region(ui) => self.next_region_var_in_universe(
RegionVariableOrigin::MiscVariable(span),
universe_map(ui),
).into(),

CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe, name }) => {
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, name }) => {
let universe_mapped = universe_map(universe);
let placeholder_mapped = ty::Placeholder {
let placeholder_mapped = ty::PlaceholderRegion {
universe: universe_mapped,
name,
};
self.tcx
.mk_region(ty::RePlaceholder(placeholder_mapped))
.into()
self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,21 +435,21 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
match result_value.unpack() {
UnpackedKind::Type(result_value) => {
// e.g., here `result_value` might be `?0` in the example above...
if let ty::Bound(b) = result_value.sty {
if let ty::Bound(debruijn, b) = result_value.sty {
// ...in which case we would set `canonical_vars[0]` to `Some(?U)`.

// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(b.index, ty::INNERMOST);
assert_eq!(debruijn, ty::INNERMOST);
opt_values[b.var] = Some(*original_value);
}
}
UnpackedKind::Lifetime(result_value) => {
// e.g., here `result_value` might be `'?1` in the example above...
if let &ty::RegionKind::ReLateBound(index, br) = result_value {
if let &ty::RegionKind::ReLateBound(debruijn, br) = result_value {
// ... in which case we would set `canonical_vars[0]` to `Some('static)`.

// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(index, ty::INNERMOST);
assert_eq!(debruijn, ty::INNERMOST);
opt_values[br.assert_bound_var()] = Some(*original_value);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
t
}

ty::Bound(..) =>
bug!("encountered bound ty during freshening"),

ty::Generator(..) |
ty::Bool |
ty::Char |
Expand Down Expand Up @@ -200,6 +197,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::Opaque(..) => {
t.super_fold_with(self)
}

ty::Placeholder(..) |
ty::Bound(..) => bug!("unexpected type {:?}", t),
}
}
}
45 changes: 28 additions & 17 deletions src/librustc/infer/higher_ranked/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// First, we instantiate each bound region in the supertype with a
// fresh placeholder region.
let (b_prime, placeholder_map) =
self.infcx.replace_late_bound_regions_with_placeholders(b);
self.infcx.replace_bound_vars_with_placeholders(b);

// Next, we instantiate each bound region in the subtype
// with a fresh region variable. These region variables --
Expand Down Expand Up @@ -115,7 +115,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// First, we instantiate each bound region in the matcher
// with a placeholder region.
let ((a_match, a_value), placeholder_map) =
self.infcx.replace_late_bound_regions_with_placeholders(a_pair);
self.infcx.replace_bound_vars_with_placeholders(a_pair);

debug!("higher_ranked_match: a_match={:?}", a_match);
debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map);
Expand Down Expand Up @@ -314,10 +314,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
region_vars
}

/// Replace all regions bound by `binder` with placeholder regions and
/// return a map indicating which bound-region was replaced with what
/// placeholder region. This is the first step of checking subtyping
/// when higher-ranked things are involved.
/// Replace all regions (resp. types) bound by `binder` with placeholder
/// regions (resp. types) and return a map indicating which bound-region
/// was replaced with what placeholder region. This is the first step of
/// checking subtyping when higher-ranked things are involved.
///
/// **Important:** you must call this function from within a snapshot.
/// Moreover, before committing the snapshot, you must eventually call
Expand All @@ -330,26 +330,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// the [rustc guide].
///
/// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html
pub fn replace_late_bound_regions_with_placeholders<T>(
pub fn replace_bound_vars_with_placeholders<T>(
&self,
binder: &ty::Binder<T>,
binder: &ty::Binder<T>
) -> (T, PlaceholderMap<'tcx>)
where
T : TypeFoldable<'tcx>,
T: TypeFoldable<'tcx>
{
let next_universe = self.create_next_universe();

let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
self.tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
let fld_r = |br| {
self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
universe: next_universe,
name: br,
}))
});
};

let fld_t = |bound_ty: ty::BoundTy| {
self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: next_universe,
name: bound_ty.var,
}))
};

let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t);

debug!("replace_late_bound_regions_with_placeholders(binder={:?}, result={:?}, map={:?})",
binder,
result,
map);
debug!(
"replace_bound_vars_with_placeholders(binder={:?}, result={:?}, map={:?})",
binder,
result,
map
);

(result, map)
}
Expand Down Expand Up @@ -530,7 +541,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {

/// Pops the placeholder regions found in `placeholder_map` from the region
/// inference context. Whenever you create placeholder regions via
/// `replace_late_bound_regions_with_placeholders`, they must be popped before you
/// `replace_bound_vars_with_placeholders`, they must be popped before you
/// commit the enclosing snapshot (if you do not commit, e.g. within a
/// probe or as a result of an error, then this is not necessary, as
/// popping happens as part of the rollback).
Expand Down
Loading

0 comments on commit abe19a7

Please sign in to comment.