Auto merge of #47861 - sgrif:sg-rebase-chalkify-universe-refactorings, r=nikomatsakis

Rebased refactorings for Chalk

The code is Niko's, I just handled the rebase.

r? @nikomatsakis
This commit is contained in:
bors 2018-03-01 21:14:35 +00:00
commit ddfbf2b0f4
43 changed files with 661 additions and 1316 deletions

10
src/Cargo.lock generated
View File

@ -598,6 +598,14 @@ name = "either"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ena"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "endian-type"
version = "0.1.2"
@ -1866,6 +1874,7 @@ name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2861,6 +2870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c"
"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
"checksum ena 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1733e41a3c37b0893685933d09dcb0c30269aa5d14dc5cafebf4bcded1e58225"
"checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"

View File

@ -870,6 +870,7 @@ for ty::steal::Steal<T>
impl_stable_hash_for!(struct ty::ParamEnv<'tcx> {
caller_bounds,
universe,
reveal
});
@ -1039,3 +1040,12 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContex
nested.hash_stable(hcx, hasher);
}
}
impl<'gcx> HashStable<StableHashingContext<'gcx>>
for ty::UniverseIndex {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
self.depth().hash_stable(hcx, hasher);
}
}

View File

@ -600,7 +600,8 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
return anon_defn.concrete_ty;
}
let span = tcx.def_span(def_id);
let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
let ty_var = infcx.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(span));
let predicates_of = tcx.predicates_of(def_id);
let bounds = predicates_of.instantiate(tcx, substs);

View File

@ -34,10 +34,10 @@
use super::equate::Equate;
use super::glb::Glb;
use super::{InferCtxt, MiscVariable, TypeTrace};
use super::lub::Lub;
use super::sub::Sub;
use super::InferCtxt;
use super::{MiscVariable, TypeTrace};
use super::type_variable::TypeVariableValue;
use hir::def_id::DefId;
use ty::{IntType, UintType};
@ -132,7 +132,7 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
{
self.int_unification_table
.borrow_mut()
.unify_var_value(vid, val)
.unify_var_value(vid, Some(val))
.map_err(|e| int_unification_error(vid_is_expected, e))?;
match val {
IntType(v) => Ok(self.tcx.mk_mach_int(v)),
@ -148,7 +148,7 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
{
self.float_unification_table
.borrow_mut()
.unify_var_value(vid, val)
.unify_var_value(vid, Some(ty::FloatVarValue(val)))
.map_err(|e| float_unification_error(vid_is_expected, e))?;
Ok(self.tcx.mk_mach_float(val))
}
@ -194,7 +194,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
use self::RelationDir::*;
// Get the actual variable that b_vid has been inferred to
debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_none());
debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_unknown());
debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
@ -402,12 +402,12 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
// `vid` are related via subtyping.
return Err(TypeError::CyclicTy(self.root_ty));
} else {
match variables.probe_root(vid) {
Some(u) => {
match variables.probe(vid) {
TypeVariableValue::Known { value: u } => {
drop(variables);
self.relate(&u, &u)
}
None => {
TypeVariableValue::Unknown { universe } => {
match self.ambient_variance {
// Invariant: no need to make a fresh type variable.
ty::Invariant => return Ok(t),
@ -423,8 +423,8 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
ty::Covariant | ty::Contravariant => (),
}
let origin = variables.origin(vid);
let new_var_id = variables.new_var(false, origin, None);
let origin = *variables.var_origin(vid);
let new_var_id = variables.new_var(universe, false, origin);
let u = self.tcx().mk_var(new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}",
vid, u);
@ -518,9 +518,9 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int
}
fn float_unification_error<'tcx>(a_is_expected: bool,
v: (ast::FloatTy, ast::FloatTy))
v: (ty::FloatVarValue, ty::FloatVarValue))
-> TypeError<'tcx>
{
let (a, b) = v;
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
}

View File

@ -133,7 +133,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
match t.sty {
ty::TyInfer(ty::TyVar(v)) => {
let opt_ty = self.infcx.type_variables.borrow_mut().probe(v);
let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known();
self.freshen(
opt_ty,
ty::TyVar(v),
@ -143,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::TyInfer(ty::IntVar(v)) => {
self.freshen(
self.infcx.int_unification_table.borrow_mut()
.probe(v)
.probe_value(v)
.map(|v| v.to_type(tcx)),
ty::IntVar(v),
ty::FreshIntTy)
@ -152,7 +152,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::TyInfer(ty::FloatVar(v)) => {
self.freshen(
self.infcx.float_unification_table.borrow_mut()
.probe(v)
.probe_value(v)
.map(|v| v.to_type(tcx)),
ty::FloatVar(v),
ty::FreshFloatTy)

View File

@ -131,7 +131,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> {
// variables to their binding anyhow, we know
// that it is unbound, so we can just return
// it.
debug_assert!(self.infcx.type_variables.borrow_mut().probe(vid).is_none());
debug_assert!(self.infcx.type_variables.borrow_mut()
.probe(vid)
.is_unknown());
ty
}
@ -139,7 +141,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> {
// This variable was created during the
// fudging. Recreate it with a fresh variable
// here.
self.infcx.next_ty_var(origin)
//
// The ROOT universe is fine because we only
// ever invoke this routine at the
// "item-level" of inference.
self.infcx.next_ty_var(ty::UniverseIndex::ROOT, origin)
}
}
}

View File

@ -244,7 +244,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
span: Span,
snapshot: &CombinedSnapshot,
snapshot: &CombinedSnapshot<'a, 'tcx>,
debruijn: ty::DebruijnIndex,
new_vars: &[ty::RegionVid],
a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
span: Span,
snapshot: &CombinedSnapshot,
snapshot: &CombinedSnapshot<'a, 'tcx>,
debruijn: ty::DebruijnIndex,
new_vars: &[ty::RegionVid],
a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
@ -479,7 +479,7 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn tainted_regions(&self,
snapshot: &CombinedSnapshot,
snapshot: &CombinedSnapshot<'a, 'tcx>,
r: ty::Region<'tcx>,
directions: TaintDirections)
-> FxHashSet<ty::Region<'tcx>> {
@ -491,7 +491,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
fn region_vars_confined_to_snapshot(&self,
snapshot: &CombinedSnapshot)
snapshot: &CombinedSnapshot<'a, 'tcx>)
-> Vec<ty::RegionVid>
{
/*!
@ -583,7 +583,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// See `README.md` for more details.
pub fn skolemize_late_bound_regions<T>(&self,
binder: &ty::Binder<T>,
snapshot: &CombinedSnapshot)
snapshot: &CombinedSnapshot<'a, 'tcx>)
-> (T, SkolemizationMap<'tcx>)
where T : TypeFoldable<'tcx>
{
@ -609,7 +609,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
overly_polymorphic: bool,
_span: Span,
skol_map: &SkolemizationMap<'tcx>,
snapshot: &CombinedSnapshot)
snapshot: &CombinedSnapshot<'a, 'tcx>)
-> RelateResult<'tcx, ()>
{
debug!("leak_check: skol_map={:?}",
@ -684,7 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// predicate is `for<'a> &'a int : Clone`.
pub fn plug_leaks<T>(&self,
skol_map: SkolemizationMap<'tcx>,
snapshot: &CombinedSnapshot,
snapshot: &CombinedSnapshot<'a, 'tcx>,
value: T) -> T
where T : TypeFoldable<'tcx>
{
@ -770,8 +770,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// Note: popping also occurs implicitly as part of `leak_check`.
pub fn pop_skolemized(&self,
skol_map: SkolemizationMap<'tcx>,
snapshot: &CombinedSnapshot)
{
snapshot: &CombinedSnapshot<'a, 'tcx>) {
debug!("pop_skolemized({:?})", skol_map);
let skol_regions: FxHashSet<_> = skol_map.values().cloned().collect();
self.borrow_region_constraints()

View File

@ -70,14 +70,6 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
let a = infcx.type_variables.borrow_mut().replace_if_possible(a);
let b = infcx.type_variables.borrow_mut().replace_if_possible(b);
match (&a.sty, &b.sty) {
(&ty::TyInfer(TyVar(..)), &ty::TyInfer(TyVar(..)))
if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => {
let v = infcx.next_diverging_ty_var(
TypeVariableOrigin::LatticeVariable(this.cause().span));
this.relate_bound(v, a, b)?;
Ok(v)
}
// If one side is known to be a variable and one is not,
// create a variable (`v`) to represent the LUB. Make sure to
// relate `v` to the non-type-variable first (by passing it
@ -96,13 +88,17 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
// is (e.g.) `Box<i32>`. A more obvious solution might be to
// iterate on the subtype obligations that are returned, but I
// think this suffices. -nmatsakis
(&ty::TyInfer(TyVar(..)), _) => {
let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span));
(&ty::TyInfer(TyVar(a_vid)), _) => {
let universe = infcx.type_variables.borrow_mut().probe(a_vid).universe().unwrap();
let v = infcx.next_ty_var(universe,
TypeVariableOrigin::LatticeVariable(this.cause().span));
this.relate_bound(v, b, a)?;
Ok(v)
}
(_, &ty::TyInfer(TyVar(..))) => {
let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span));
(_, &ty::TyInfer(TyVar(b_vid))) => {
let universe = infcx.type_variables.borrow_mut().probe(b_vid).universe().unwrap();
let v = infcx.next_ty_var(universe,
TypeVariableOrigin::LatticeVariable(this.cause().span));
this.relate_bound(v, a, b)?;
Ok(v)
}

View File

@ -22,14 +22,14 @@ use middle::free_region::RegionRelations;
use middle::region;
use middle::lang_items;
use mir::tcx::PlaceTy;
use ty::subst::{Kind, Subst, Substs};
use ty::subst::Substs;
use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::relate::RelateResult;
use traits::{self, ObligationCause, PredicateObligations, Reveal};
use rustc_data_structures::unify::{self, UnificationTable};
use rustc_data_structures::unify as ut;
use std::cell::{Cell, RefCell, Ref, RefMut};
use std::collections::BTreeMap;
use std::fmt;
@ -99,10 +99,10 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
pub type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>,
// Map from integral variable to the kind of integer it represents
int_unification_table: RefCell<UnificationTable<ty::IntVid>>,
int_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::IntVid>>>,
// Map from floating variable to the kind of float it represents
float_unification_table: RefCell<UnificationTable<ty::FloatVid>>,
float_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::FloatVid>>>,
// Tracks the set of region variables and the constraints between
// them. This is initially `Some(_)` but when
@ -441,8 +441,8 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
in_progress_tables,
projection_cache: RefCell::new(traits::ProjectionCache::new()),
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
int_unification_table: RefCell::new(UnificationTable::new()),
float_unification_table: RefCell::new(UnificationTable::new()),
int_unification_table: RefCell::new(ut::UnificationTable::new()),
float_unification_table: RefCell::new(ut::UnificationTable::new()),
region_constraints: RefCell::new(Some(RegionConstraintCollector::new())),
lexical_region_resolutions: RefCell::new(None),
selection_cache: traits::SelectionCache::new(),
@ -475,9 +475,9 @@ impl<'tcx, T> InferOk<'tcx, T> {
#[must_use = "once you start a snapshot, you should always consume it"]
pub struct CombinedSnapshot<'a, 'tcx:'a> {
projection_cache_snapshot: traits::ProjectionCacheSnapshot,
type_snapshot: type_variable::Snapshot,
int_snapshot: unify::Snapshot<ty::IntVid>,
float_snapshot: unify::Snapshot<ty::FloatVid>,
type_snapshot: type_variable::Snapshot<'tcx>,
int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
region_constraints_snapshot: RegionSnapshot,
region_obligations_snapshot: usize,
was_in_snapshot: bool,
@ -678,14 +678,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
use ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
match ty.sty {
ty::TyInfer(ty::IntVar(vid)) => {
if self.int_unification_table.borrow_mut().has_value(vid) {
if self.int_unification_table.borrow_mut().probe_value(vid).is_some() {
Neither
} else {
UnconstrainedInt
}
},
ty::TyInfer(ty::FloatVar(vid)) => {
if self.float_unification_table.borrow_mut().has_value(vid) {
if self.float_unification_table.borrow_mut().probe_value(vid).is_some() {
Neither
} else {
UnconstrainedFloat
@ -695,46 +695,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
/// Returns a type variable's default fallback if any exists. A default
/// must be attached to the variable when created, if it is created
/// without a default, this will return None.
///
/// This code does not apply to integral or floating point variables,
/// only to use declared defaults.
///
/// See `new_ty_var_with_default` to create a type variable with a default.
/// See `type_variable::Default` for details about what a default entails.
pub fn default(&self, ty: Ty<'tcx>) -> Option<type_variable::Default<'tcx>> {
match ty.sty {
ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid),
_ => None
}
}
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
let mut variables = Vec::new();
let unbound_ty_vars = self.type_variables
.borrow_mut()
.unsolved_variables()
.into_iter()
.map(|t| self.tcx.mk_var(t));
{
let mut type_variables = self.type_variables.borrow_mut();
variables.extend(
type_variables
.unsolved_variables()
.into_iter()
.map(|t| self.tcx.mk_var(t)));
}
let unbound_int_vars = self.int_unification_table
.borrow_mut()
.unsolved_variables()
.into_iter()
.map(|v| self.tcx.mk_int_var(v));
{
let mut int_unification_table = self.int_unification_table.borrow_mut();
variables.extend(
(0..int_unification_table.len())
.map(|i| ty::IntVid { index: i as u32 })
.filter(|&vid| int_unification_table.probe_value(vid).is_none())
.map(|v| self.tcx.mk_int_var(v)));
}
let unbound_float_vars = self.float_unification_table
.borrow_mut()
.unsolved_variables()
.into_iter()
.map(|v| self.tcx.mk_float_var(v));
variables.extend(unbound_ty_vars);
variables.extend(unbound_int_vars);
variables.extend(unbound_float_vars);
{
let mut float_unification_table = self.float_unification_table.borrow_mut();
variables.extend(
(0..float_unification_table.len())
.map(|i| ty::FloatVid { index: i as u32 })
.filter(|&vid| float_unification_table.probe_value(vid).is_none())
.map(|v| self.tcx.mk_float_var(v)));
}
return variables;
}
@ -776,7 +765,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
result
}
fn start_snapshot<'b>(&'b self) -> CombinedSnapshot<'b, 'tcx> {
fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
debug!("start_snapshot()");
let in_snapshot = self.in_snapshot.get();
@ -798,7 +787,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) {
fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
debug!("rollback_to(cause={})", cause);
let CombinedSnapshot { projection_cache_snapshot,
type_snapshot,
@ -830,7 +819,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
.rollback_to(region_constraints_snapshot);
}
fn commit_from(&self, snapshot: CombinedSnapshot) {
fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
debug!("commit_from()");
let CombinedSnapshot { projection_cache_snapshot,
type_snapshot,
@ -872,7 +861,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce(&CombinedSnapshot) -> Result<T, E>
F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>
{
debug!("commit_if_ok()");
let snapshot = self.start_snapshot();
@ -887,7 +876,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// Execute `f` in a snapshot, and commit the bindings it creates
pub fn in_snapshot<T, F>(&self, f: F) -> T where
F: FnOnce(&CombinedSnapshot) -> T
F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T
{
debug!("in_snapshot()");
let snapshot = self.start_snapshot();
@ -898,7 +887,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// Execute `f` then unroll any bindings it creates
pub fn probe<R, F>(&self, f: F) -> R where
F: FnOnce(&CombinedSnapshot) -> R,
F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
{
debug!("probe()");
let snapshot = self.start_snapshot();
@ -1026,18 +1015,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
})
}
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
pub fn next_ty_var_id(&self,
universe: ty::UniverseIndex,
diverging: bool,
origin: TypeVariableOrigin)
-> TyVid {
self.type_variables
.borrow_mut()
.new_var(diverging, origin, None)
.new_var(universe, diverging, origin)
}
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(false, origin))
pub fn next_ty_var(&self, universe: ty::UniverseIndex, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(universe, false, origin))
}
pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(true, origin))
pub fn next_diverging_ty_var(&self,
universe: ty::UniverseIndex,
origin: TypeVariableOrigin)
-> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(universe, true, origin))
}
pub fn next_int_var_id(&self) -> IntVid {
@ -1092,27 +1088,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// use an inference variable for `C` with `[T, U]`
/// as the substitutions for the default, `(T, U)`.
pub fn type_var_for_def(&self,
universe: ty::UniverseIndex,
span: Span,
def: &ty::TypeParameterDef,
substs: &[Kind<'tcx>])
def: &ty::TypeParameterDef)
-> Ty<'tcx> {
let default = if def.has_default {
let default = self.tcx.type_of(def.def_id);
Some(type_variable::Default {
ty: default.subst_spanned(self.tcx, substs, Some(span)),
origin_span: span,
def_id: def.def_id
})
} else {
None
};
let ty_var_id = self.type_variables
.borrow_mut()
.new_var(false,
TypeVariableOrigin::TypeParameterDefinition(span, def.name),
default);
.new_var(universe,
false,
TypeVariableOrigin::TypeParameterDefinition(span, def.name));
self.tcx.mk_var(ty_var_id)
}
@ -1120,13 +1104,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
/// type/region parameter to a fresh inference variable.
pub fn fresh_substs_for_item(&self,
universe: ty::UniverseIndex,
span: Span,
def_id: DefId)
-> &'tcx Substs<'tcx> {
Substs::for_item(self.tcx, def_id, |def, _| {
self.region_var_for_def(span, def)
}, |def, substs| {
self.type_var_for_def(span, def, substs)
}, |def, _| {
self.type_var_for_def(universe, span, def)
})
}
@ -1284,15 +1269,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// so this recursion should always be of very limited
// depth.
self.type_variables.borrow_mut()
.probe(v)
.map(|t| self.shallow_resolve(t))
.unwrap_or(typ)
.probe(v)
.known()
.map(|t| self.shallow_resolve(t))
.unwrap_or(typ)
}
ty::TyInfer(ty::IntVar(v)) => {
self.int_unification_table
.borrow_mut()
.probe(v)
.probe_value(v)
.map(|v| v.to_type(self.tcx))
.unwrap_or(typ)
}
@ -1300,7 +1286,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::TyInfer(ty::FloatVar(v)) => {
self.float_unification_table
.borrow_mut()
.probe(v)
.probe_value(v)
.map(|v| v.to_type(self.tcx))
.unwrap_or(typ)
}
@ -1402,28 +1388,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.report_and_explain_type_error(trace, &err)
}
pub fn report_conflicting_default_types(&self,
span: Span,
body_id: ast::NodeId,
expected: type_variable::Default<'tcx>,
actual: type_variable::Default<'tcx>) {
let trace = TypeTrace {
cause: ObligationCause::misc(span, body_id),
values: Types(ExpectedFound {
expected: expected.ty,
found: actual.ty
})
};
self.report_and_explain_type_error(
trace,
&TypeError::TyParamDefaultMismatch(ExpectedFound {
expected,
found: actual
}))
.emit();
}
pub fn replace_late_bound_regions_with_fresh_var<T>(
&self,
span: Span,

View File

@ -18,7 +18,7 @@ use super::unify_key;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::unify::{self, UnificationTable};
use rustc_data_structures::unify as ut;
use ty::{self, Ty, TyCtxt};
use ty::{Region, RegionVid};
use ty::ReStatic;
@ -48,7 +48,7 @@ pub struct RegionConstraintCollector<'tcx> {
glbs: CombineMap<'tcx>,
/// Number of skolemized variables currently active.
skolemization_count: u32,
skolemization_count: ty::UniverseIndex,
/// Global counter used during the GLB algorithm to create unique
/// names for fresh bound regions
@ -73,7 +73,7 @@ pub struct RegionConstraintCollector<'tcx> {
/// is iterating to a fixed point, because otherwise we sometimes
/// would wind up with a fresh stream of region variables that
/// have been equated but appear distinct.
unification_table: UnificationTable<ty::RegionVid>,
unification_table: ut::UnificationTable<ut::InPlace<ty::RegionVid>>,
}
pub type VarOrigins = IndexVec<RegionVid, RegionVariableOrigin>;
@ -232,8 +232,8 @@ type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>;
pub struct RegionSnapshot {
length: usize,
region_snapshot: unify::Snapshot<ty::RegionVid>,
skolemization_count: u32,
region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>,
skolemization_count: ty::UniverseIndex,
}
/// When working with skolemized regions, we often wish to find all of
@ -277,10 +277,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
data: RegionConstraintData::default(),
lubs: FxHashMap(),
glbs: FxHashMap(),
skolemization_count: 0,
skolemization_count: ty::UniverseIndex::ROOT,
bound_count: 0,
undo_log: Vec::new(),
unification_table: UnificationTable::new(),
unification_table: ut::UnificationTable::new(),
}
}
@ -329,7 +329,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
unification_table,
} = self;
assert_eq!(*skolemization_count, 0);
assert_eq!(skolemization_count.as_usize(), 0);
// Clear the tables of (lubs, glbs), so that we will create
// fresh regions if we do a LUB operation. As it happens,
@ -342,7 +342,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
// un-unified" state. Note that when we unify `a` and `b`, we
// also insert `a <= b` and a `b <= a` edges, so the
// `RegionConstraintData` contains the relationship here.
*unification_table = UnificationTable::new();
*unification_table = ut::UnificationTable::new();
for vid in var_origins.indices() {
unification_table.new_key(unify_key::RegionVidKey { min_vid: vid });
}
@ -371,7 +371,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
assert!(self.undo_log[snapshot.length] == OpenSnapshot);
assert!(
self.skolemization_count == snapshot.skolemization_count,
"failed to pop skolemized regions: {} now vs {} at start",
"failed to pop skolemized regions: {:?} now vs {:?} at start",
self.skolemization_count,
snapshot.skolemization_count
);
@ -479,9 +479,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
assert!(self.in_snapshot());
assert!(self.undo_log[snapshot.length] == OpenSnapshot);
let sc = self.skolemization_count;
self.skolemization_count = sc + 1;
tcx.mk_region(ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br))
let universe = self.skolemization_count.subuniverse();
self.skolemization_count = universe;
tcx.mk_region(ReSkolemized(universe, br))
}
/// Removes all the edges to/from the skolemized regions that are
@ -499,20 +499,20 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
assert!(self.in_snapshot());
assert!(self.undo_log[snapshot.length] == OpenSnapshot);
assert!(
self.skolemization_count as usize >= skols.len(),
self.skolemization_count.as_usize() >= skols.len(),
"popping more skolemized variables than actually exist, \
sc now = {}, skols.len = {}",
self.skolemization_count,
self.skolemization_count.as_usize(),
skols.len()
);
let last_to_pop = self.skolemization_count;
let first_to_pop = last_to_pop - (skols.len() as u32);
let last_to_pop = self.skolemization_count.subuniverse();
let first_to_pop = ty::UniverseIndex::from(last_to_pop.as_u32() - (skols.len() as u32));
assert!(
first_to_pop >= snapshot.skolemization_count,
"popping more regions than snapshot contains, \
sc now = {}, sc then = {}, skols.len = {}",
sc now = {:?}, sc then = {:?}, skols.len = {}",
self.skolemization_count,
snapshot.skolemization_count,
skols.len()
@ -520,13 +520,13 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
debug_assert! {
skols.iter()
.all(|&k| match *k {
ty::ReSkolemized(index, _) =>
index.index >= first_to_pop &&
index.index < last_to_pop,
ty::ReSkolemized(universe, _) =>
universe >= first_to_pop &&
universe < last_to_pop,
_ =>
false
}),
"invalid skolemization keys or keys out of range ({}..{}): {:?}",
"invalid skolemization keys or keys out of range ({:?}..{:?}): {:?}",
snapshot.skolemization_count,
self.skolemization_count,
skols
@ -776,7 +776,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
tcx: TyCtxt<'_, '_, 'tcx>,
rid: RegionVid,
) -> ty::Region<'tcx> {
let vid = self.unification_table.find_value(rid).min_vid;
let vid = self.unification_table.probe_value(rid).min_vid;
tcx.mk_region(ty::ReVar(vid))
}
@ -861,7 +861,7 @@ impl fmt::Debug for RegionSnapshot {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"RegionSnapshot(length={},skolemization={})",
"RegionSnapshot(length={},skolemization={:?})",
self.length,
self.skolemization_count
)

View File

@ -8,26 +8,28 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use self::TypeVariableValue::*;
use hir::def_id::{DefId};
use syntax::ast;
use syntax_pos::Span;
use ty::{self, Ty};
use std::cmp::min;
use std::cmp;
use std::marker::PhantomData;
use std::mem;
use std::u32;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::unify as ut;
pub struct TypeVariableTable<'tcx> {
values: sv::SnapshotVec<Delegate<'tcx>>,
/// Extra data for each type variable, such as the origin. This is
/// not stored in the unification table since, when we inquire
/// after the origin of a variable X, we want the origin of **that
/// variable X**, not the origin of some other variable Y with
/// which X has been unified.
var_data: Vec<TypeVariableData>,
/// Two variables are unified in `eq_relations` when we have a
/// constraint `?X == ?Y`.
eq_relations: ut::UnificationTable<ty::TyVid>,
/// constraint `?X == ?Y`. This table also stores, for each key,
/// the known value.
eq_relations: ut::UnificationTable<ut::InPlace<TyVidEqKey<'tcx>>>,
/// Two variables are unified in `eq_relations` when we have a
/// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
@ -46,7 +48,7 @@ pub struct TypeVariableTable<'tcx> {
/// This is reasonable because, in Rust, subtypes have the same
/// "skeleton" and hence there is no possible type such that
/// (e.g.) `Box<?3> <: ?3` for any `?3`.
sub_relations: ut::UnificationTable<ty::TyVid>,
sub_relations: ut::UnificationTable<ut::InPlace<ty::TyVid>>,
}
/// Reasons to create a type inference variable
@ -72,73 +74,91 @@ pub enum TypeVariableOrigin {
pub type TypeVariableMap = FxHashMap<ty::TyVid, TypeVariableOrigin>;
struct TypeVariableData<'tcx> {
value: TypeVariableValue<'tcx>,
struct TypeVariableData {
origin: TypeVariableOrigin,
diverging: bool
}
enum TypeVariableValue<'tcx> {
Known(Ty<'tcx>),
Bounded {
default: Option<Default<'tcx>>
#[derive(Copy, Clone, Debug)]
pub enum TypeVariableValue<'tcx> {
Known { value: Ty<'tcx> },
Unknown { universe: ty::UniverseIndex },
}
#[derive(Copy, Clone, Debug)]
pub enum ProbeTyValue<'tcx> {
Ty(Ty<'tcx>),
Vid(ty::TyVid),
}
impl<'tcx> TypeVariableValue<'tcx> {
/// If this value is known, returns the type it is known to be.
/// Otherwise, `None`.
pub fn known(&self) -> Option<Ty<'tcx>> {
match *self {
TypeVariableValue::Unknown { .. } => None,
TypeVariableValue::Known { value } => Some(value),
}
}
/// If this value is unknown, returns the universe, otherwise `None`.
pub fn universe(&self) -> Option<ty::UniverseIndex> {
match *self {
TypeVariableValue::Unknown { universe } => Some(universe),
TypeVariableValue::Known { .. } => None,
}
}
pub fn is_unknown(&self) -> bool {
match *self {
TypeVariableValue::Unknown { .. } => true,
TypeVariableValue::Known { .. } => false,
}
}
}
// We will use this to store the required information to recapitulate what happened when
// an error occurs.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Default<'tcx> {
pub ty: Ty<'tcx>,
/// The span where the default was incurred
pub origin_span: Span,
/// The definition that the default originates from
pub def_id: DefId
}
pub struct Snapshot<'tcx> {
/// number of variables at the time of the snapshot
num_vars: usize,
pub struct Snapshot {
snapshot: sv::Snapshot,
eq_snapshot: ut::Snapshot<ty::TyVid>,
sub_snapshot: ut::Snapshot<ty::TyVid>,
}
/// snapshot from the `eq_relations` table
eq_snapshot: ut::Snapshot<ut::InPlace<TyVidEqKey<'tcx>>>,
struct Instantiate<'tcx> {
vid: ty::TyVid,
default: Option<Default<'tcx>>,
/// snapshot from the `sub_relations` table
sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>,
}
struct Delegate<'tcx>(PhantomData<&'tcx ()>);
impl<'tcx> TypeVariableTable<'tcx> {
pub fn new() -> TypeVariableTable<'tcx> {
TypeVariableTable {
values: sv::SnapshotVec::new(),
var_data: Vec::new(),
eq_relations: ut::UnificationTable::new(),
sub_relations: ut::UnificationTable::new(),
}
}
pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> {
match &self.values.get(vid.index as usize).value {
&Known(_) => None,
&Bounded { ref default, .. } => default.clone()
}
}
/// Returns the diverges flag given when `vid` was created.
///
/// Note that this function does not return care whether
/// `vid` has been unified with something else or not.
pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
self.values.get(vid.index as usize).diverging
self.var_data[vid.index as usize].diverging
}
/// Returns the origin that was given when `vid` was created.
///
/// Note that this function does not return care whether
/// `vid` has been unified with something else or not.
pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
&self.values.get(vid.index as usize).origin
&self.var_data[vid.index as usize].origin
}
/// Records that `a == b`, depending on `dir`.
///
/// Precondition: neither `a` nor `b` are known.
pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
debug_assert!(self.probe(a).is_none());
debug_assert!(self.probe(b).is_none());
debug_assert!(self.probe(a).is_unknown());
debug_assert!(self.probe(b).is_unknown());
self.eq_relations.union(a, b);
self.sub_relations.union(a, b);
}
@ -147,8 +167,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
///
/// Precondition: neither `a` nor `b` are known.
pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) {
debug_assert!(self.probe(a).is_none());
debug_assert!(self.probe(b).is_none());
debug_assert!(self.probe(a).is_unknown());
debug_assert!(self.probe(b).is_unknown());
self.sub_relations.union(a, b);
}
@ -157,43 +177,44 @@ impl<'tcx> TypeVariableTable<'tcx> {
/// Precondition: `vid` must not have been previously instantiated.
pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
let vid = self.root_var(vid);
debug_assert!(self.probe_root(vid).is_none());
let old_value = {
let vid_data = &mut self.values[vid.index as usize];
mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty))
};
match old_value {
TypeVariableValue::Bounded { default } => {
self.values.record(Instantiate { vid: vid, default: default });
}
TypeVariableValue::Known(old_ty) => {
bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
vid, ty, old_ty)
}
}
debug_assert!(self.probe(vid).is_unknown());
debug_assert!(self.eq_relations.probe_value(vid).is_unknown(),
"instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
vid, ty, self.eq_relations.probe_value(vid));
self.eq_relations.union_value(vid, TypeVariableValue::Known { value: ty });
}
/// Creates a new type variable.
///
/// - `diverging`: indicates if this is a "diverging" type
/// variable, e.g. one created as the type of a `return`
/// expression. The code in this module doesn't care if a
/// variable is diverging, but the main Rust type-checker will
/// sometimes "unify" such variables with the `!` or `()` types.
/// - `origin`: indicates *why* the type variable was created.
/// The code in this module doesn't care, but it can be useful
/// for improving error messages.
pub fn new_var(&mut self,
universe: ty::UniverseIndex,
diverging: bool,
origin: TypeVariableOrigin,
default: Option<Default<'tcx>>,) -> ty::TyVid {
debug!("new_var(diverging={:?}, origin={:?})", diverging, origin);
self.eq_relations.new_key(());
self.sub_relations.new_key(());
let index = self.values.push(TypeVariableData {
value: Bounded { default: default },
origin,
diverging,
});
let v = ty::TyVid { index: index as u32 };
debug!("new_var: diverging={:?} index={:?}", diverging, v);
v
origin: TypeVariableOrigin)
-> ty::TyVid {
let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown { universe });
let sub_key = self.sub_relations.new_key(());
assert_eq!(eq_key.vid, sub_key);
assert_eq!(self.var_data.len(), sub_key.index as usize);
self.var_data.push(TypeVariableData { origin, diverging });
debug!("new_var(index={:?}, diverging={:?}, origin={:?}", eq_key.vid, diverging, origin);
eq_key.vid
}
/// Returns the number of type variables created thus far.
pub fn num_vars(&self) -> usize {
self.values.len()
self.var_data.len()
}
/// Returns the "root" variable of `vid` in the `eq_relations`
@ -202,7 +223,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
/// algorithm), so `root_var(a) == root_var(b)` implies that `a ==
/// b` (transitively).
pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
self.eq_relations.find(vid)
self.eq_relations.find(vid).vid
}
/// Returns the "root" variable of `vid` in the `sub_relations`
@ -222,65 +243,58 @@ impl<'tcx> TypeVariableTable<'tcx> {
self.sub_root_var(a) == self.sub_root_var(b)
}
pub fn probe(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
let vid = self.root_var(vid);
self.probe_root(vid)
}
pub fn origin(&self, vid: ty::TyVid) -> TypeVariableOrigin {
self.values.get(vid.index as usize).origin.clone()
}
/// Retrieves the type of `vid` given that it is currently a root in the unification table
pub fn probe_root(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
debug_assert!(self.root_var(vid) == vid);
match self.values.get(vid.index as usize).value {
Bounded { .. } => None,
Known(t) => Some(t)
}
/// Retrieves the type to which `vid` has been instantiated, if
/// any.
pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
self.eq_relations.probe_value(vid)
}
/// If `t` is a type-inference variable, and it has been
/// instantiated, then return the with which it was
/// instantiated. Otherwise, returns `t`.
pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match t.sty {
ty::TyInfer(ty::TyVar(v)) => {
match self.probe(v) {
None => t,
Some(u) => u
TypeVariableValue::Unknown { .. } => t,
TypeVariableValue::Known { value } => value,
}
}
_ => t,
}
}
pub fn snapshot(&mut self) -> Snapshot {
/// Creates a snapshot of the type variable state. This snapshot
/// must later be committed (`commit()`) or rolled back
/// (`rollback_to()`). Nested snapshots are permitted, but must
/// be processed in a stack-like fashion.
pub fn snapshot(&mut self) -> Snapshot<'tcx> {
Snapshot {
snapshot: self.values.start_snapshot(),
num_vars: self.var_data.len(),
eq_snapshot: self.eq_relations.snapshot(),
sub_snapshot: self.sub_relations.snapshot(),
}
}
pub fn rollback_to(&mut self, s: Snapshot) {
debug!("rollback_to{:?}", {
for action in self.values.actions_since_snapshot(&s.snapshot) {
match *action {
sv::UndoLog::NewElem(index) => {
debug!("inference variable _#{}t popped", index)
}
_ => { }
}
}
});
let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
self.values.rollback_to(snapshot);
/// Undoes all changes since the snapshot was created. Any
/// snapshots created since that point must already have been
/// committed or rolled back.
pub fn rollback_to(&mut self, s: Snapshot<'tcx>) {
let Snapshot { num_vars, eq_snapshot, sub_snapshot } = s;
debug!("type_variables::rollback_to(num_vars = {})", num_vars);
assert!(self.var_data.len() >= num_vars);
self.eq_relations.rollback_to(eq_snapshot);
self.sub_relations.rollback_to(sub_snapshot);
self.var_data.truncate(num_vars);
}
pub fn commit(&mut self, s: Snapshot) {
let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
self.values.commit(snapshot);
/// Commits all changes since the snapshot was created, making
/// them permanent (unless this snapshot was created within
/// another snapshot). Any snapshots created since that point
/// must already have been committed or rolled back.
pub fn commit(&mut self, s: Snapshot<'tcx>) {
let Snapshot { num_vars, eq_snapshot, sub_snapshot } = s;
debug!("type_variables::commit(num_vars = {})", num_vars);
self.eq_relations.commit(eq_snapshot);
self.sub_relations.commit(sub_snapshot);
}
@ -289,90 +303,125 @@ impl<'tcx> TypeVariableTable<'tcx> {
/// ty-variables created during the snapshot, and the values
/// `{V2}` are the root variables that they were unified with,
/// along with their origin.
pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap {
let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
actions_since_snapshot
pub fn types_created_since_snapshot(&mut self, snapshot: &Snapshot<'tcx>) -> TypeVariableMap {
self.var_data
.iter()
.filter_map(|action| match action {
&sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }),
_ => None,
})
.map(|vid| {
let origin = self.values.get(vid.index as usize).origin.clone();
(vid, origin)
})
.enumerate()
.skip(snapshot.num_vars) // skip those that existed when snapshot was taken
.map(|(index, data)| (ty::TyVid { index: index as u32 }, data.origin))
.collect()
}
pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec<Ty<'tcx>> {
/*!
* Find the set of type variables that existed *before* `s`
* but which have only been unified since `s` started, and
* return the types with which they were unified. So if we had
* a type variable `V0`, then we started the snapshot, then we
* created a type variable `V1`, unifed `V0` with `T0`, and
* unified `V1` with `T1`, this function would return `{T0}`.
*/
let mut new_elem_threshold = u32::MAX;
let mut escaping_types = Vec::new();
let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len());
for action in actions_since_snapshot {
match *action {
sv::UndoLog::NewElem(index) => {
// if any new variables were created during the
// snapshot, remember the lower index (which will
// always be the first one we see). Note that this
// action must precede those variables being
// specified.
new_elem_threshold = min(new_elem_threshold, index as u32);
debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
}
sv::UndoLog::Other(Instantiate { vid, .. }) => {
if vid.index < new_elem_threshold {
// quick check to see if this variable was
// created since the snapshot started or not.
let escaping_type = match self.values.get(vid.index as usize).value {
Bounded { .. } => bug!(),
Known(ty) => ty,
};
escaping_types.push(escaping_type);
}
debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold);
}
_ => { }
}
}
/// Find the set of type variables that existed *before* `s`
/// but which have only been unified since `s` started, and
/// return the types with which they were unified. So if we had
/// a type variable `V0`, then we started the snapshot, then we
/// created a type variable `V1`, unifed `V0` with `T0`, and
/// unified `V1` with `T1`, this function would return `{T0}`.
pub fn types_escaping_snapshot(&mut self, snapshot: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> {
// We want to select only those instantiations that have
// occurred since the snapshot *and* which affect some
// variable that existed prior to the snapshot. This code just
// affects all instantiatons that ever occurred which affect
// variables prior to the snapshot.
//
// It's hard to do better than this, though, without changing
// the unification table to prefer "lower" vids -- the problem
// is that we may have a variable X (from before the snapshot)
// and Y (from after the snapshot) which get unified, with Y
// chosen as the new root. Now we are "instantiating" Y with a
// value, but it escapes into X, but we wouldn't readily see
// that. (In fact, earlier revisions of this code had this
// bug; it was introduced when we added the `eq_relations`
// table, but it's hard to create rust code that triggers it.)
//
// We could tell the table to prefer lower vids, and then we would
// see the case above, but we would get less-well-balanced trees.
//
// Since I hope to kill the leak-check in this branch, and
// that's the code which uses this logic anyway, I'm going to
// use the less efficient algorithm for now.
let mut escaping_types = Vec::with_capacity(snapshot.num_vars);
escaping_types.extend(
(0..snapshot.num_vars) // for all variables that pre-exist the snapshot, collect..
.map(|i| ty::TyVid { index: i as u32 })
.filter_map(|vid| self.probe(vid).known())); // ..types they are instantiated with.
debug!("types_escaping_snapshot = {:?}", escaping_types);
escaping_types
}
/// Returns indices of all variables that are not yet
/// instantiated.
pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> {
(0..self.values.len())
(0..self.var_data.len())
.filter_map(|i| {
let vid = ty::TyVid { index: i as u32 };
if self.probe(vid).is_some() {
None
} else {
Some(vid)
match self.probe(vid) {
TypeVariableValue::Unknown { .. } => Some(vid),
TypeVariableValue::Known { .. } => None,
}
})
.collect()
}
}
///////////////////////////////////////////////////////////////////////////
impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
type Value = TypeVariableData<'tcx>;
type Undo = Instantiate<'tcx>;
/// These structs (a newtyped TyVid) are used as the unification key
/// for the `eq_relations`; they carry a `TypeVariableValue` along
/// with them.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct TyVidEqKey<'tcx> {
vid: ty::TyVid,
fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate<'tcx>) {
let Instantiate { vid, default } = action;
values[vid.index as usize].value = Bounded {
default,
};
// in the table, we map each ty-vid to one of these:
phantom: PhantomData<TypeVariableValue<'tcx>>,
}
impl<'tcx> From<ty::TyVid> for TyVidEqKey<'tcx> {
fn from(vid: ty::TyVid) -> Self {
TyVidEqKey { vid, phantom: PhantomData }
}
}
impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> {
type Value = TypeVariableValue<'tcx>;
fn index(&self) -> u32 { self.vid.index }
fn from_index(i: u32) -> Self { TyVidEqKey::from(ty::TyVid { index: i }) }
fn tag() -> &'static str { "TyVidEqKey" }
}
impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
type Error = ut::NoError;
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, ut::NoError> {
match (value1, value2) {
// We never equate two type variables, both of which
// have known types. Instead, we recursively equate
// those types.
(&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => {
bug!("equating two type variables, both of which have known types")
}
// If one side is known, prefer that one.
(&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => Ok(*value1),
(&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => Ok(*value2),
// If both sides are unknown, we need to pick the most restrictive universe.
(&TypeVariableValue::Unknown { universe: universe1 },
&TypeVariableValue::Unknown { universe: universe2 }) => {
let universe = cmp::min(universe1, universe2);
Ok(TypeVariableValue::Unknown { universe })
}
}
}
}
/// Raw `TyVid` are used as the unification key for `sub_relations`;
/// they carry no values.
impl ut::UnifyKey for ty::TyVid {
type Value = ();
fn index(&self) -> u32 { self.index }
fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } }
fn tag() -> &'static str { "TyVid" }
}

View File

@ -8,9 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syntax::ast;
use ty::{self, IntVarValue, Ty, TyCtxt};
use rustc_data_structures::unify::{Combine, UnifyKey};
use ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt};
use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue};
pub trait ToType {
fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
@ -20,7 +19,10 @@ impl UnifyKey for ty::IntVid {
type Value = Option<IntVarValue>;
fn index(&self) -> u32 { self.index }
fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" }
fn tag() -> &'static str { "IntVid" }
}
impl EqUnifyValue for IntVarValue {
}
#[derive(PartialEq, Copy, Clone, Debug)]
@ -31,15 +33,17 @@ pub struct RegionVidKey {
pub min_vid: ty::RegionVid
}
impl Combine for RegionVidKey {
fn combine(&self, other: &RegionVidKey) -> RegionVidKey {
let min_vid = if self.min_vid.index() < other.min_vid.index() {
self.min_vid
impl UnifyValue for RegionVidKey {
type Error = NoError;
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
let min_vid = if value1.min_vid.index() < value2.min_vid.index() {
value1.min_vid
} else {
other.min_vid
value2.min_vid
};
RegionVidKey { min_vid: min_vid }
Ok(RegionVidKey { min_vid: min_vid })
}
}
@ -47,7 +51,7 @@ impl UnifyKey for ty::RegionVid {
type Value = RegionVidKey;
fn index(&self) -> u32 { self.0 }
fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid(i) }
fn tag(_: Option<ty::RegionVid>) -> &'static str { "RegionVid" }
fn tag() -> &'static str { "RegionVid" }
}
impl ToType for IntVarValue {
@ -62,21 +66,17 @@ impl ToType for IntVarValue {
// Floating point type keys
impl UnifyKey for ty::FloatVid {
type Value = Option<ast::FloatTy>;
type Value = Option<FloatVarValue>;
fn index(&self) -> u32 { self.index }
fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" }
fn tag() -> &'static str { "FloatVid" }
}
impl ToType for ast::FloatTy {
impl EqUnifyValue for FloatVarValue {
}
impl ToType for FloatVarValue {
fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
tcx.mk_mach_float(*self)
tcx.mk_mach_float(self.0)
}
}
impl UnifyKey for ty::TyVid {
type Value = ();
fn index(&self) -> u32 { self.index }
fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } }
fn tag(_: Option<ty::TyVid>) -> &'static str { "TyVid" }
}

View File

@ -92,7 +92,9 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, '
-> ty::ImplHeader<'tcx>
{
let tcx = selcx.tcx();
let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
let impl_substs = selcx.infcx().fresh_substs_for_item(param_env.universe,
DUMMY_SP,
impl_def_id);
let header = ty::ImplHeader {
impl_def_id,

View File

@ -292,7 +292,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.for_each_relevant_impl(
trait_ref.def_id, trait_self_ty, |def_id| {
let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
let impl_substs = self.fresh_substs_for_item(param_env.universe,
obligation.cause.span,
def_id);
let impl_trait_ref = tcx
.impl_trait_ref(def_id)
.unwrap()
@ -1194,6 +1196,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-> bool {
struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>
}
@ -1203,9 +1206,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::TyParam(ty::ParamTy {name, ..}) = ty.sty {
let infcx = self.infcx;
self.var_map.entry(ty).or_insert_with(||
infcx.next_ty_var(
TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, name)))
let param_env = self.param_env;
self.var_map
.entry(ty)
.or_insert_with(|| {
let origin = TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP,
name);
infcx.next_ty_var(param_env.universe, origin)
})
} else {
ty.super_fold_with(self)
}
@ -1217,6 +1225,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let cleaned_pred = pred.fold_with(&mut ParamToVarFolder {
infcx: self,
param_env,
var_map: FxHashMap()
});

View File

@ -77,10 +77,21 @@ pub enum IntercrateMode {
/// scope. The eventual result is usually a `Selection` (defined below).
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Obligation<'tcx, T> {
/// Why do we have to prove this thing?
pub cause: ObligationCause<'tcx>,
/// In which environment should we prove this thing?
pub param_env: ty::ParamEnv<'tcx>,
pub recursion_depth: usize,
/// What are we trying to prove?
pub predicate: T,
/// If we started proving this as a result of trying to prove
/// something else, track the total depth to ensure termination.
/// If this goes over a certain threshold, we abort compilation --
/// in such cases, we can not say whether or not the predicate
/// holds for certain. Stupid halting problem. Such a drag.
pub recursion_depth: usize,
}
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
@ -535,7 +546,8 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
predicates);
let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
unnormalized_env.reveal);
unnormalized_env.reveal,
unnormalized_env.universe);
tcx.infer_ctxt().enter(|infcx| {
// FIXME. We should really... do something with these region
@ -609,7 +621,9 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_param_env_or_error: resolved predicates={:?}",
predicates);
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal)
ty::ParamEnv::new(tcx.intern_predicates(&predicates),
unnormalized_env.reveal,
unnormalized_env.universe)
})
}

View File

@ -469,6 +469,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
let tcx = selcx.infcx().tcx;
let def_id = projection_ty.item_def_id;
let ty_var = selcx.infcx().next_ty_var(
param_env.universe,
TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
let projection = ty::Binder(ty::ProjectionPredicate {
projection_ty,
@ -789,6 +790,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
let tcx = selcx.infcx().tcx;
let def_id = projection_ty.item_def_id;
let new_value = selcx.infcx().next_ty_var(
param_env.universe,
TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
Normalized {
value: new_value,

View File

@ -496,7 +496,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
/// context's self.
fn in_snapshot<R, F>(&mut self, f: F) -> R
where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> R
where F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R
{
// The irrefutable nature of the operation means we don't need to snapshot the
// inferred_obligations vector.
@ -506,7 +506,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
/// Wraps a probe s.t. obligations collected during it are ignored and old obligations are
/// retained.
fn probe<R, F>(&mut self, f: F) -> R
where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> R
where F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R
{
let inferred_obligations_snapshot = self.inferred_obligations.start_snapshot();
let result = self.infcx.probe(|snapshot| f(self, snapshot));
@ -1478,7 +1478,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
snapshot: &infer::CombinedSnapshot)
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
-> bool
{
let poly_trait_predicate =
@ -1549,7 +1549,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
trait_bound: ty::PolyTraitRef<'tcx>,
skol_trait_ref: ty::TraitRef<'tcx>,
skol_map: &infer::SkolemizationMap<'tcx>,
snapshot: &infer::CombinedSnapshot)
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
-> bool
{
assert!(!skol_trait_ref.has_escaping_regions());
@ -2587,7 +2587,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
recursion_depth: usize,
param_env: ty::ParamEnv<'tcx>,
skol_map: infer::SkolemizationMap<'tcx>,
snapshot: &infer::CombinedSnapshot)
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
-> VtableImplData<'tcx, PredicateObligation<'tcx>>
{
debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, skol_map={:?})",
@ -3076,7 +3076,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
fn rematch_impl(&mut self,
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
snapshot: &infer::CombinedSnapshot)
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
-> (Normalized<'tcx, &'tcx Substs<'tcx>>,
infer::SkolemizationMap<'tcx>)
{
@ -3093,7 +3093,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
fn match_impl(&mut self,
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
snapshot: &infer::CombinedSnapshot)
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
-> Result<(Normalized<'tcx, &'tcx Substs<'tcx>>,
infer::SkolemizationMap<'tcx>), ()>
{
@ -3111,7 +3111,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
snapshot);
let skol_obligation_trait_ref = skol_obligation.trait_ref;
let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span,
let impl_substs = self.infcx.fresh_substs_for_item(obligation.param_env.universe,
obligation.cause.span,
impl_def_id);
let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
@ -3288,7 +3289,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
def_id: DefId, // of impl or trait
substs: &Substs<'tcx>, // for impl or trait
skol_map: infer::SkolemizationMap<'tcx>,
snapshot: &infer::CombinedSnapshot)
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
-> Vec<PredicateObligation<'tcx>>
{
debug!("impl_or_trait_obligations(def_id={:?})", def_id);

View File

@ -221,7 +221,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
target_impl: DefId)
-> Result<&'tcx Substs<'tcx>, ()> {
let selcx = &mut SelectionContext::new(&infcx);
let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
let target_substs = infcx.fresh_substs_for_item(param_env.universe, DUMMY_SP, target_impl);
let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx,
param_env,
target_impl,

View File

@ -9,9 +9,8 @@
// except according to those terms.
use hir::def_id::DefId;
use infer::type_variable;
use middle::const_val::ConstVal;
use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
use ty::{self, BoundRegion, Region, Ty, TyCtxt};
use std::fmt;
use syntax::abi;
@ -56,7 +55,6 @@ pub enum TypeError<'tcx> {
CyclicTy(Ty<'tcx>),
ProjectionMismatched(ExpectedFound<DefId>),
ProjectionBoundsLength(ExpectedFound<usize>),
TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
OldStyleLUB(Box<TypeError<'tcx>>),
@ -167,11 +165,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
values.expected,
values.found)
},
TyParamDefaultMismatch(ref values) => {
write!(f, "conflicting type parameter defaults `{}` and `{}`",
values.expected.ty,
values.found.ty)
}
ExistentialMismatch(ref values) => {
report_maybe_different(f, format!("trait `{}`", values.expected),
format!("trait `{}`", values.found))
@ -265,42 +258,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
db.help("consider boxing your closure and/or using it as a trait object");
}
},
TyParamDefaultMismatch(values) => {
let expected = values.expected;
let found = values.found;
db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`",
expected.ty,
found.ty));
match self.hir.span_if_local(expected.def_id) {
Some(span) => {
db.span_note(span, "a default was defined here...");
}
None => {
let item_def_id = self.parent(expected.def_id).unwrap();
db.note(&format!("a default is defined on `{}`",
self.item_path_str(item_def_id)));
}
}
db.span_note(
expected.origin_span,
"...that was applied to an unconstrained type variable here");
match self.hir.span_if_local(found.def_id) {
Some(span) => {
db.span_note(span, "a second default was defined here...");
}
None => {
let item_def_id = self.parent(found.def_id).unwrap();
db.note(&format!("a second default is defined on `{}`",
self.item_path_str(item_def_id)));
}
}
db.span_note(found.origin_span,
"...that also applies to the same type variable here");
}
OldStyleLUB(err) => {
db.note("this was previously accepted by the compiler but has been phased out");
db.note("for more information, see https://github.com/rust-lang/rust/issues/45852");

View File

@ -69,7 +69,7 @@ pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const};
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
pub use self::sty::RegionKind;
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid};
pub use self::sty::BoundRegion::*;
pub use self::sty::InferTy::*;
pub use self::sty::RegionKind::*;
@ -685,12 +685,15 @@ pub struct ClosureUpvar<'tcx> {
pub ty: Ty<'tcx>,
}
#[derive(Clone, Copy, PartialEq)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum IntVarValue {
IntType(ast::IntTy),
UintType(ast::UintTy),
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct FloatVarValue(pub ast::FloatTy);
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct TypeParameterDef {
pub name: Name,
@ -1306,6 +1309,85 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
}
}
/// "Universes" are used during type- and trait-checking in the
/// presence of `for<..>` binders to control what sets of names are
/// visible. Universes are arranged into a tree: the root universe
/// contains names that are always visible. But when you enter into
/// some subuniverse, then it may add names that are only visible
/// within that subtree (but it can still name the names of its
/// ancestor universes).
///
/// To make this more concrete, consider this program:
///
/// ```
/// struct Foo { }
/// fn bar<T>(x: T) {
/// let y: for<'a> fn(&'a u8, Foo) = ...;
/// }
/// ```
///
/// The struct name `Foo` is in the root universe U0. But the type
/// parameter `T`, introduced on `bar`, is in a subuniverse U1 --
/// i.e., within `bar`, we can name both `T` and `Foo`, but outside of
/// `bar`, we cannot name `T`. Then, within the type of `y`, the
/// region `'a` is in a subuniverse U2 of U1, because we can name it
/// inside the fn type but not outside.
///
/// Universes are related to **skolemization** -- which is a way of
/// doing type- and trait-checking around these "forall" binders (also
/// called **universal quantification**). The idea is that when, in
/// the body of `bar`, we refer to `T` as a type, we aren't referring
/// to any type in particular, but rather a kind of "fresh" type that
/// is distinct from all other types we have actually declared. This
/// is called a **skolemized** type, and we use universes to talk
/// about this. In other words, a type name in universe 0 always
/// corresponds to some "ground" type that the user declared, but a
/// type name in a non-zero universe is a skolemized type -- an
/// idealized representative of "types in general" that we use for
/// checking generic functions.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct UniverseIndex(u32);
impl UniverseIndex {
/// The root universe, where things that the user defined are
/// visible.
pub const ROOT: UniverseIndex = UniverseIndex(0);
/// A "subuniverse" corresponds to being inside a `forall` quantifier.
/// So, for example, suppose we have this type in universe `U`:
///
/// ```
/// for<'a> fn(&'a u32)
/// ```
///
/// Once we "enter" into this `for<'a>` quantifier, we are in a
/// subuniverse of `U` -- in this new universe, we can name the
/// region `'a`, but that region was not nameable from `U` because
/// it was not in scope there.
pub fn subuniverse(self) -> UniverseIndex {
UniverseIndex(self.0.checked_add(1).unwrap())
}
pub fn from(v: u32) -> UniverseIndex {
UniverseIndex(v)
}
pub fn as_u32(&self) -> u32 {
self.0
}
pub fn as_usize(&self) -> usize {
self.0 as usize
}
/// Gets the "depth" of this universe in the universe tree. This
/// is not really useful except for e.g. the `HashStable`
/// implementation
pub fn depth(&self) -> u32 {
self.0
}
}
/// When type checking, we use the `ParamEnv` to track
/// details about the set of where-clauses that are in scope at this
/// particular point.
@ -1320,6 +1402,17 @@ pub struct ParamEnv<'tcx> {
/// want `Reveal::All` -- note that this is always paired with an
/// empty environment. To get that, use `ParamEnv::reveal()`.
pub reveal: traits::Reveal,
/// What is the innermost universe we have created? Starts out as
/// `UniverseIndex::root()` but grows from there as we enter
/// universal quantifiers.
///
/// NB: At present, we exclude the universal quantifiers on the
/// item we are type-checking, and just consider those names as
/// part of the root universe. So this would only get incremented
/// when we enter into a higher-ranked (`for<..>`) type or trait
/// bound.
pub universe: UniverseIndex,
}
impl<'tcx> ParamEnv<'tcx> {
@ -2595,7 +2688,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// sure that this will succeed without errors anyway.
let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
traits::Reveal::UserFacing);
traits::Reveal::UserFacing,
ty::UniverseIndex::ROOT);
let body_id = tcx.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
tcx.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id)

View File

@ -13,7 +13,6 @@
//! hand, though we've recently added some macros (e.g.,
//! `BraceStructLiftImpl!`) to help with the tedium.
use infer::type_variable;
use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr};
use ty::{self, Lift, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@ -405,6 +404,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
tcx.lift(&self.caller_bounds).map(|caller_bounds| {
ty::ParamEnv {
reveal: self.reveal,
universe: self.universe,
caller_bounds,
}
})
@ -547,13 +547,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> {
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for type_variable::Default<'a> {
type Lifted = type_variable::Default<'tcx>;
ty, origin_span, def_id
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
type Lifted = ty::error::TypeError<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@ -585,11 +578,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
Sorts(ref x) => return tcx.lift(x).map(Sorts),
TyParamDefaultMismatch(ref x) => {
return tcx.lift(x).map(TyParamDefaultMismatch)
}
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
OldStyleLUB(ref x) => return tcx.lift(x).map(OldStyleLUB),
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
})
}
}
@ -733,8 +723,29 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> { reveal, caller_bounds }
impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::ParamEnv {
reveal: self.reveal,
caller_bounds: self.caller_bounds.fold_with(folder),
universe: self.universe.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
let &ty::ParamEnv { reveal: _, ref universe, ref caller_bounds } = self;
universe.super_visit_with(visitor) || caller_bounds.super_visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::UniverseIndex {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
@ -1177,20 +1188,6 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFoun
}
}
impl<'tcx> TypeFoldable<'tcx> for type_variable::Default<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
type_variable::Default {
ty: self.ty.fold_with(folder),
origin_span: self.origin_span,
def_id: self.def_id
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.ty.visit_with(visitor)
}
}
impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
self.iter().map(|x| x.fold_with(folder)).collect()
@ -1230,7 +1227,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
ProjectionMismatched(x) => ProjectionMismatched(x),
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
Sorts(x) => Sorts(x.fold_with(folder)),
TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)),
ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)),
OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)),
}
@ -1251,7 +1247,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
},
Sorts(x) => x.visit_with(visitor),
OldStyleLUB(ref x) => x.visit_with(visitor),
TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
ExistentialMismatch(x) => x.visit_with(visitor),
CyclicTy(t) => t.visit_with(visitor),
Mismatch |

View File

@ -1028,7 +1028,7 @@ pub enum RegionKind {
/// A skolemized region - basically the higher-ranked version of ReFree.
/// Should not exist after typeck.
ReSkolemized(SkolemizedRegionVid, BoundRegion),
ReSkolemized(ty::UniverseIndex, BoundRegion),
/// Empty lifetime is for data that is never accessed.
/// Bottom in the region lattice. We treat ReEmpty somewhat
@ -1079,11 +1079,6 @@ newtype_index!(RegionVid
DEBUG_FORMAT = custom,
});
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)]
pub struct SkolemizedRegionVid {
pub index: u32,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum InferTy {
TyVar(TyVid),

View File

@ -153,14 +153,15 @@ impl<'tcx> ty::ParamEnv<'tcx> {
/// Construct a trait environment suitable for contexts where
/// there are no where clauses in scope.
pub fn empty(reveal: Reveal) -> Self {
Self::new(ty::Slice::empty(), reveal)
Self::new(ty::Slice::empty(), reveal, ty::UniverseIndex::ROOT)
}
/// Construct a trait environment with the given set of predicates.
pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>,
reveal: Reveal)
reveal: Reveal,
universe: ty::UniverseIndex)
-> Self {
ty::ParamEnv { caller_bounds, reveal }
ty::ParamEnv { caller_bounds, reveal, universe }
}
/// Returns a new parameter environment with the same clauses, but

View File

@ -786,7 +786,7 @@ define_print! {
}
ty::ReSkolemized(id, ref bound_region) => {
write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
write!(f, "ReSkolemized({:?}, {:?})", id, bound_region)
}
ty::ReEmpty => write!(f, "ReEmpty"),
@ -916,6 +916,12 @@ impl fmt::Debug for ty::IntVarValue {
}
}
impl fmt::Debug for ty::FloatVarValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
// The generic impl doesn't work yet because projections are not
// normalized under HRTB.
/*impl<T> fmt::Display for ty::Binder<T>

View File

@ -9,6 +9,7 @@ path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
ena = "0.9.1"
log = "0.4"
serialize = { path = "../libserialize" }
cfg-if = "0.1.2"

View File

@ -39,6 +39,7 @@
#![cfg_attr(test, feature(test))]
extern crate core;
extern crate ena;
#[macro_use]
extern crate log;
extern crate serialize as rustc_serialize; // used by deriving
@ -63,10 +64,10 @@ pub mod indexed_vec;
pub mod obligation_forest;
pub mod sip128;
pub mod snapshot_map;
pub mod snapshot_vec;
pub use ena::snapshot_vec;
pub mod stable_hasher;
pub mod transitive_relation;
pub mod unify;
pub use ena::unify;
pub mod fx;
pub mod tuple_slice;
pub mod control_flow_graph;

View File

@ -1,230 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A utility class for implementing "snapshottable" things; a snapshottable data structure permits
//! you to take a snapshot (via `start_snapshot`) and then, after making some changes, elect either
//! to rollback to the start of the snapshot or commit those changes.
//!
//! This vector is intended to be used as part of an abstraction, not serve as a complete
//! abstraction on its own. As such, while it will roll back most changes on its own, it also
//! supports a `get_mut` operation that gives you an arbitrary mutable pointer into the vector. To
//! ensure that any changes you make this with this pointer are rolled back, you must invoke
//! `record` to record any changes you make and also supplying a delegate capable of reversing
//! those changes.
use self::UndoLog::*;
use std::mem;
use std::ops;
pub enum UndoLog<D: SnapshotVecDelegate> {
/// Indicates where a snapshot started.
OpenSnapshot,
/// Indicates a snapshot that has been committed.
CommittedSnapshot,
/// New variable with given index was created.
NewElem(usize),
/// Variable with given index was changed *from* the given value.
SetElem(usize, D::Value),
/// Extensible set of actions
Other(D::Undo),
}
pub struct SnapshotVec<D: SnapshotVecDelegate> {
values: Vec<D::Value>,
undo_log: Vec<UndoLog<D>>,
}
// Snapshots are tokens that should be created/consumed linearly.
pub struct Snapshot {
// Length of the undo log at the time the snapshot was taken.
length: usize,
}
pub trait SnapshotVecDelegate {
type Value;
type Undo;
fn reverse(values: &mut Vec<Self::Value>, action: Self::Undo);
}
impl<D: SnapshotVecDelegate> SnapshotVec<D> {
pub fn new() -> SnapshotVec<D> {
SnapshotVec {
values: Vec::new(),
undo_log: Vec::new(),
}
}
pub fn with_capacity(n: usize) -> SnapshotVec<D> {
SnapshotVec {
values: Vec::with_capacity(n),
undo_log: Vec::new(),
}
}
fn in_snapshot(&self) -> bool {
!self.undo_log.is_empty()
}
pub fn record(&mut self, action: D::Undo) {
if self.in_snapshot() {
self.undo_log.push(Other(action));
}
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn push(&mut self, elem: D::Value) -> usize {
let len = self.values.len();
self.values.push(elem);
if self.in_snapshot() {
self.undo_log.push(NewElem(len));
}
len
}
pub fn get(&self, index: usize) -> &D::Value {
&self.values[index]
}
/// Returns a mutable pointer into the vec; whatever changes you make here cannot be undone
/// automatically, so you should be sure call `record()` with some sort of suitable undo
/// action.
pub fn get_mut(&mut self, index: usize) -> &mut D::Value {
&mut self.values[index]
}
/// Updates the element at the given index. The old value will saved (and perhaps restored) if
/// a snapshot is active.
pub fn set(&mut self, index: usize, new_elem: D::Value) {
let old_elem = mem::replace(&mut self.values[index], new_elem);
if self.in_snapshot() {
self.undo_log.push(SetElem(index, old_elem));
}
}
pub fn start_snapshot(&mut self) -> Snapshot {
let length = self.undo_log.len();
self.undo_log.push(OpenSnapshot);
Snapshot { length: length }
}
pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog<D>] {
&self.undo_log[snapshot.length..]
}
fn assert_open_snapshot(&self, snapshot: &Snapshot) {
// Or else there was a failure to follow a stack discipline:
assert!(self.undo_log.len() > snapshot.length);
// Invariant established by start_snapshot():
assert!(match self.undo_log[snapshot.length] {
OpenSnapshot => true,
_ => false,
});
}
pub fn rollback_to(&mut self, snapshot: Snapshot) {
debug!("rollback_to({})", snapshot.length);
self.assert_open_snapshot(&snapshot);
while self.undo_log.len() > snapshot.length + 1 {
match self.undo_log.pop().unwrap() {
OpenSnapshot => {
// This indicates a failure to obey the stack discipline.
panic!("Cannot rollback an uncommitted snapshot");
}
CommittedSnapshot => {
// This occurs when there are nested snapshots and
// the inner is committed but outer is rolled back.
}
NewElem(i) => {
self.values.pop();
assert!(self.values.len() == i);
}
SetElem(i, v) => {
self.values[i] = v;
}
Other(u) => {
D::reverse(&mut self.values, u);
}
}
}
let v = self.undo_log.pop().unwrap();
assert!(match v {
OpenSnapshot => true,
_ => false,
});
assert!(self.undo_log.len() == snapshot.length);
}
/// Commits all changes since the last snapshot. Of course, they
/// can still be undone if there is a snapshot further out.
pub fn commit(&mut self, snapshot: Snapshot) {
debug!("commit({})", snapshot.length);
self.assert_open_snapshot(&snapshot);
if snapshot.length == 0 {
// The root snapshot.
self.undo_log.truncate(0);
} else {
self.undo_log[snapshot.length] = CommittedSnapshot;
}
}
}
impl<D: SnapshotVecDelegate> ops::Deref for SnapshotVec<D> {
type Target = [D::Value];
fn deref(&self) -> &[D::Value] {
&*self.values
}
}
impl<D: SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> {
fn deref_mut(&mut self) -> &mut [D::Value] {
&mut *self.values
}
}
impl<D: SnapshotVecDelegate> ops::Index<usize> for SnapshotVec<D> {
type Output = D::Value;
fn index(&self, index: usize) -> &D::Value {
self.get(index)
}
}
impl<D: SnapshotVecDelegate> ops::IndexMut<usize> for SnapshotVec<D> {
fn index_mut(&mut self, index: usize) -> &mut D::Value {
self.get_mut(index)
}
}
impl<D: SnapshotVecDelegate> Extend<D::Value> for SnapshotVec<D> {
fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=D::Value> {
for item in iterable {
self.push(item);
}
}
}

View File

@ -1,363 +0,0 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::marker;
use std::fmt::Debug;
use std::marker::PhantomData;
use snapshot_vec as sv;
#[cfg(test)]
mod tests;
/// This trait is implemented by any type that can serve as a type
/// variable. We call such variables *unification keys*. For example,
/// this trait is implemented by `IntVid`, which represents integral
/// variables.
///
/// Each key type has an associated value type `V`. For example, for
/// `IntVid`, this is `Option<IntVarValue>`, representing some
/// (possibly not yet known) sort of integer.
///
/// Clients are expected to provide implementations of this trait; you
/// can see some examples in the `test` module.
pub trait UnifyKey: Copy + Clone + Debug + PartialEq {
type Value: Clone + PartialEq + Debug;
fn index(&self) -> u32;
fn from_index(u: u32) -> Self;
fn tag(k: Option<Self>) -> &'static str;
}
/// This trait is implemented for unify values that can be
/// combined. This relation should be a monoid.
pub trait Combine {
fn combine(&self, other: &Self) -> Self;
}
impl Combine for () {
fn combine(&self, _other: &()) {}
}
/// Value of a unification key. We implement Tarjan's union-find
/// algorithm: when two keys are unified, one of them is converted
/// into a "redirect" pointing at the other. These redirects form a
/// DAG: the roots of the DAG (nodes that are not redirected) are each
/// associated with a value of type `V` and a rank. The rank is used
/// to keep the DAG relatively balanced, which helps keep the running
/// time of the algorithm under control. For more information, see
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
#[derive(PartialEq,Clone,Debug)]
pub struct VarValue<K: UnifyKey> {
parent: K, // if equal to self, this is a root
value: K::Value, // value assigned (only relevant to root)
rank: u32, // max depth (only relevant to root)
}
/// Table of unification keys and their values.
pub struct UnificationTable<K: UnifyKey> {
/// Indicates the current value of each key.
values: sv::SnapshotVec<Delegate<K>>,
}
/// At any time, users may snapshot a unification table. The changes
/// made during the snapshot may either be *committed* or *rolled back*.
pub struct Snapshot<K: UnifyKey> {
// Link snapshot to the key type `K` of the table.
marker: marker::PhantomData<K>,
snapshot: sv::Snapshot,
}
#[derive(Copy, Clone)]
struct Delegate<K>(PhantomData<K>);
impl<K: UnifyKey> VarValue<K> {
fn new_var(key: K, value: K::Value) -> VarValue<K> {
VarValue::new(key, value, 0)
}
fn new(parent: K, value: K::Value, rank: u32) -> VarValue<K> {
VarValue {
parent: parent, // this is a root
value,
rank,
}
}
fn redirect(self, to: K) -> VarValue<K> {
VarValue { parent: to, ..self }
}
fn root(self, rank: u32, value: K::Value) -> VarValue<K> {
VarValue {
rank,
value,
..self
}
}
/// Returns the key of this node. Only valid if this is a root
/// node, which you yourself must ensure.
fn key(&self) -> K {
self.parent
}
fn parent(&self, self_key: K) -> Option<K> {
self.if_not_self(self.parent, self_key)
}
fn if_not_self(&self, key: K, self_key: K) -> Option<K> {
if key == self_key { None } else { Some(key) }
}
}
/// We can't use V:LatticeValue, much as I would like to,
/// because frequently the pattern is that V=Option<U> for some
/// other type parameter U, and we have no way to say
/// Option<U>:LatticeValue.
impl<K: UnifyKey> UnificationTable<K> {
pub fn new() -> UnificationTable<K> {
UnificationTable { values: sv::SnapshotVec::new() }
}
/// Starts a new snapshot. Each snapshot must be either
/// rolled back or committed in a "LIFO" (stack) order.
pub fn snapshot(&mut self) -> Snapshot<K> {
Snapshot {
marker: marker::PhantomData::<K>,
snapshot: self.values.start_snapshot(),
}
}
/// Reverses all changes since the last snapshot. Also
/// removes any keys that have been created since then.
pub fn rollback_to(&mut self, snapshot: Snapshot<K>) {
debug!("{}: rollback_to()", UnifyKey::tag(None::<K>));
self.values.rollback_to(snapshot.snapshot);
}
/// Commits all changes since the last snapshot. Of course, they
/// can still be undone if there is a snapshot further out.
pub fn commit(&mut self, snapshot: Snapshot<K>) {
debug!("{}: commit()", UnifyKey::tag(None::<K>));
self.values.commit(snapshot.snapshot);
}
pub fn new_key(&mut self, value: K::Value) -> K {
let len = self.values.len();
let key: K = UnifyKey::from_index(len as u32);
self.values.push(VarValue::new_var(key, value));
debug!("{}: created new key: {:?}", UnifyKey::tag(None::<K>), key);
key
}
/// Find the root node for `vid`. This uses the standard
/// union-find algorithm with path compression:
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
///
/// NB. This is a building-block operation and you would probably
/// prefer to call `probe` below.
fn get(&mut self, vid: K) -> VarValue<K> {
let index = vid.index() as usize;
let mut value: VarValue<K> = self.values.get(index).clone();
match value.parent(vid) {
Some(redirect) => {
let root: VarValue<K> = self.get(redirect);
if root.key() != redirect {
// Path compression
value.parent = root.key();
self.values.set(index, value);
}
root
}
None => value,
}
}
fn is_root(&self, key: K) -> bool {
let index = key.index() as usize;
self.values.get(index).parent(key).is_none()
}
/// Sets the value for `vid` to `new_value`. `vid` MUST be a root
/// node! This is an internal operation used to impl other things.
fn set(&mut self, key: K, new_value: VarValue<K>) {
assert!(self.is_root(key));
debug!("Updating variable {:?} to {:?}", key, new_value);
let index = key.index() as usize;
self.values.set(index, new_value);
}
/// Either redirects `node_a` to `node_b` or vice versa, depending
/// on the relative rank. The value associated with the new root
/// will be `new_value`.
///
/// NB: This is the "union" operation of "union-find". It is
/// really more of a building block. If the values associated with
/// your key are non-trivial, you would probably prefer to call
/// `unify_var_var` below.
fn unify(&mut self, root_a: VarValue<K>, root_b: VarValue<K>, new_value: K::Value) -> K {
debug!("unify(root_a(id={:?}, rank={:?}), root_b(id={:?}, rank={:?}))",
root_a.key(),
root_a.rank,
root_b.key(),
root_b.rank);
if root_a.rank > root_b.rank {
// a has greater rank, so a should become b's parent,
// i.e., b should redirect to a.
self.redirect_root(root_a.rank, root_b, root_a, new_value)
} else if root_a.rank < root_b.rank {
// b has greater rank, so a should redirect to b.
self.redirect_root(root_b.rank, root_a, root_b, new_value)
} else {
// If equal, redirect one to the other and increment the
// other's rank.
self.redirect_root(root_a.rank + 1, root_a, root_b, new_value)
}
}
fn redirect_root(&mut self,
new_rank: u32,
old_root: VarValue<K>,
new_root: VarValue<K>,
new_value: K::Value)
-> K {
let old_root_key = old_root.key();
let new_root_key = new_root.key();
self.set(old_root_key, old_root.redirect(new_root_key));
self.set(new_root_key, new_root.root(new_rank, new_value));
new_root_key
}
}
impl<K: UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
type Value = VarValue<K>;
type Undo = ();
fn reverse(_: &mut Vec<VarValue<K>>, _: ()) {}
}
/// # Base union-find algorithm, where we are just making sets
impl<'tcx, K: UnifyKey> UnificationTable<K>
where K::Value: Combine
{
pub fn union(&mut self, a_id: K, b_id: K) -> K {
let node_a = self.get(a_id);
let node_b = self.get(b_id);
let a_id = node_a.key();
let b_id = node_b.key();
if a_id != b_id {
let new_value = node_a.value.combine(&node_b.value);
self.unify(node_a, node_b, new_value)
} else {
a_id
}
}
pub fn find(&mut self, id: K) -> K {
self.get(id).key()
}
pub fn find_value(&mut self, id: K) -> K::Value {
self.get(id).value
}
#[cfg(test)]
fn unioned(&mut self, a_id: K, b_id: K) -> bool {
self.find(a_id) == self.find(b_id)
}
}
/// # Non-subtyping unification
///
/// Code to handle keys which carry a value, like ints,
/// floats---anything that doesn't have a subtyping relationship we
/// need to worry about.
impl<'tcx, K, V> UnificationTable<K>
where K: UnifyKey<Value = Option<V>>,
V: Clone + PartialEq + Debug
{
pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result<K, (V, V)> {
let node_a = self.get(a_id);
let node_b = self.get(b_id);
let a_id = node_a.key();
let b_id = node_b.key();
if a_id == b_id {
return Ok(a_id);
}
let combined = {
match (&node_a.value, &node_b.value) {
(&None, &None) => None,
(&Some(ref v), &None) |
(&None, &Some(ref v)) => Some(v.clone()),
(&Some(ref v1), &Some(ref v2)) => {
if *v1 != *v2 {
return Err((v1.clone(), v2.clone()));
}
Some(v1.clone())
}
}
};
Ok(self.unify(node_a, node_b, combined))
}
/// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
/// relationships, if `a_id` already has a value, it must be the same as `b`.
pub fn unify_var_value(&mut self, a_id: K, b: V) -> Result<(), (V, V)> {
let mut node_a = self.get(a_id);
match node_a.value {
None => {
node_a.value = Some(b);
self.set(node_a.key(), node_a);
Ok(())
}
Some(ref a_t) => {
if *a_t == b {
Ok(())
} else {
Err((a_t.clone(), b))
}
}
}
}
pub fn has_value(&mut self, id: K) -> bool {
self.get(id).value.is_some()
}
pub fn probe(&mut self, a_id: K) -> Option<V> {
self.get(a_id).value
}
pub fn unsolved_variables(&mut self) -> Vec<K> {
self.values
.iter()
.filter_map(|vv| {
if vv.value.is_some() {
None
} else {
Some(vv.key())
}
})
.collect()
}
}

View File

@ -1,205 +0,0 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(non_snake_case)]
extern crate test;
use self::test::Bencher;
use unify::{UnifyKey, UnificationTable};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct UnitKey(u32);
impl UnifyKey for UnitKey {
type Value = ();
fn index(&self) -> u32 {
self.0
}
fn from_index(u: u32) -> UnitKey {
UnitKey(u)
}
fn tag(_: Option<UnitKey>) -> &'static str {
"UnitKey"
}
}
#[test]
fn basic() {
let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
let k1 = ut.new_key(());
let k2 = ut.new_key(());
assert_eq!(ut.unioned(k1, k2), false);
ut.union(k1, k2);
assert_eq!(ut.unioned(k1, k2), true);
}
#[test]
fn big_array() {
let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
let mut keys = Vec::new();
const MAX: usize = 1 << 15;
for _ in 0..MAX {
keys.push(ut.new_key(()));
}
for i in 1..MAX {
let l = keys[i - 1];
let r = keys[i];
ut.union(l, r);
}
for i in 0..MAX {
assert!(ut.unioned(keys[0], keys[i]));
}
}
#[bench]
fn big_array_bench(b: &mut Bencher) {
let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
let mut keys = Vec::new();
const MAX: usize = 1 << 15;
for _ in 0..MAX {
keys.push(ut.new_key(()));
}
b.iter(|| {
for i in 1..MAX {
let l = keys[i - 1];
let r = keys[i];
ut.union(l, r);
}
for i in 0..MAX {
assert!(ut.unioned(keys[0], keys[i]));
}
})
}
#[test]
fn even_odd() {
let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
let mut keys = Vec::new();
const MAX: usize = 1 << 10;
for i in 0..MAX {
let key = ut.new_key(());
keys.push(key);
if i >= 2 {
ut.union(key, keys[i - 2]);
}
}
for i in 1..MAX {
assert!(!ut.unioned(keys[i - 1], keys[i]));
}
for i in 2..MAX {
assert!(ut.unioned(keys[i - 2], keys[i]));
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct IntKey(u32);
impl UnifyKey for IntKey {
type Value = Option<i32>;
fn index(&self) -> u32 {
self.0
}
fn from_index(u: u32) -> IntKey {
IntKey(u)
}
fn tag(_: Option<IntKey>) -> &'static str {
"IntKey"
}
}
/// Test unifying a key whose value is `Some(_)` with a key whose value is `None`.
/// Afterwards both should be `Some(_)`.
#[test]
fn unify_key_Some_key_None() {
let mut ut: UnificationTable<IntKey> = UnificationTable::new();
let k1 = ut.new_key(Some(22));
let k2 = ut.new_key(None);
assert!(ut.unify_var_var(k1, k2).is_ok());
assert_eq!(ut.probe(k2), Some(22));
assert_eq!(ut.probe(k1), Some(22));
}
/// Test unifying a key whose value is `None` with a key whose value is `Some(_)`.
/// Afterwards both should be `Some(_)`.
#[test]
fn unify_key_None_key_Some() {
let mut ut: UnificationTable<IntKey> = UnificationTable::new();
let k1 = ut.new_key(Some(22));
let k2 = ut.new_key(None);
assert!(ut.unify_var_var(k2, k1).is_ok());
assert_eq!(ut.probe(k2), Some(22));
assert_eq!(ut.probe(k1), Some(22));
}
/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(y)`.
/// This should yield an error.
#[test]
fn unify_key_Some_x_key_Some_y() {
let mut ut: UnificationTable<IntKey> = UnificationTable::new();
let k1 = ut.new_key(Some(22));
let k2 = ut.new_key(Some(23));
assert_eq!(ut.unify_var_var(k1, k2), Err((22, 23)));
assert_eq!(ut.unify_var_var(k2, k1), Err((23, 22)));
assert_eq!(ut.probe(k1), Some(22));
assert_eq!(ut.probe(k2), Some(23));
}
/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(x)`.
/// This should be ok.
#[test]
fn unify_key_Some_x_key_Some_x() {
let mut ut: UnificationTable<IntKey> = UnificationTable::new();
let k1 = ut.new_key(Some(22));
let k2 = ut.new_key(Some(22));
assert!(ut.unify_var_var(k1, k2).is_ok());
assert_eq!(ut.probe(k1), Some(22));
assert_eq!(ut.probe(k2), Some(22));
}
/// Test unifying a key whose value is `None` with a value is `x`.
/// Afterwards key should be `x`.
#[test]
fn unify_key_None_val() {
let mut ut: UnificationTable<IntKey> = UnificationTable::new();
let k1 = ut.new_key(None);
assert!(ut.unify_var_value(k1, 22).is_ok());
assert_eq!(ut.probe(k1), Some(22));
}
/// Test unifying a key whose value is `Some(x)` with the value `y`.
/// This should yield an error.
#[test]
fn unify_key_Some_x_val_y() {
let mut ut: UnificationTable<IntKey> = UnificationTable::new();
let k1 = ut.new_key(Some(22));
assert_eq!(ut.unify_var_value(k1, 23), Err((22, 23)));
assert_eq!(ut.probe(k1), Some(22));
}
/// Test unifying a key whose value is `Some(x)` with the value `x`.
/// This should be ok.
#[test]
fn unify_key_Some_x_val_x() {
let mut ut: UnificationTable<IntKey> = UnificationTable::new();
let k1 = ut.new_key(Some(22));
assert!(ut.unify_var_value(k1, 22).is_ok());
assert_eq!(ut.probe(k1), Some(22));
}

View File

@ -444,7 +444,8 @@ fn sub_free_bound_false_infer() {
//! does NOT hold for any instantiation of `_#1`.
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
let t_infer1 = env.infcx.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(DUMMY_SP));
let t_rptr_bound1 = env.t_rptr_late_bound(1);
env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize),
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));

View File

@ -51,7 +51,6 @@ pub trait AstConv<'gcx, 'tcx> {
/// Same as ty_infer, but with a known type parameter definition.
fn ty_infer_for_def(&self,
_def: &ty::TypeParameterDef,
_substs: &[Kind<'tcx>],
span: Span) -> Ty<'tcx> {
self.ty_infer(span)
}
@ -261,7 +260,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
} else if infer_types {
// No type parameters were provided, we can infer all.
let ty_var = if !default_needs_object_self(def) {
self.ty_infer_for_def(def, substs, span)
self.ty_infer_for_def(def, span)
} else {
self.ty_infer(span)
};

View File

@ -329,6 +329,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(
// FIXME: MiscVariable for now, obtaining the span and name information
// from all tuple elements isn't trivial.
ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(pat.span)));
let element_tys = tcx.mk_type_list(element_tys_iter);
let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false));
@ -339,7 +340,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pat_ty
}
PatKind::Box(ref inner) => {
let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span));
let inner_ty = self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(inner.span));
let uniq_ty = tcx.mk_box(inner_ty);
if self.check_dereferencable(pat.span, expected, &inner) {
@ -372,6 +374,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
_ => {
let inner_ty = self.next_ty_var(
ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(inner.span));
let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
let region = self.next_region_var(infer::PatternRegion(pat.span));
@ -630,7 +633,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
// ...but otherwise we want to use any supertype of the
// discriminant. This is sort of a workaround, see note (*) in
// `check_pat` for some details.
discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span));
discrim_ty = self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(discrim.span));
self.check_expr_has_type_or_error(discrim, discrim_ty);
};
@ -691,7 +695,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
// arm for inconsistent arms or to the whole match when a `()` type
// is required).
Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety,
_ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)),
_ => self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(expr.span)),
};
CoerceMany::with_coercion_sites(coerce_first, arms)
};

View File

@ -110,7 +110,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|_, _| span_bug!(expr.span, "closure has region param"),
|_, _| {
self.infcx
.next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span))
.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::ClosureSynthetic(expr.span))
},
);
let substs = ty::ClosureSubsts { substs };

View File

@ -177,6 +177,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
// micro-optimization: no need for this if `b` is
// already resolved in some way.
let diverging_ty = self.next_diverging_ty_var(
ty::UniverseIndex::ROOT,
TypeVariableOrigin::AdjustmentType(self.cause.span));
self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
} else {
@ -510,7 +511,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
// We only have the latter, so we use an inference variable
// for the former and let type inference do the rest.
let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
let coerce_target = self.next_ty_var(origin);
let coerce_target = self.next_ty_var(ty::UniverseIndex::ROOT, origin);
let mut coercion = self.unify_and(coerce_target, target, |target| {
let unsize = Adjustment {
kind: Adjust::Unsize,

View File

@ -218,7 +218,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates),
Reveal::UserFacing);
Reveal::UserFacing,
ty::UniverseIndex::ROOT);
let param_env = traits::normalize_param_env_or_error(tcx,
impl_m.def_id,
param_env,

View File

@ -90,7 +90,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
let drop_impl_span = tcx.def_span(drop_impl_did);
let fresh_impl_substs =
infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
infcx.fresh_substs_for_item(ty::UniverseIndex::ROOT, drop_impl_span, drop_impl_did);
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);

View File

@ -259,7 +259,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
// the process we will unify the transformed-self-type
// of the method with the actual type in order to
// unify some of these variables.
self.fresh_substs_for_item(self.span, trait_def_id)
self.fresh_substs_for_item(ty::UniverseIndex::ROOT, self.span, trait_def_id)
}
probe::WhereClausePick(ref poly_trait_ref) => {
@ -325,7 +325,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
} else {
self.region_var_for_def(self.span, def)
}
}, |def, cur_substs| {
}, |def, _cur_substs| {
let i = def.index as usize;
if i < parent_substs.len() {
parent_substs.type_at(i)
@ -336,7 +336,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
{
self.to_ty(ast_ty)
} else {
self.type_var_for_def(self.span, def, cur_substs)
self.type_var_for_def(ty::UniverseIndex::ROOT, self.span, def)
}
})
}

View File

@ -249,13 +249,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let substs = Substs::for_item(self.tcx,
trait_def_id,
|def, _| self.region_var_for_def(span, def),
|def, substs| {
|def, _substs| {
if def.index == 0 {
self_ty
} else if let Some(ref input_types) = opt_input_types {
input_types[def.index as usize - 1]
} else {
self.type_var_for_def(span, def, substs)
self.type_var_for_def(ty::UniverseIndex::ROOT, span, def)
}
});

View File

@ -730,7 +730,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
Def::Method(def_id) => {
let fty = self.tcx.fn_sig(def_id);
self.probe(|_| {
let substs = self.fresh_substs_for_item(self.span, method.def_id);
let substs = self.fresh_substs_for_item(ty::UniverseIndex::ROOT,
self.span,
method.def_id);
let fty = fty.subst(self.tcx, substs);
let (fty, _) = self.replace_late_bound_regions_with_fresh_var(
self.span, infer::FnCall, &fty);
@ -1304,12 +1306,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
// `impl_self_ty()` for an explanation.
self.tcx.types.re_erased
}
}, |def, cur_substs| {
}, |def, _cur_substs| {
let i = def.index as usize;
if i < substs.len() {
substs.type_at(i)
} else {
self.type_var_for_def(self.span, def, cur_substs)
self.type_var_for_def(ty::UniverseIndex::ROOT, self.span, def)
}
});
xform_fn_sig.subst(self.tcx, substs)
@ -1326,6 +1328,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
def_id,
|_, _| self.tcx.types.re_erased,
|_, _| self.next_ty_var(
ty::UniverseIndex::ROOT,
TypeVariableOrigin::SubstitutionPlaceholder(
self.tcx.def_span(def_id))))
}

View File

@ -54,7 +54,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.autoderef(span, ty).any(|(ty, _)| {
self.probe(|_| {
let fn_once_substs = tcx.mk_substs_trait(ty,
&[self.next_ty_var(TypeVariableOrigin::MiscVariable(span))]);
&[self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(span))]);
let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
let poly_trait_ref = trait_ref.to_poly_trait_ref();
let obligation =

View File

@ -362,7 +362,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
/// hard constraint exists, creates a fresh type variable.
fn coercion_target_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> {
self.only_has_type(fcx)
.unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span)))
.unwrap_or_else(|| fcx.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(span)))
}
}
@ -921,7 +922,8 @@ impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> {
match ty_opt {
None => {
// infer the variable's type
let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
let var_ty = self.fcx.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(span));
self.fcx.locals.borrow_mut().insert(nid, var_ty);
var_ty
}
@ -1025,7 +1027,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
let span = body.value.span;
if body.is_generator && can_be_generator.is_some() {
let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
let yield_ty = fcx.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(span));
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
fcx.yield_ty = Some(yield_ty);
}
@ -1058,7 +1061,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
// This ensures that all nested generators appear before the entry of this generator.
// resolve_generator_interiors relies on this property.
let gen_ty = if can_be_generator.is_some() && body.is_generator {
let witness = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span));
let witness = fcx.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(span));
let interior = ty::GeneratorInterior {
witness,
movable: can_be_generator.unwrap() == hir::GeneratorMovability::Movable,
@ -1096,6 +1100,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
let mut actual_return_ty = coercion.complete(&fcx);
if actual_return_ty.is_never() {
actual_return_ty = fcx.next_diverging_ty_var(
ty::UniverseIndex::ROOT,
TypeVariableOrigin::DivergingFn(span));
}
fcx.demand_suptype(span, ret_ty, actual_return_ty);
@ -1687,14 +1692,14 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
}
fn ty_infer(&self, span: Span) -> Ty<'tcx> {
self.next_ty_var(TypeVariableOrigin::TypeInference(span))
self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(span))
}
fn ty_infer_for_def(&self,
ty_param_def: &ty::TypeParameterDef,
substs: &[Kind<'tcx>],
span: Span) -> Ty<'tcx> {
self.type_var_for_def(span, ty_param_def, substs)
self.type_var_for_def(ty::UniverseIndex::ROOT, span, ty_param_def)
}
fn projected_ty_from_poly_trait_ref(&self,
@ -2316,7 +2321,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// If some lookup succeeds, write callee into table and extract index/element
// type from the method signature.
// If some lookup succeeded, install method in table
let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
let input_ty = self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::AutoDeref(base_expr.span));
let method = self.try_overloaded_place_op(
expr.span, self_ty, &[input_ty], needs, PlaceOp::Index);
@ -2755,6 +2761,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
assert!(!self.tables.borrow().adjustments().contains_key(expr.hir_id),
"expression with never type wound up being adjusted");
let adj_ty = self.next_diverging_ty_var(
ty::UniverseIndex::ROOT,
TypeVariableOrigin::AdjustmentType(expr.span));
self.apply_adjustments(expr, vec![Adjustment {
kind: Adjust::NeverToAny,
@ -2832,7 +2839,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let ity = self.tcx.type_of(did);
debug!("impl_self_ty: ity={:?}", ity);
let substs = self.fresh_substs_for_item(span, did);
let substs = self.fresh_substs_for_item(ty::UniverseIndex::ROOT, span, did);
let substd_ty = self.instantiate_type_scheme(span, &substs, &ity);
TypeAndSubsts { substs: substs, ty: substd_ty }
@ -3972,7 +3979,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let element_ty = if !args.is_empty() {
let coerce_to = uty.unwrap_or_else(
|| self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)));
|| self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(expr.span)));
let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
assert_eq!(self.diverges.get(), Diverges::Maybe);
for e in args {
@ -3982,7 +3990,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
coerce.complete(self)
} else {
self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))
self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::TypeInference(expr.span))
};
tcx.mk_array(element_ty, args.len() as u64)
}
@ -4012,7 +4021,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
(uty, uty)
}
None => {
let t: Ty = self.next_ty_var(TypeVariableOrigin::MiscVariable(element.span));
let t: Ty = self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(element.span));
let element_ty = self.check_expr_has_type_or_error(&element, t);
(element_ty, t)
}
@ -4793,7 +4803,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Handle Self first, so we can adjust the index to match the AST.
if has_self && i == 0 {
return opt_self_ty.unwrap_or_else(|| {
self.type_var_for_def(span, def, substs)
self.type_var_for_def(ty::UniverseIndex::ROOT, span, def)
});
}
i -= has_self as usize;
@ -4826,7 +4836,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// This can also be reached in some error cases:
// We prefer to use inference variables instead of
// TyError to let type inference recover somewhat.
self.type_var_for_def(span, def, substs)
self.type_var_for_def(ty::UniverseIndex::ROOT, span, def)
}
});

View File

@ -174,8 +174,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// trait matching creating lifetime constraints that are too strict.
// E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
// in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
let lhs_ty = self.check_expr_coercable_to_type_with_needs(lhs_expr,
self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span)),
let lhs_ty = self.check_expr_coercable_to_type_with_needs(
lhs_expr,
self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(lhs_expr.span)),
lhs_needs);
let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
@ -185,7 +187,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// using this variable as the expected type, which sometimes lets
// us do better coercions than we would be able to do otherwise,
// particularly for things like `String + &String`.
let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span));
let rhs_ty_var = self.next_ty_var(ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(rhs_expr.span));
let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign));

View File

@ -681,12 +681,17 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
computed_preds.extend(user_computed_preds.iter().cloned());
let normalized_preds =
traits::elaborate_predicates(tcx, computed_preds.clone().into_iter().collect());
new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal);
new_env = ty::ParamEnv::new(
tcx.mk_predicates(normalized_preds),
param_env.reveal,
ty::UniverseIndex::ROOT,
);
}
let final_user_env = ty::ParamEnv::new(
tcx.mk_predicates(user_computed_preds.into_iter()),
user_env.reveal,
ty::UniverseIndex::ROOT,
);
debug!(
"evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \