Skip to content

Add placeholder types #55921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 25, 2018
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is a bug fix?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Seems unrelated to the rest of the commit)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er, wait, won't canonical_ty_var handle this already?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e., this logic here:

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 {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I guess the goal was to extract the ui?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes the goal was to extract the ui!

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