diff --git a/src/Cargo.lock b/src/Cargo.lock index 53744dca0a012..2cc647c49c627 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -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" diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 71a57dbf32fb1..7b2cfa0a3ffec 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -870,6 +870,7 @@ for ty::steal::Steal impl_stable_hash_for!(struct ty::ParamEnv<'tcx> { caller_bounds, + universe, reveal }); @@ -1039,3 +1040,12 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable HashStable> +for ty::UniverseIndex { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + self.depth().hash_stable(hcx, hasher); + } +} diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index a749d0dddd7ee..eb26f0c1188bf 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -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); diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index f7bc092a3d7ae..469cb4591124e 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -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)) } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 8b61fcff2335e..ee0921f4b07ae 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -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) diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 756a6947ee3f8..48eb253415cdf 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -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) } } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 57e237fb9137f..a317e0699b4bb 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -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>, @@ -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>, @@ -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> { @@ -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 { /*! @@ -583,7 +583,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// See `README.md` for more details. pub fn skolemize_late_bound_regions(&self, binder: &ty::Binder, - 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(&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() diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index d5c1163cfc1b1..c4722f9a7f96c 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -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`. 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) } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 7a386c144b738..402cb6a8fef43 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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>, // Map from integral variable to the kind of integer it represents - int_unification_table: RefCell>, + int_unification_table: RefCell>>, // Map from floating variable to the kind of float it represents - float_unification_table: RefCell>, + float_unification_table: RefCell>>, // 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, - float_snapshot: unify::Snapshot, + type_snapshot: type_variable::Snapshot<'tcx>, + int_snapshot: ut::Snapshot>, + float_snapshot: ut::Snapshot>, 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> { - match ty.sty { - ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid), - _ => None - } - } - pub fn unsolved_variables(&self) -> Vec> { 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 unbound_int_vars = self.int_unification_table - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|v| self.tcx.mk_int_var(v)); + { + 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_float_vars = self.float_unification_table - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|v| self.tcx.mk_float_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))); + } - 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(&self, f: F) -> Result where - F: FnOnce(&CombinedSnapshot) -> Result + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result { 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(&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(&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( &self, span: Span, diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index be196192371fd..4a75037aa5035 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -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, + unification_table: ut::UnificationTable>, } pub type VarOrigins = IndexVec; @@ -232,8 +232,8 @@ type CombineMap<'tcx> = FxHashMap, RegionVid>; pub struct RegionSnapshot { length: usize, - region_snapshot: unify::Snapshot, - skolemization_count: u32, + region_snapshot: ut::Snapshot>, + 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 ) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 6aa094d2cd6d7..5daac988f80b7 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -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>, + /// 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, /// Two variables are unified in `eq_relations` when we have a - /// constraint `?X == ?Y`. - eq_relations: ut::UnificationTable, + /// constraint `?X == ?Y`. This table also stores, for each key, + /// the known value. + eq_relations: ut::UnificationTable>>, /// 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` for any `?3`. - sub_relations: ut::UnificationTable, + sub_relations: ut::UnificationTable>, } /// Reasons to create a type inference variable @@ -72,73 +74,91 @@ pub enum TypeVariableOrigin { pub type TypeVariableMap = FxHashMap; -struct TypeVariableData<'tcx> { - value: TypeVariableValue<'tcx>, +struct TypeVariableData { origin: TypeVariableOrigin, diverging: bool } -enum TypeVariableValue<'tcx> { - Known(Ty<'tcx>), - Bounded { - default: Option> - } +#[derive(Copy, Clone, Debug)] +pub enum TypeVariableValue<'tcx> { + Known { value: Ty<'tcx> }, + Unknown { universe: ty::UniverseIndex }, } -// 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 +#[derive(Copy, Clone, Debug)] +pub enum ProbeTyValue<'tcx> { + Ty(Ty<'tcx>), + Vid(ty::TyVid), } -pub struct Snapshot { - snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot, - sub_snapshot: ut::Snapshot, -} +impl<'tcx> TypeVariableValue<'tcx> { + /// If this value is known, returns the type it is known to be. + /// Otherwise, `None`. + pub fn known(&self) -> Option> { + match *self { + TypeVariableValue::Unknown { .. } => None, + TypeVariableValue::Known { value } => Some(value), + } + } -struct Instantiate<'tcx> { - vid: ty::TyVid, - default: Option>, + /// If this value is unknown, returns the universe, otherwise `None`. + pub fn universe(&self) -> Option { + match *self { + TypeVariableValue::Unknown { universe } => Some(universe), + TypeVariableValue::Known { .. } => None, + } + } + + pub fn is_unknown(&self) -> bool { + match *self { + TypeVariableValue::Unknown { .. } => true, + TypeVariableValue::Known { .. } => false, + } + } } -struct Delegate<'tcx>(PhantomData<&'tcx ()>); +pub struct Snapshot<'tcx> { + /// number of variables at the time of the snapshot + num_vars: usize, + + /// snapshot from the `eq_relations` table + eq_snapshot: ut::Snapshot>>, + + /// snapshot from the `sub_relations` table + sub_snapshot: ut::Snapshot>, +} 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> { - 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>,) -> 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> { - 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> { - 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> { - /*! - * 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> { + // 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 { - (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>, 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>, +} + +impl<'tcx> From 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 { + 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" } +} + diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index 99b11794cc5b5..a1145572b79d9 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -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; fn index(&self) -> u32 { self.index } fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } - fn tag(_: Option) -> &'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 { + 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) -> &'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; + type Value = Option; fn index(&self) -> u32 { self.index } fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } - fn tag(_: Option) -> &'static str { "FloatVid" } + fn tag() -> &'static str { "FloatVid" } } -impl ToType for ast::FloatTy { - fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - tcx.mk_mach_float(*self) - } +impl EqUnifyValue for FloatVarValue { } -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) -> &'static str { "TyVid" } +impl ToType for FloatVarValue { + fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + tcx.mk_mach_float(self.0) + } } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index a9f1c8750f4be..183b1a5470e5a 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -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, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 118d4ddd4457b..dba23c22647f8 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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>> } @@ -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() }); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c1ffc10c3c0f0..76d3c7f150670 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -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) }) } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 1cf92d5a78669..3fe72344e8fea 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -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, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f21ec295c5f7b..9e24a4e6afacf 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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(&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(&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> { debug!("impl_or_trait_obligations(def_id={:?})", def_id); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 72d9dd9012ca9..5dfeb1bb42928 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -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, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 583612f9590f1..be89aeebdea75 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -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), ProjectionBoundsLength(ExpectedFound), - TyParamDefaultMismatch(ExpectedFound>), ExistentialMismatch(ExpectedFound<&'tcx ty::Slice>>), OldStyleLUB(Box>), @@ -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"); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3ab2cd274b90e..88422a3ef8235 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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(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) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0dc1338fff860..6147b52844fe4 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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 { } } -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 { @@ -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 { } } -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>(&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>(&self, _visitor: &mut V) -> bool { + false + } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { @@ -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>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) - } -} - impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec { 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 | diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a18e8f578364d..7bcc816b5f03d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -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), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 110808919e905..44771444c8aa8 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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>, - 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 diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 37d1c568515b5..40c8e8aa4a29a 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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 fmt::Display for ty::Binder diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 23e42f6a672c6..e1f0a74fc683d 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -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" diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 33d760d0a1482..265c64858300b 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -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; diff --git a/src/librustc_data_structures/snapshot_vec.rs b/src/librustc_data_structures/snapshot_vec.rs deleted file mode 100644 index 2da91918288ba..0000000000000 --- a/src/librustc_data_structures/snapshot_vec.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - /// 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 { - values: Vec, - undo_log: Vec>, -} - -// 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, action: Self::Undo); -} - -impl SnapshotVec { - pub fn new() -> SnapshotVec { - SnapshotVec { - values: Vec::new(), - undo_log: Vec::new(), - } - } - - pub fn with_capacity(n: usize) -> SnapshotVec { - 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] { - &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 ops::Deref for SnapshotVec { - type Target = [D::Value]; - fn deref(&self) -> &[D::Value] { - &*self.values - } -} - -impl ops::DerefMut for SnapshotVec { - fn deref_mut(&mut self) -> &mut [D::Value] { - &mut *self.values - } -} - -impl ops::Index for SnapshotVec { - type Output = D::Value; - fn index(&self, index: usize) -> &D::Value { - self.get(index) - } -} - -impl ops::IndexMut for SnapshotVec { - fn index_mut(&mut self, index: usize) -> &mut D::Value { - self.get_mut(index) - } -} - -impl Extend for SnapshotVec { - fn extend(&mut self, iterable: T) where T: IntoIterator { - for item in iterable { - self.push(item); - } - } -} diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs deleted file mode 100644 index 5411ae0257a4b..0000000000000 --- a/src/librustc_data_structures/unify/mod.rs +++ /dev/null @@ -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 or the MIT license -// , 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`, 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) -> &'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 -/// . -#[derive(PartialEq,Clone,Debug)] -pub struct VarValue { - 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 { - /// Indicates the current value of each key. - values: sv::SnapshotVec>, -} - -/// 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 { - // Link snapshot to the key type `K` of the table. - marker: marker::PhantomData, - snapshot: sv::Snapshot, -} - -#[derive(Copy, Clone)] -struct Delegate(PhantomData); - -impl VarValue { - fn new_var(key: K, value: K::Value) -> VarValue { - VarValue::new(key, value, 0) - } - - fn new(parent: K, value: K::Value, rank: u32) -> VarValue { - VarValue { - parent: parent, // this is a root - value, - rank, - } - } - - fn redirect(self, to: K) -> VarValue { - VarValue { parent: to, ..self } - } - - fn root(self, rank: u32, value: K::Value) -> VarValue { - 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 { - self.if_not_self(self.parent, self_key) - } - - fn if_not_self(&self, key: K, self_key: K) -> Option { - 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 for some -/// other type parameter U, and we have no way to say -/// Option:LatticeValue. - -impl UnificationTable { - pub fn new() -> UnificationTable { - 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 { - Snapshot { - marker: marker::PhantomData::, - 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) { - debug!("{}: rollback_to()", UnifyKey::tag(None::)); - 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) { - debug!("{}: commit()", UnifyKey::tag(None::)); - 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::), key); - key - } - - /// Find the root node for `vid`. This uses the standard - /// union-find algorithm with path compression: - /// . - /// - /// NB. This is a building-block operation and you would probably - /// prefer to call `probe` below. - fn get(&mut self, vid: K) -> VarValue { - let index = vid.index() as usize; - let mut value: VarValue = self.values.get(index).clone(); - match value.parent(vid) { - Some(redirect) => { - let root: VarValue = 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) { - 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, root_b: VarValue, 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, - new_root: VarValue, - 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 sv::SnapshotVecDelegate for Delegate { - type Value = VarValue; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -/// # Base union-find algorithm, where we are just making sets - -impl<'tcx, K: UnifyKey> UnificationTable - 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 - where K: UnifyKey>, - V: Clone + PartialEq + Debug -{ - pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result { - 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 { - self.get(a_id).value - } - - pub fn unsolved_variables(&mut self) -> Vec { - self.values - .iter() - .filter_map(|vv| { - if vv.value.is_some() { - None - } else { - Some(vv.key()) - } - }) - .collect() - } -} diff --git a/src/librustc_data_structures/unify/tests.rs b/src/librustc_data_structures/unify/tests.rs deleted file mode 100644 index f29a7132e831b..0000000000000 --- a/src/librustc_data_structures/unify/tests.rs +++ /dev/null @@ -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 or the MIT license -// , 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) -> &'static str { - "UnitKey" - } -} - -#[test] -fn basic() { - let mut ut: UnificationTable = 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 = 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 = 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 = 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; - fn index(&self) -> u32 { - self.0 - } - fn from_index(u: u32) -> IntKey { - IntKey(u) - } - fn tag(_: Option) -> &'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 = 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 = 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 = 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 = 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 = 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 = 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 = 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)); -} diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 35d2205cf33f3..665a71a90898d 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -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)); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 650e530519887..bc1b70ffc8e1c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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) }; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 427641aaf0951..da66a2e52e81f 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -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) }; diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 794d466ee7cdb..5e0c47f18bf5a 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -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 }; diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 47e4b0272bed4..e2d6817697e8f 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -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, diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 4c10f28eb8e5d..d0419382bc312 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -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, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 039669a62e104..165cfe6604e8b 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -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); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 20d5899149645..b777ac30920cd 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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) } }) } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 58d72e37d51cf..af86570309dfd 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -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) } }); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9f3e44f56dae2..c95ead285594b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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)))) } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 4556b5a42b3d6..5c20490f82303 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -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 = diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 91fa3c5da6991..df3d081f898a7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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) } }); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a28625be2c739..12791107ebb41 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -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)); diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 3654de6fb2ed2..370fc9bbca243 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -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 '{:?}' \