From 803bd761278e6e06baabfd5aa1aa15e75c4a16a4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 15 Jul 2017 06:41:19 -0400 Subject: [PATCH 01/22] introduce `Universe` struct --- src/librustc/ty/mod.rs | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3ab2cd274b90e..26fcd5c311056 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1306,6 +1306,68 @@ 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)] +pub struct UniverseIndex(u32); + +impl UniverseIndex { + /// The root universe, where things that the user defined are + /// visible. + pub fn 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 + 1) + } +} + /// When type checking, we use the `ParamEnv` to track /// details about the set of where-clauses that are in scope at this /// particular point. From e7efce23618adcc9c960e1518d00883da8a8c444 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 15 Jul 2017 06:47:30 -0400 Subject: [PATCH 02/22] add some comments to `Obligation` --- src/librustc/traits/mod.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c1ffc10c3c0f0..027ad4174bd15 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>>; From d4df52cacbee5d95e912a43188192a5054d36b4f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 15 Jul 2017 07:23:28 -0400 Subject: [PATCH 03/22] introduce `UniverseIndex` into `ParamEnv` Always using root environment for now. --- src/librustc/ich/impls_ty.rs | 10 ++++++++ src/librustc/traits/mod.rs | 7 ++++-- src/librustc/ty/mod.rs | 25 ++++++++++++++++---- src/librustc/ty/structural_impls.rs | 26 +++++++++++++++++++-- src/librustc/ty/util.rs | 7 +++--- src/librustc_typeck/check/compare_method.rs | 3 ++- 6 files changed, 66 insertions(+), 12 deletions(-) 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/traits/mod.rs b/src/librustc/traits/mod.rs index 027ad4174bd15..76d3c7f150670 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -546,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 @@ -620,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/ty/mod.rs b/src/librustc/ty/mod.rs index 26fcd5c311056..856c53d19c98c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1348,9 +1348,7 @@ pub struct UniverseIndex(u32); impl UniverseIndex { /// The root universe, where things that the user defined are /// visible. - pub fn root() -> UniverseIndex { - UniverseIndex(0) - } + 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`: @@ -1366,6 +1364,13 @@ impl UniverseIndex { pub fn subuniverse(self) -> UniverseIndex { UniverseIndex(self.0 + 1) } + + /// 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 @@ -1382,6 +1387,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> { @@ -2657,7 +2673,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..3a1ad8db9c20a 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -405,6 +405,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, } }) @@ -733,8 +734,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> { 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_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, From d516b263c6bda687bc5ca52e6940cd5f5bd40149 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 15 Jul 2017 14:47:49 -0400 Subject: [PATCH 04/22] use `{}` for `Known` variant just for more parity --- src/librustc/infer/type_variable.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 6aa094d2cd6d7..d89625ac871a7 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -79,7 +79,9 @@ struct TypeVariableData<'tcx> { } enum TypeVariableValue<'tcx> { - Known(Ty<'tcx>), + Known { + value: Ty<'tcx> + }, Bounded { default: Option> } @@ -120,7 +122,7 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn default(&self, vid: ty::TyVid) -> Option> { match &self.values.get(vid.index as usize).value { - &Known(_) => None, + &Known { .. } => None, &Bounded { ref default, .. } => default.clone() } } @@ -161,14 +163,14 @@ impl<'tcx> TypeVariableTable<'tcx> { let old_value = { let vid_data = &mut self.values[vid.index as usize]; - mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty)) + mem::replace(&mut vid_data.value, TypeVariableValue::Known { value: ty }) }; match old_value { TypeVariableValue::Bounded { default } => { self.values.record(Instantiate { vid: vid, default: default }); } - TypeVariableValue::Known(old_ty) => { + TypeVariableValue::Known { value: old_ty } => { bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", vid, ty, old_ty) } @@ -236,7 +238,7 @@ impl<'tcx> TypeVariableTable<'tcx> { debug_assert!(self.root_var(vid) == vid); match self.values.get(vid.index as usize).value { Bounded { .. } => None, - Known(t) => Some(t) + Known { value } => Some(value) } } @@ -337,7 +339,7 @@ impl<'tcx> TypeVariableTable<'tcx> { // created since the snapshot started or not. let escaping_type = match self.values.get(vid.index as usize).value { Bounded { .. } => bug!(), - Known(ty) => ty, + Known { value } => value, }; escaping_types.push(escaping_type); } From 7112d6584c355fa13df5cb672befb0f7c383cafb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 15 Jul 2017 14:52:32 -0400 Subject: [PATCH 05/22] make `Default` Copy and Clone --- src/librustc/infer/type_variable.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index d89625ac871a7..36afb8b536725 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -89,7 +89,7 @@ enum TypeVariableValue<'tcx> { // We will use this to store the required information to recapitulate what happened when // an error occurs. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct Default<'tcx> { pub ty: Ty<'tcx>, /// The span where the default was incurred @@ -123,7 +123,7 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn default(&self, vid: ty::TyVid) -> Option> { match &self.values.get(vid.index as usize).value { &Known { .. } => None, - &Bounded { ref default, .. } => default.clone() + &Bounded { default, .. } => default, } } @@ -185,7 +185,7 @@ impl<'tcx> TypeVariableTable<'tcx> { self.eq_relations.new_key(()); self.sub_relations.new_key(()); let index = self.values.push(TypeVariableData { - value: Bounded { default: default }, + value: Bounded { default }, origin, diverging, }); From 047a8d016111c5a12beba2202c61df5b897eea45 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 15 Jul 2017 18:24:51 -0400 Subject: [PATCH 06/22] kill custom type inference defaults (these don't really work anyway) --- src/librustc/infer/mod.rs | 23 +++++---------------- src/librustc_typeck/astconv.rs | 3 +-- src/librustc_typeck/check/method/confirm.rs | 4 ++-- src/librustc_typeck/check/method/mod.rs | 4 ++-- src/librustc_typeck/check/method/probe.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 9 ++++---- 6 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 7a386c144b738..349a2af5aa9ab 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -22,7 +22,7 @@ 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}; @@ -1093,26 +1093,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// as the substitutions for the default, `(T, U)`. pub fn type_var_for_def(&self, 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); + None); self.tcx.mk_var(ty_var_id) } @@ -1125,8 +1112,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> &'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(span, def) }) } 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/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 20d5899149645..a3233c8d86599 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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(self.span, def) } }) } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 58d72e37d51cf..4a122fbc4c195 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(span, def) } }); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9f3e44f56dae2..0a20af23e2e9d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1304,12 +1304,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(self.span, def) } }); xform_fn_sig.subst(self.tcx, substs) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 91fa3c5da6991..4fa48d96d36c4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -93,7 +93,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::anon_types::AnonTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; -use rustc::ty::subst::{Kind, Subst, Substs}; +use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -1692,9 +1692,8 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { 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(span, ty_param_def) } fn projected_ty_from_poly_trait_ref(&self, @@ -4793,7 +4792,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(span, def) }); } i -= has_self as usize; @@ -4826,7 +4825,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(span, def) } }); From b680b12e949097602dd6d39009fee8c95d86a261 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 16 Jul 2017 04:55:48 -0400 Subject: [PATCH 07/22] kill supporting code from type-variable defaults This was all unused anyway. --- src/librustc/infer/combine.rs | 2 +- src/librustc/infer/mod.rs | 43 ++----------------------- src/librustc/infer/type_variable.rs | 50 ++++++++--------------------- src/librustc/ty/error.rs | 45 +------------------------- src/librustc/ty/structural_impls.rs | 29 +---------------- 5 files changed, 18 insertions(+), 151 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index f7bc092a3d7ae..bd175c510fba3 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -424,7 +424,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' } let origin = variables.origin(vid); - let new_var_id = variables.new_var(false, origin, None); + let new_var_id = variables.new_var(false, origin); let u = self.tcx().mk_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 349a2af5aa9ab..4292845792560 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -695,22 +695,6 @@ 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(); @@ -1029,7 +1013,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { self.type_variables .borrow_mut() - .new_var(diverging, origin, None) + .new_var(diverging, origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { @@ -1098,8 +1082,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let ty_var_id = self.type_variables .borrow_mut() .new_var(false, - TypeVariableOrigin::TypeParameterDefinition(span, def.name), - None); + TypeVariableOrigin::TypeParameterDefinition(span, def.name)); self.tcx.mk_var(ty_var_id) } @@ -1389,28 +1372,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/type_variable.rs b/src/librustc/infer/type_variable.rs index 36afb8b536725..e07cc92ec2158 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -9,7 +9,6 @@ // except according to those terms. use self::TypeVariableValue::*; -use hir::def_id::{DefId}; use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; @@ -82,20 +81,7 @@ enum TypeVariableValue<'tcx> { Known { value: Ty<'tcx> }, - Bounded { - default: Option> - } -} - -// We will use this to store the required information to recapitulate what happened when -// an error occurs. -#[derive(Copy, 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 + Unknown, } pub struct Snapshot { @@ -104,9 +90,8 @@ pub struct Snapshot { sub_snapshot: ut::Snapshot, } -struct Instantiate<'tcx> { +struct Instantiate { vid: ty::TyVid, - default: Option>, } struct Delegate<'tcx>(PhantomData<&'tcx ()>); @@ -120,13 +105,6 @@ impl<'tcx> TypeVariableTable<'tcx> { } } - pub fn default(&self, vid: ty::TyVid) -> Option> { - match &self.values.get(vid.index as usize).value { - &Known { .. } => None, - &Bounded { default, .. } => default, - } - } - pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool { self.values.get(vid.index as usize).diverging } @@ -167,8 +145,8 @@ impl<'tcx> TypeVariableTable<'tcx> { }; match old_value { - TypeVariableValue::Bounded { default } => { - self.values.record(Instantiate { vid: vid, default: default }); + TypeVariableValue::Unknown => { + self.values.record(Instantiate { vid: vid }); } TypeVariableValue::Known { value: old_ty } => { bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", @@ -179,13 +157,13 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn new_var(&mut self, diverging: bool, - origin: TypeVariableOrigin, - default: Option>,) -> ty::TyVid { + origin: TypeVariableOrigin) + -> 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 }, + value: Unknown, origin, diverging, }); @@ -237,7 +215,7 @@ impl<'tcx> TypeVariableTable<'tcx> { 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, + Unknown => None, Known { value } => Some(value) } } @@ -338,7 +316,7 @@ impl<'tcx> TypeVariableTable<'tcx> { // 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!(), + Unknown => bug!(), Known { value } => value, }; escaping_types.push(escaping_type); @@ -369,12 +347,10 @@ impl<'tcx> TypeVariableTable<'tcx> { impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; - type Undo = Instantiate<'tcx>; + type Undo = Instantiate; - fn reverse(values: &mut Vec>, action: Instantiate<'tcx>) { - let Instantiate { vid, default } = action; - values[vid.index as usize].value = Bounded { - default, - }; + fn reverse(values: &mut Vec>, action: Instantiate) { + let Instantiate { vid } = action; + values[vid.index as usize].value = Unknown; } } 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/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 3a1ad8db9c20a..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}; @@ -548,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 { @@ -586,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) }) } } @@ -1199,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() @@ -1252,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)), } @@ -1273,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 | From c7953bb6d67dead45033434161be2ed8cdd6cd31 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 16 Jul 2017 07:07:51 -0400 Subject: [PATCH 08/22] obtain `UnificationTable` and `snapshot_vec` from `ena` instead The ena version has an improved interface. I suspect `librustc_data_structures` should start migrating out to crates.io in general. --- src/librustc/infer/combine.rs | 8 +-- src/librustc/infer/freshen.rs | 4 +- src/librustc/infer/mod.rs | 65 +++++++++++++------------ src/librustc/infer/type_variable.rs | 15 ++++-- src/librustc/infer/unify_key.rs | 44 ++++++++--------- src/librustc/ty/mod.rs | 5 +- src/librustc/util/ppaux.rs | 6 +++ src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/lib.rs | 5 +- 9 files changed, 88 insertions(+), 65 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index bd175c510fba3..8997e7d99dac1 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -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)) } @@ -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..25300eed548ba 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -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/mod.rs b/src/librustc/infer/mod.rs index 4292845792560..72a4dfbb7e0ec 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -29,7 +29,7 @@ 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(), @@ -476,8 +476,8 @@ impl<'tcx, T> InferOk<'tcx, T> { pub struct CombinedSnapshot<'a, 'tcx:'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, type_snapshot: type_variable::Snapshot, - int_snapshot: unify::Snapshot, - float_snapshot: unify::Snapshot, + 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 @@ -698,27 +698,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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; } @@ -1262,7 +1267,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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) } @@ -1270,7 +1275,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) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index e07cc92ec2158..423b18823b148 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -26,7 +26,7 @@ pub struct TypeVariableTable<'tcx> { /// Two variables are unified in `eq_relations` when we have a /// constraint `?X == ?Y`. - eq_relations: ut::UnificationTable, + 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 @@ -45,7 +45,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 @@ -86,8 +86,8 @@ enum TypeVariableValue<'tcx> { pub struct Snapshot { snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot, - sub_snapshot: ut::Snapshot, + eq_snapshot: ut::Snapshot>, + sub_snapshot: ut::Snapshot>, } struct Instantiate { @@ -354,3 +354,10 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { values[vid.index as usize].value = Unknown; } } + +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/ty/mod.rs b/src/librustc/ty/mod.rs index 856c53d19c98c..4315d1f2c8ca3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 37d1c568515b5..d390d1c15e2aa 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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..40d557ee5e04a 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.8.0" 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; From 57a593fcbb6af3db567c27b70b3a03c5a244705f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 16 Jul 2017 08:32:21 -0400 Subject: [PATCH 09/22] store type values in the unification table directly --- src/librustc/infer/combine.rs | 4 +- src/librustc/infer/higher_ranked/mod.rs | 17 +- src/librustc/infer/mod.rs | 14 +- src/librustc/infer/type_variable.rs | 223 ++++++++++++++++-------- src/librustc/traits/select.rs | 16 +- 5 files changed, 176 insertions(+), 98 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 8997e7d99dac1..959fefbe6b6e4 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -402,7 +402,7 @@ 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) { + match variables.probe(vid) { Some(u) => { drop(variables); self.relate(&u, &u) @@ -423,7 +423,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' ty::Covariant | ty::Contravariant => (), } - let origin = variables.origin(vid); + let origin = *variables.var_origin(vid); let new_var_id = variables.new_var(false, origin); let u = self.tcx().mk_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", 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/mod.rs b/src/librustc/infer/mod.rs index 72a4dfbb7e0ec..fa224b575a312 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -475,7 +475,7 @@ 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, + type_snapshot: type_variable::Snapshot<'tcx>, int_snapshot: ut::Snapshot>, float_snapshot: ut::Snapshot>, region_constraints_snapshot: RegionSnapshot, @@ -765,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(); @@ -787,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, @@ -819,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, @@ -861,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(); @@ -876,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(); @@ -887,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(); diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 423b18823b148..261cd396fced7 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -8,25 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::TypeVariableValue::*; use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; use std::cmp::min; 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>, + values: sv::SnapshotVec, /// 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 @@ -71,22 +70,20 @@ pub enum TypeVariableOrigin { pub type TypeVariableMap = FxHashMap; -struct TypeVariableData<'tcx> { - value: TypeVariableValue<'tcx>, +struct TypeVariableData { origin: TypeVariableOrigin, diverging: bool } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum TypeVariableValue<'tcx> { - Known { - value: Ty<'tcx> - }, + Known { value: Ty<'tcx> }, Unknown, } -pub struct Snapshot { +pub struct Snapshot<'tcx> { snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot>, + eq_snapshot: ut::Snapshot>>, sub_snapshot: ut::Snapshot>, } @@ -94,7 +91,7 @@ struct Instantiate { vid: ty::TyVid, } -struct Delegate<'tcx>(PhantomData<&'tcx ()>); +struct Delegate; impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { @@ -105,10 +102,18 @@ impl<'tcx> TypeVariableTable<'tcx> { } } + /// 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 } + /// 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 } @@ -137,41 +142,49 @@ 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 { value: ty }) - }; - - match old_value { - TypeVariableValue::Unknown => { - self.values.record(Instantiate { vid: vid }); - } - TypeVariableValue::Known { value: old_ty } => { - bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", - vid, ty, old_ty) - } - } + debug_assert!(self.probe(vid).is_none()); + debug_assert!(self.eq_relations.probe_value(vid) == TypeVariableValue::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 }); + + // Hack: we only need this so that `types_escaping_snapshot` + // can see what has been unified; see the Delegate impl for + // more details. + self.values.record(Instantiate { vid: vid }); } + /// 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, diverging: bool, origin: TypeVariableOrigin) -> ty::TyVid { - debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); - self.eq_relations.new_key(()); - self.sub_relations.new_key(()); + let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown); + + let sub_key = self.sub_relations.new_key(()); + assert_eq!(eq_key.vid, sub_key); + let index = self.values.push(TypeVariableData { - value: Unknown, origin, diverging, }); - let v = ty::TyVid { index: index as u32 }; - debug!("new_var: diverging={:?} index={:?}", diverging, v); - v + assert_eq!(eq_key.vid.index, index as u32); + + 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() } @@ -182,7 +195,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` @@ -202,24 +215,19 @@ impl<'tcx> TypeVariableTable<'tcx> { self.sub_root_var(a) == self.sub_root_var(b) } + /// Retrieves the type to which `vid` has been instantiated, if + /// any. 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 { - Unknown => None, - Known { value } => Some(value) + match self.eq_relations.probe_value(vid) { + TypeVariableValue::Unknown => None, + TypeVariableValue::Known { value } => Some(value) } } + /// 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)) => { @@ -232,7 +240,11 @@ impl<'tcx> TypeVariableTable<'tcx> { } } - 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(), eq_snapshot: self.eq_relations.snapshot(), @@ -240,7 +252,10 @@ impl<'tcx> TypeVariableTable<'tcx> { } } - pub fn rollback_to(&mut self, s: 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>) { debug!("rollback_to{:?}", { for action in self.values.actions_since_snapshot(&s.snapshot) { match *action { @@ -258,7 +273,11 @@ impl<'tcx> TypeVariableTable<'tcx> { self.sub_relations.rollback_to(sub_snapshot); } - pub fn commit(&mut self, s: 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 { snapshot, eq_snapshot, sub_snapshot } = s; self.values.commit(snapshot); self.eq_relations.commit(eq_snapshot); @@ -269,7 +288,7 @@ 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 { + pub fn types_created_since_snapshot(&mut self, s: &Snapshot<'tcx>) -> TypeVariableMap { let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); actions_since_snapshot @@ -285,16 +304,13 @@ impl<'tcx> TypeVariableTable<'tcx> { .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}`. - */ - + /// 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, s: &Snapshot<'tcx>) -> Vec> { let mut new_elem_threshold = u32::MAX; let mut escaping_types = Vec::new(); let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); @@ -315,9 +331,9 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 { - Unknown => bug!(), - Known { value } => value, + let escaping_type = match self.eq_relations.probe_value(vid) { + TypeVariableValue::Unknown => bug!(), + TypeVariableValue::Known { value } => value, }; escaping_types.push(escaping_type); } @@ -331,6 +347,8 @@ impl<'tcx> TypeVariableTable<'tcx> { escaping_types } + /// Returns indices of all variables that are not yet + /// instantiated. pub fn unsolved_variables(&mut self) -> Vec { (0..self.values.len()) .filter_map(|i| { @@ -345,19 +363,80 @@ impl<'tcx> TypeVariableTable<'tcx> { } } -impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { - type Value = TypeVariableData<'tcx>; +impl sv::SnapshotVecDelegate for Delegate { + type Value = TypeVariableData; type Undo = Instantiate; - fn reverse(values: &mut Vec>, action: Instantiate) { - let Instantiate { vid } = action; - values[vid.index as usize].value = Unknown; + fn reverse(_values: &mut Vec, _action: Instantiate) { + // We don't actually have to *do* anything to reverse an + // instanation; the value for a variable is stored in the + // `eq_relations` and hence its rollback code will handle + // it. In fact, we could *almost* just remove the + // `SnapshotVec` entirely, except that we would have to + // reproduce *some* of its logic, since we want to know which + // type variables have been instantiated since the snapshot + // was started, so we can implement `types_escaping_snapshot`. + // + // (If we extended the `UnificationTable` to let us see which + // values have been unified and so forth, that might also + // suffice.) + } +} + +/////////////////////////////////////////////////////////////////////////// + +/// 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, + + // 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*, it hardly matters, does it? + (&TypeVariableValue::Unknown, &TypeVariableValue::Unknown) => Ok(*value1), + } } } +/// 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/traits/select.rs b/src/librustc/traits/select.rs index f21ec295c5f7b..e5f05f30fd8a8 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>), ()> { @@ -3288,7 +3288,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); From ccd92c2a4e5ed634bbbd6d3a5bd491c47b80f642 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 16 Jul 2017 08:49:21 -0400 Subject: [PATCH 10/22] correct subtle bug in the type variable code --- src/librustc/infer/type_variable.rs | 171 ++++++++++------------------ 1 file changed, 63 insertions(+), 108 deletions(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 261cd396fced7..9e98c16c819b9 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -12,15 +12,18 @@ use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; -use std::cmp::min; use std::marker::PhantomData; 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`. This table also stores, for each key, @@ -82,21 +85,20 @@ enum TypeVariableValue<'tcx> { } pub struct Snapshot<'tcx> { - snapshot: sv::Snapshot, + /// number of variables at the time of the snapshot + num_vars: usize, + + /// snapshot from the `eq_relations` table eq_snapshot: ut::Snapshot>>, - sub_snapshot: ut::Snapshot>, -} -struct Instantiate { - vid: ty::TyVid, + /// snapshot from the `sub_relations` table + sub_snapshot: ut::Snapshot>, } -struct Delegate; - 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(), } @@ -107,7 +109,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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. @@ -115,7 +117,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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`. @@ -147,11 +149,6 @@ impl<'tcx> TypeVariableTable<'tcx> { "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 }); - - // Hack: we only need this so that `types_escaping_snapshot` - // can see what has been unified; see the Delegate impl for - // more details. - self.values.record(Instantiate { vid: vid }); } /// Creates a new type variable. @@ -173,11 +170,8 @@ impl<'tcx> TypeVariableTable<'tcx> { let sub_key = self.sub_relations.new_key(()); assert_eq!(eq_key.vid, sub_key); - let index = self.values.push(TypeVariableData { - origin, - diverging, - }); - assert_eq!(eq_key.vid.index, index as u32); + 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); @@ -186,7 +180,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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` @@ -246,7 +240,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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(), } @@ -256,21 +250,12 @@ impl<'tcx> TypeVariableTable<'tcx> { /// snapshots created since that point must already have been /// committed or rolled back. pub fn rollback_to(&mut self, s: Snapshot<'tcx>) { - 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); + 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); } /// Commits all changes since the snapshot was created, making @@ -278,8 +263,8 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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 { snapshot, eq_snapshot, sub_snapshot } = s; - self.values.commit(snapshot); + 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); } @@ -288,19 +273,12 @@ 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<'tcx>) -> 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() } @@ -310,47 +288,45 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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, s: &Snapshot<'tcx>) -> Vec> { - 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.eq_relations.probe_value(vid) { - TypeVariableValue::Unknown => bug!(), - TypeVariableValue::Known { value } => value, - }; - escaping_types.push(escaping_type); - } - debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold); - } - - _ => { } - } - } - + 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... + .map(|i| ty::TyVid { index: i as u32 }) + .filter_map(|vid| match self.eq_relations.probe_value(vid) { + TypeVariableValue::Unknown => None, + TypeVariableValue::Known { value } => Some(value), + })); // ...collect what types they've been 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() { @@ -362,27 +338,6 @@ impl<'tcx> TypeVariableTable<'tcx> { .collect() } } - -impl sv::SnapshotVecDelegate for Delegate { - type Value = TypeVariableData; - type Undo = Instantiate; - - fn reverse(_values: &mut Vec, _action: Instantiate) { - // We don't actually have to *do* anything to reverse an - // instanation; the value for a variable is stored in the - // `eq_relations` and hence its rollback code will handle - // it. In fact, we could *almost* just remove the - // `SnapshotVec` entirely, except that we would have to - // reproduce *some* of its logic, since we want to know which - // type variables have been instantiated since the snapshot - // was started, so we can implement `types_escaping_snapshot`. - // - // (If we extended the `UnificationTable` to let us see which - // values have been unified and so forth, that might also - // suffice.) - } -} - /////////////////////////////////////////////////////////////////////////// /// These structs (a newtyped TyVid) are used as the unification key From 69fe43c97e46ed920ead85a2c9c44630bf20570f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 16 Jul 2017 10:18:55 -0400 Subject: [PATCH 11/22] have `probe()` return `TypeVariableValue` --- src/librustc/infer/combine.rs | 10 ++--- src/librustc/infer/freshen.rs | 2 +- src/librustc/infer/fudge.rs | 4 +- src/librustc/infer/mod.rs | 7 ++-- src/librustc/infer/type_variable.rs | 58 ++++++++++++++++------------- 5 files changed, 46 insertions(+), 35 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 959fefbe6b6e4..44a848d3cc6e3 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}; @@ -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); @@ -403,11 +403,11 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' return Err(TypeError::CyclicTy(self.root_ty)); } else { match variables.probe(vid) { - Some(u) => { + TypeVariableValue::Known { value: u } => { drop(variables); self.relate(&u, &u) } - None => { + TypeVariableValue::Unknown { .. } => { match self.ambient_variance { // Invariant: no need to make a fresh type variable. ty::Invariant => return Ok(t), diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 25300eed548ba..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), diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 756a6947ee3f8..961dd70a46852 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 } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fa224b575a312..9b856f94c5615 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1259,9 +1259,10 @@ 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)) => { diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 9e98c16c819b9..9b9e9fa0015fa 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -78,12 +78,28 @@ struct TypeVariableData { diverging: bool } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum TypeVariableValue<'tcx> { +#[derive(Copy, Clone, Debug)] +pub enum TypeVariableValue<'tcx> { Known { value: Ty<'tcx> }, Unknown, } +impl<'tcx> TypeVariableValue<'tcx> { + pub fn known(&self) -> Option> { + match *self { + TypeVariableValue::Unknown { .. } => None, + TypeVariableValue::Known { value } => Some(value), + } + } + + pub fn is_unknown(&self) -> bool { + match *self { + TypeVariableValue::Unknown { .. } => true, + TypeVariableValue::Known { .. } => false, + } + } +} + pub struct Snapshot<'tcx> { /// number of variables at the time of the snapshot num_vars: usize, @@ -124,8 +140,8 @@ impl<'tcx> TypeVariableTable<'tcx> { /// /// 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); } @@ -134,8 +150,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); } @@ -144,8 +160,8 @@ 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(vid).is_none()); - debug_assert!(self.eq_relations.probe_value(vid) == TypeVariableValue::Unknown, + 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 }); @@ -211,12 +227,8 @@ impl<'tcx> TypeVariableTable<'tcx> { /// Retrieves the type to which `vid` has been instantiated, if /// any. - pub fn probe(&mut self, vid: ty::TyVid) -> Option> { - let vid = self.root_var(vid); - match self.eq_relations.probe_value(vid) { - TypeVariableValue::Unknown => None, - TypeVariableValue::Known { value } => Some(value) - } + 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 @@ -226,8 +238,8 @@ impl<'tcx> TypeVariableTable<'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, @@ -313,12 +325,9 @@ impl<'tcx> TypeVariableTable<'tcx> { // 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... + (0..snapshot.num_vars) // for all variables that pre-exist the snapshot, collect.. .map(|i| ty::TyVid { index: i as u32 }) - .filter_map(|vid| match self.eq_relations.probe_value(vid) { - TypeVariableValue::Unknown => None, - TypeVariableValue::Known { value } => Some(value), - })); // ...collect what types they've been instantiated with. + .filter_map(|vid| self.probe(vid).known())); // ..types they are instantiated with. debug!("types_escaping_snapshot = {:?}", escaping_types); escaping_types } @@ -329,10 +338,9 @@ impl<'tcx> TypeVariableTable<'tcx> { (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() From 44d992984acd4f736743b103467e19e907d8d4c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 16 Jul 2017 13:32:34 -0400 Subject: [PATCH 12/22] remove unnecessary clause propagating divergence This should not be needed: the new variable will be related to the old ones, so if they are constrained, so is the new variable; if they are not, and hence default to diverging, so will the new variable. --- src/librustc/infer/lattice.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index d5c1163cfc1b1..28aba51ab3724 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 From 13efaf0481275dba18f1d18f4b59b664b2d2031a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 17 Jul 2017 16:16:14 -0400 Subject: [PATCH 13/22] add universes to type inference variables --- src/librustc/infer/anon_types/mod.rs | 3 +- src/librustc/infer/combine.rs | 4 +-- src/librustc/infer/fudge.rs | 6 +++- src/librustc/infer/lattice.rs | 12 ++++--- src/librustc/infer/mod.rs | 23 ++++++++----- src/librustc/infer/type_variable.rs | 30 ++++++++++++++--- src/librustc/traits/coherence.rs | 4 ++- src/librustc/traits/error_reporting.rs | 17 +++++++--- src/librustc/traits/project.rs | 2 ++ src/librustc/traits/select.rs | 3 +- src/librustc/traits/specialize/mod.rs | 2 +- src/librustc_typeck/check/_match.rs | 11 ++++-- src/librustc_typeck/check/closure.rs | 3 +- src/librustc_typeck/check/coercion.rs | 3 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 4 +-- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 7 ++-- src/librustc_typeck/check/method/suggest.rs | 3 +- src/librustc_typeck/check/mod.rs | 37 +++++++++++++-------- src/librustc_typeck/check/op.rs | 9 +++-- 21 files changed, 132 insertions(+), 55 deletions(-) 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 44a848d3cc6e3..469cb4591124e 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -407,7 +407,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' drop(variables); self.relate(&u, &u) } - TypeVariableValue::Unknown { .. } => { + TypeVariableValue::Unknown { universe } => { match self.ambient_variance { // Invariant: no need to make a fresh type variable. ty::Invariant => return Ok(t), @@ -424,7 +424,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' } let origin = *variables.var_origin(vid); - let new_var_id = variables.new_var(false, origin); + 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); diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 961dd70a46852..48eb253415cdf 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -141,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/lattice.rs b/src/librustc/infer/lattice.rs index 28aba51ab3724..c4722f9a7f96c 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -88,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 9b856f94c5615..58026007320d0 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1015,18 +1015,22 @@ 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) + .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 { @@ -1081,12 +1085,14 @@ 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) -> Ty<'tcx> { let ty_var_id = self.type_variables .borrow_mut() - .new_var(false, + .new_var(universe, + false, TypeVariableOrigin::TypeParameterDefinition(span, def.name)); self.tcx.mk_var(ty_var_id) @@ -1095,13 +1101,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, _| { - self.type_var_for_def(span, def) + self.type_var_for_def(universe, span, def) }) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 9b9e9fa0015fa..5daac988f80b7 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -12,6 +12,7 @@ use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; +use std::cmp; use std::marker::PhantomData; use std::u32; use rustc_data_structures::fx::FxHashMap; @@ -81,10 +82,18 @@ struct TypeVariableData { #[derive(Copy, Clone, Debug)] pub enum TypeVariableValue<'tcx> { Known { value: Ty<'tcx> }, - Unknown, + Unknown { universe: ty::UniverseIndex }, +} + +#[derive(Copy, Clone, Debug)] +pub enum ProbeTyValue<'tcx> { + Ty(Ty<'tcx>), + Vid(ty::TyVid), } impl<'tcx> TypeVariableValue<'tcx> { + /// If this value is known, returns the type it is known to be. + /// Otherwise, `None`. pub fn known(&self) -> Option> { match *self { TypeVariableValue::Unknown { .. } => None, @@ -92,6 +101,14 @@ impl<'tcx> TypeVariableValue<'tcx> { } } + /// 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, @@ -178,10 +195,11 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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) -> ty::TyVid { - let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown); + 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); @@ -388,8 +406,12 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => Ok(*value1), (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => Ok(*value2), - // If both sides are *unknown*, it hardly matters, does it? - (&TypeVariableValue::Unknown, &TypeVariableValue::Unknown) => Ok(*value1), + // 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 }) + } } } } 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/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 e5f05f30fd8a8..9e24a4e6afacf 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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(), 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_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/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 a3233c8d86599..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) => { @@ -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) + 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 4a122fbc4c195..af86570309dfd 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -255,7 +255,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } 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) + 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 0a20af23e2e9d..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); @@ -1309,7 +1311,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { if i < substs.len() { substs.type_at(i) } else { - self.type_var_for_def(self.span, def) + 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 4fa48d96d36c4..a7001acc495a3 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(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,13 +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, span: Span) -> Ty<'tcx> { - self.type_var_for_def(span, ty_param_def) + self.type_var_for_def(ty::UniverseIndex::ROOT, span, ty_param_def) } fn projected_ty_from_poly_trait_ref(&self, @@ -2315,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); @@ -2754,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, @@ -2831,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 } @@ -3971,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 { @@ -3981,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) } @@ -4011,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) } @@ -4792,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) + self.type_var_for_def(ty::UniverseIndex::ROOT, span, def) }); } i -= has_self as usize; @@ -4825,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) + 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)); From 35e78b5cddc04c6bd13da2a1290d27cfb8ae8db8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 31 Jul 2017 07:40:24 +0300 Subject: [PATCH 14/22] change skolemizations to use universe index --- src/librustc/ty/mod.rs | 18 +++++++++++++++--- src/librustc/ty/sty.rs | 7 +------ src/librustc/util/ppaux.rs | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4315d1f2c8ca3..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::*; @@ -1345,7 +1345,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { /// 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)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct UniverseIndex(u32); impl UniverseIndex { @@ -1365,7 +1365,19 @@ impl UniverseIndex { /// 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 + 1) + 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 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/util/ppaux.rs b/src/librustc/util/ppaux.rs index d390d1c15e2aa..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"), From a985634fc08893d9e1255e287ad4bacc2cefa2ce Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 31 Oct 2017 11:40:24 -0400 Subject: [PATCH 15/22] fix tidy error --- src/librustc/infer/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 58026007320d0..402cb6a8fef43 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1029,7 +1029,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_var(self.next_ty_var_id(universe, false, origin)) } - pub fn next_diverging_ty_var(&self, universe: ty::UniverseIndex, origin: TypeVariableOrigin) -> Ty<'tcx> { + 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)) } From 17df455c2eda9717e2d7ff2f43809b553852d7e6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 31 Oct 2017 15:24:55 -0400 Subject: [PATCH 16/22] fix tests in `librustc_driver` --- src/librustc_driver/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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)); From 755bdaa19084c3ae116ad8320b99a6932fa7f0b1 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 29 Jan 2018 13:45:12 -0700 Subject: [PATCH 17/22] change skolemizations to use universe index These changes were meant to be in 2b18d8fe9dc05415a8e6b7cadf879c7f7ebe020a (rebased from 12a230562ece9b0d29018a436676141054dc53b7), but I messed up the rebase a bit as the file had been moved. --- src/Cargo.lock | 10 ++++ src/librustc/infer/region_constraints/mod.rs | 48 ++++++++++---------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 53744dca0a012..d70631fa519d8 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.8.0" +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.8.0 (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.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb80e4764284ff0ec7054cb05c557f5ba01ccf65ff0c265e981c0b303d0ffc" "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/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 ) From c30183873e2be5a23021adce01bacc901ccfff63 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 29 Jan 2018 13:46:52 -0700 Subject: [PATCH 18/22] Remove dead code These modules were replaced with re-exports from ena --- src/librustc_data_structures/snapshot_vec.rs | 230 ------------ src/librustc_data_structures/unify/mod.rs | 363 ------------------- src/librustc_data_structures/unify/tests.rs | 205 ----------- 3 files changed, 798 deletions(-) delete mode 100644 src/librustc_data_structures/snapshot_vec.rs delete mode 100644 src/librustc_data_structures/unify/mod.rs delete mode 100644 src/librustc_data_structures/unify/tests.rs 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)); -} From 4fb201dee5d5c920950859fe81152fff401de230 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 29 Jan 2018 14:06:28 -0700 Subject: [PATCH 19/22] Re-add some removed uses of `Kind` Additional uses of this item were added to these files in #45701 and #46479 --- src/librustc_typeck/check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a7001acc495a3..97fa508759546 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -93,7 +93,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::anon_types::AnonTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; From e9eb1a6adc1193a623ad7495f01a4c4125e49ce6 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 26 Feb 2018 15:14:24 -0700 Subject: [PATCH 20/22] Fix bad rebase --- src/librustc_typeck/check/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 97fa508759546..df3d081f898a7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1027,8 +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(fcx.next_ty_var(ty::UniverseIndex::ROOT, - 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); } From a6d85332f4f16167725c12d48700fd96e7acaa2a Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Tue, 27 Feb 2018 12:09:40 -0700 Subject: [PATCH 21/22] Fix breakage in rustdoc --- src/librustdoc/clean/auto_trait.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 '{:?}' \ From fec4d3b71161aa7b2861861cbf9b708c8c393b30 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Wed, 28 Feb 2018 10:27:18 -0700 Subject: [PATCH 22/22] Bump ena --- src/Cargo.lock | 6 +++--- src/librustc_data_structures/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index d70631fa519d8..2cc647c49c627 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -600,7 +600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ena" -version = "0.8.0" +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)", @@ -1874,7 +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.8.0 (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)", @@ -2870,7 +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.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb80e4764284ff0ec7054cb05c557f5ba01ccf65ff0c265e981c0b303d0ffc" +"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_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 40d557ee5e04a..e1f0a74fc683d 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -ena = "0.8.0" +ena = "0.9.1" log = "0.4" serialize = { path = "../libserialize" } cfg-if = "0.1.2"