Skip to content

Commit

Permalink
Rollup merge of rust-lang#55330 - scalexm:bound-ty, r=nikomatsakis
Browse files Browse the repository at this point in the history
Add support for bound types

This PR may have some slight performance impacts, I don't know how hot is the code I touched.

Also, this breaks clippy and miri.

r? @nikomatsakis
  • Loading branch information
Mark-Simulacrum committed Oct 27, 2018
2 parents 805fcb6 + 2b205dc commit 0956690
Show file tree
Hide file tree
Showing 72 changed files with 554 additions and 389 deletions.
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 @@ -894,6 +891,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 @@ -911,7 +911,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 @@ -225,21 +225,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 @@ -263,8 +277,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
| ty::ReEmpty
| 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 @@ -283,8 +297,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 @@ -335,12 +353,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 All @@ -367,6 +379,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 All @@ -393,7 +406,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 @@ -413,7 +426,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 @@ -428,35 +441,35 @@ 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
}

fn canonical_var_for_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let info = CanonicalVarInfo {
kind: CanonicalVarKind::Region,
};
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 @@ -472,9 +485,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, Region, List, TyCtxt};
use ty::{self, BoundVar, Lift, Region, List, TyCtxt};

mod canonicalizer;

Expand Down Expand Up @@ -72,7 +72,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 @@ -264,7 +264,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
span: Span,
variables: &List<CanonicalVarInfo>,
) -> CanonicalVarValues<'tcx> {
let var_values: IndexVec<BoundTyIndex, Kind<'tcx>> = variables
let var_values: IndexVec<BoundVar, Kind<'tcx>> = variables
.iter()
.map(|info| self.fresh_inference_var_for_canonical_var(span, *info))
.collect();
Expand Down Expand Up @@ -367,10 +367,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

0 comments on commit 0956690

Please sign in to comment.