Skip to content
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

Add support for bound types #55330

Merged
merged 11 commits into from
Nov 3, 2018
9 changes: 4 additions & 5 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ for ty::RegionKind {
ty::ReEmpty => {
// No variant fields to hash for these ...
}
ty::ReCanonical(c) => {
c.hash_stable(hcx, hasher);
}
ty::ReLateBound(db, ty::BrAnon(i)) => {
db.hash_stable(hcx, hasher);
i.hash_stable(hcx, hasher);
Expand Down Expand Up @@ -147,7 +144,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionVid {
}
}

impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::BoundTyIndex {
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::BoundVar {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
Expand Down Expand Up @@ -852,6 +849,9 @@ for ty::TyKind<'gcx>
Param(param_ty) => {
param_ty.hash_stable(hcx, hasher);
}
Bound(bound_ty) => {
bound_ty.hash_stable(hcx, hasher);
}
Foreign(def_id) => {
def_id.hash_stable(hcx, hasher);
}
Expand All @@ -869,7 +869,6 @@ impl_stable_hash_for!(enum ty::InferTy {
FreshTy(a),
FreshIntTy(a),
FreshFloatTy(a),
BoundTy(a),
});

impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
Expand Down
72 changes: 42 additions & 30 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, BoundTyIndex, Lift, List, Ty, TyCtxt, TypeFlags};
use ty::{self, BoundTy, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};

use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
Expand Down Expand Up @@ -277,21 +277,35 @@ struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
query_state: &'cx mut OriginalQueryValues<'tcx>,
// Note that indices is only used once `var_values` is big enough to be
// heap-allocated.
indices: FxHashMap<Kind<'tcx>, BoundTyIndex>,
indices: FxHashMap<Kind<'tcx>, BoundVar>,
canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
needs_canonical_flags: TypeFlags,

binder_index: ty::DebruijnIndex,
}

impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
self.tcx
}

fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
where T: TypeFoldable<'tcx>
{
self.binder_index.shift_in(1);
let t = t.super_fold_with(self);
self.binder_index.shift_out(1);
t
}

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(..) => {
// leave bound regions alone
r
ty::ReLateBound(index, ..) => {
if index >= self.binder_index {
bug!("escaping late bound region during canonicalization")
} else {
r
}
}

ty::ReVar(vid) => {
Expand All @@ -317,8 +331,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
| ty::ReErased => self.canonicalize_region_mode
.canonicalize_free_region(self, r),

ty::ReClosureBound(..) | ty::ReCanonical(_) => {
bug!("canonical region encountered during canonicalization")
ty::ReClosureBound(..) => {
bug!("closure bound region encountered during canonicalization")
}
}
}
Expand All @@ -337,8 +351,12 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
bug!("encountered a fresh type during canonicalization")
}

ty::Infer(ty::BoundTy(_)) => {
bug!("encountered a canonical type during canonicalization")
ty::Bound(bound_ty) => {
if bound_ty.index >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
t
}
}

ty::Closure(..)
Expand Down Expand Up @@ -389,12 +407,6 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
where
V: TypeFoldable<'tcx> + Lift<'gcx>,
{
debug_assert!(
!value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS),
"canonicalizing a canonical value: {:?}",
value,
);

let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX
} else {
Expand Down Expand Up @@ -422,6 +434,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
variables: SmallVec::new(),
query_state,
indices: FxHashMap::default(),
binder_index: ty::INNERMOST,
};
let out_value = value.fold_with(&mut canonicalizer);

Expand Down Expand Up @@ -455,7 +468,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
/// or returns an existing variable if `kind` has already been
/// seen. `kind` is expected to be an unbound variable (or
/// potentially a free region).
fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundTy {
fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundVar {
let Canonicalizer {
variables,
query_state,
Expand All @@ -475,7 +488,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
// direct linear search of `var_values`.
if let Some(idx) = var_values.iter().position(|&k| k == kind) {
// `kind` is already present in `var_values`.
BoundTyIndex::new(idx)
BoundVar::new(idx)
} else {
// `kind` isn't present in `var_values`. Append it. Likewise
// for `info` and `variables`.
Expand All @@ -490,26 +503,23 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
*indices = var_values
.iter()
.enumerate()
.map(|(i, &kind)| (kind, BoundTyIndex::new(i)))
.map(|(i, &kind)| (kind, BoundVar::new(i)))
.collect();
}
// The cv is the index of the appended element.
BoundTyIndex::new(var_values.len() - 1)
BoundVar::new(var_values.len() - 1)
}
} else {
// `var_values` is large. Do a hashmap search via `indices`.
*indices.entry(kind).or_insert_with(|| {
variables.push(info);
var_values.push(kind);
assert_eq!(variables.len(), var_values.len());
BoundTyIndex::new(variables.len() - 1)
BoundVar::new(variables.len() - 1)
})
};

BoundTy {
level: ty::INNERMOST,
var,
}
var
}

/// Shorthand helper that creates a canonical region variable for
Expand Down Expand Up @@ -552,9 +562,12 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
info: CanonicalVarInfo,
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
let b = self.canonical_var(info, r.into());
debug_assert_eq!(ty::INNERMOST, b.level);
self.tcx().mk_region(ty::ReCanonical(b.var))
let var = self.canonical_var(info, r.into());
let region = ty::ReLateBound(
self.binder_index,
ty::BoundRegion::BrAnon(var.as_u32())
);
self.tcx().mk_region(region)
}

/// Given a type variable `ty_var` of the given kind, first check
Expand All @@ -570,9 +583,8 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
let info = CanonicalVarInfo {
kind: CanonicalVarKind::Ty(ty_kind),
};
let b = self.canonical_var(info, ty_var.into());
debug_assert_eq!(ty::INNERMOST, b.level);
self.tcx().mk_infer(ty::InferTy::BoundTy(b))
let var = self.canonical_var(info, ty_var.into());
self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var)))
}
}
}
12 changes: 6 additions & 6 deletions src/librustc/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//! - a map M (of type `CanonicalVarValues`) from those canonical
//! variables back to the original.
//!
//! We can then do queries using T2. These will give back constriants
//! We can then do queries using T2. These will give back constraints
//! on the canonical variables which can be translated, using the map
//! M, into constraints in our source context. This process of
//! translating the results back is done by the
Expand All @@ -40,7 +40,7 @@ use std::ops::Index;
use syntax::source_map::Span;
use ty::fold::TypeFoldable;
use ty::subst::Kind;
use ty::{self, BoundTyIndex, Lift, List, Region, TyCtxt};
use ty::{self, BoundVar, Lift, List, Region, TyCtxt};

mod canonicalizer;

Expand Down Expand Up @@ -73,7 +73,7 @@ impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> {}
/// canonicalized query response.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarValues<'tcx> {
pub var_values: IndexVec<BoundTyIndex, Kind<'tcx>>,
pub var_values: IndexVec<BoundVar, Kind<'tcx>>,
}

/// When we canonicalize a value to form a query, we wind up replacing
Expand Down Expand Up @@ -337,7 +337,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
variables: &List<CanonicalVarInfo>,
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
) -> CanonicalVarValues<'tcx> {
let var_values: IndexVec<BoundTyIndex, Kind<'tcx>> = variables
let var_values: IndexVec<BoundVar, Kind<'tcx>> = variables
.iter()
.map(|info| self.instantiate_canonical_var(span, *info, &universe_map))
.collect();
Expand Down Expand Up @@ -456,10 +456,10 @@ BraceStructLiftImpl! {
} where R: Lift<'tcx>
}

impl<'tcx> Index<BoundTyIndex> for CanonicalVarValues<'tcx> {
impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
type Output = Kind<'tcx>;

fn index(&self, value: BoundTyIndex) -> &Kind<'tcx> {
fn index(&self, value: BoundVar) -> &Kind<'tcx> {
&self.var_values[value]
}
}
Loading