From f1c83de1ddcd64fe05085e5d03f4745bf9a55401 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:12:51 +0000 Subject: [PATCH 01/47] Add `consts` to `TypeRelation` Co-Authored-By: Gabriel Smith --- src/librustc/ty/relate.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2638a1c7c8808..03ca414cd5462 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -76,11 +76,19 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { // additional hooks for other types in the future if needed // without making older code, which called `relate`, obsolete. - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>>; - - fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) - -> RelateResult<'tcx, ty::Region<'tcx>>; + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>; + + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx> + ) -> RelateResult<'tcx, ty::Region<'tcx>>; + + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx> + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>>; fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> From cafa10d96eae5f0cd20d835f100c1c10d256abe1 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:13:08 +0000 Subject: [PATCH 02/47] Define `super_relate_consts` Co-Authored-By: Gabriel Smith --- src/librustc/ty/relate.rs | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 03ca414cd5462..2034795a0b582 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -583,6 +583,70 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, } } +/// The main "const relation" routine. Note that this does not handle +/// inference artifacts, so you should filter those out before calling +/// it. +pub fn super_relate_consts<'a, 'gcx, 'tcx, R>( + relation: &mut R, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx> +) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> +where + R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a +{ + let tcx = relation.tcx(); + + match (a, b) { + (ty::LazyConst::Evaluated(a_eval), ty::LazyConst::Evaluated(b_eval)) => { + // Only consts whose types are equal should be compared. + assert_eq!(a_eval.ty, b_eval.ty); + + // Currently, the values that can be unified are those that + // implement both `PartialEq` and `Eq`, corresponding to + // `structural_match` types. + // FIXME(const_generics): check for `structural_match` synthetic attribute. + match (a_eval.val, b_eval.val) { + (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { + // The caller should handle these cases! + bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) + } + (ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => { + Ok(a) + } + (ConstValue::Scalar(Scalar::Bits { .. }), _) if a == b => { + Ok(a) + } + (ConstValue::ByRef(..), _) => { + bug!( + "non-Scalar ConstValue encountered in super_relate_consts {:?} {:?}", + a, + b, + ); + } + _ => { + Err(TypeError::ConstError( + ConstError::Mismatch(expected_found(relation, &a, &b)) + )) + } + } + } + // FIXME(const_generics): this is probably wrong (regarding TyProjection) + ( + ty::LazyConst::Unevaluated(a_def_id, a_substs), + ty::LazyConst::Unevaluated(b_def_id, b_substs), + ) if a_def_id == b_def_id => { + let substs = + relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?; + Ok(tcx.mk_lazy_const(ty::LazyConst::Unevaluated(*a_def_id, substs))) + } + _ => { + Err(TypeError::ConstError( + ConstError::Mismatch(expected_found(relation, &a, &b)) + )) + } + } +} + impl<'tcx> Relate<'tcx> for &'tcx ty::List> { fn relate<'a, 'gcx, R>(relation: &mut R, a: &Self, From 225472748094e4cb8b1628579d3e1f0c77f209ff Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:13:38 +0000 Subject: [PATCH 03/47] Add `ConstError` Co-Authored-By: Gabriel Smith --- src/librustc/ty/error.rs | 23 +++++++++++++++++++++++ src/librustc/ty/structural_impls.rs | 21 ++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 74d0a29bcff00..5e3718b73bfd8 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -44,6 +44,14 @@ pub enum TypeError<'tcx> { ProjectionMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), + + ConstError(ConstError<'tcx>), +} + +// Data structure used in const unification +#[derive(Clone, Debug)] +pub enum ConstError<'tcx> { + Mismatch(ExpectedFound<&'tcx ty::LazyConst<'tcx>>), } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -163,6 +171,21 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { report_maybe_different(f, &format!("trait `{}`", values.expected), &format!("trait `{}`", values.found)) } + ConstError(ref err) => { + write!(f, "{}", err) + } + } + } +} + +impl<'tcx> fmt::Display for ConstError<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::ConstError::*; + + match *self { + Mismatch(ref values) => { + write!(f, "expected `{:?}`, found `{:?}`", values.expected, values.found) + } } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9aaff33e93339..548339ee68763 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -737,11 +737,23 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { ProjectionMismatched(x) => ProjectionMismatched(x), ProjectionBoundsLength(x) => ProjectionBoundsLength(x), Sorts(ref x) => return tcx.lift(x).map(Sorts), - ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch) + ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), + ConstError(ref x) => return tcx.lift(x).map(ConstError), }) } } +impl<'a, 'tcx> Lift<'tcx> for ty::error::ConstError<'a> { + type Lifted = ty::error::ConstError<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + use ty::error::ConstError::*; + + match *self { + Mismatch(ref x) => return tcx.lift(x).map(Mismatch), + } + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { type Lifted = ty::InstanceDef<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -1320,6 +1332,13 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::ProjectionBoundsLength)(x), (ty::error::TypeError::Sorts)(x), (ty::error::TypeError::ExistentialMismatch)(x), + (ty::error::TypeError::ConstError)(x), + } +} + +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ty::error::ConstError<'tcx> { + (ty::error::ConstError::Mismatch)(x), } } From 77447deb2184d618abb26a16fde43d153f85c3b8 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:14:01 +0000 Subject: [PATCH 04/47] Add const_variable.rs Co-Authored-By: Gabriel Smith --- src/librustc/infer/const_variable.rs | 242 +++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 src/librustc/infer/const_variable.rs diff --git a/src/librustc/infer/const_variable.rs b/src/librustc/infer/const_variable.rs new file mode 100644 index 0000000000000..5691bf08eae1c --- /dev/null +++ b/src/librustc/infer/const_variable.rs @@ -0,0 +1,242 @@ +use crate::mir::interpret::ConstValue; +use syntax::symbol::InternedString; +use syntax_pos::Span; +use crate::ty::{self, InferConst}; + +use std::cmp; +use std::marker::PhantomData; +use rustc_data_structures::snapshot_vec as sv; +use rustc_data_structures::unify as ut; + +pub struct ConstVariableTable<'tcx> { + values: sv::SnapshotVec>, + + relations: ut::UnificationTable>>, +} + +/// Reasons to create a const inference variable +#[derive(Copy, Clone, Debug)] +pub enum ConstVariableOrigin { + MiscVariable(Span), + ConstInference(Span), + ConstParameterDefinition(Span, InternedString), + SubstitutionPlaceholder(Span), +} + +struct ConstVariableData { + origin: ConstVariableOrigin, +} + +#[derive(Copy, Clone, Debug)] +pub enum ConstVariableValue<'tcx> { + Known { value: &'tcx ty::LazyConst<'tcx> }, + Unknown { universe: ty::UniverseIndex }, +} + +impl<'tcx> ConstVariableValue<'tcx> { + /// If this value is known, returns the const it is known to be. + /// Otherwise, `None`. + pub fn known(&self) -> Option<&'tcx ty::LazyConst<'tcx>> { + match *self { + ConstVariableValue::Unknown { .. } => None, + ConstVariableValue::Known { value } => Some(value), + } + } + + pub fn is_unknown(&self) -> bool { + match *self { + ConstVariableValue::Unknown { .. } => true, + ConstVariableValue::Known { .. } => false, + } + } +} + +pub struct Snapshot<'tcx> { + snapshot: sv::Snapshot, + relation_snapshot: ut::Snapshot>>, +} + +struct Instantiate<'tcx> { + _vid: ty::ConstVid<'tcx>, +} + +struct Delegate<'tcx> { + pub phantom: PhantomData<&'tcx ()>, +} + +impl<'tcx> ConstVariableTable<'tcx> { + pub fn new() -> ConstVariableTable<'tcx> { + ConstVariableTable { + values: sv::SnapshotVec::new(), + relations: ut::UnificationTable::new(), + } + } + + /// 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::ConstVid<'tcx>) -> &ConstVariableOrigin { + &self.values[vid.index as usize].origin + } + + pub fn unify_var_var( + &mut self, + a_id: ty::ConstVid<'tcx>, + b_id: ty::ConstVid<'tcx>, + ) -> Result<(), (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>)> { + self.relations.unify_var_var(a_id, b_id) + } + + pub fn unify_var_value( + &mut self, + a_id: ty::ConstVid<'tcx>, + b: ConstVariableValue<'tcx>, + ) -> Result<(), (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>)> { + self.relations.unify_var_value(a_id, b) + } + + /// Creates a new const variable. + /// + /// - `origin`: indicates *why* the const variable was created. + /// The code in this module doesn't care, but it can be useful + /// for improving error messages. + pub fn new_var( + &mut self, + universe: ty::UniverseIndex, + origin: ConstVariableOrigin, + ) -> ty::ConstVid<'tcx> { + let vid = self.relations.new_key(ConstVariableValue::Unknown{ universe }); + + let index = self.values.push(ConstVariableData { + origin, + }); + assert_eq!(vid.index, index as u32); + + debug!("new_var(index={:?}, origin={:?}", vid, origin); + + vid + } + + /// Retrieves the type to which `vid` has been instantiated, if + /// any. + pub fn probe( + &mut self, + vid: ty::ConstVid<'tcx> + ) -> ConstVariableValue<'tcx> { + self.relations.probe_value(vid) + } + + /// If `t` is a type-inference variable, and it has been + /// instantiated, then return the with which it was + /// instantiated. Otherwise, returns `t`. + pub fn replace_if_possible( + &mut self, + c: &'tcx ty::LazyConst<'tcx> + ) -> &'tcx ty::LazyConst<'tcx> { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Var(vid)), + .. + }) = c { + match self.probe(*vid).known() { + Some(c) => c, + None => c, + } + } else { + c + } + } + + /// 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(), + relation_snapshot: self.relations.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) { + if let sv::UndoLog::NewElem(index) = *action { + debug!("inference variable _#{}t popped", index) + } + } + }); + + let Snapshot { snapshot, relation_snapshot } = s; + self.values.rollback_to(snapshot); + self.relations.rollback_to(relation_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, relation_snapshot } = s; + self.values.commit(snapshot); + self.relations.commit(relation_snapshot); + } +} + +impl<'tcx> ut::UnifyKey for ty::ConstVid<'tcx> { + type Value = ConstVariableValue<'tcx>; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } } + fn tag() -> &'static str { "ConstVid" } +} + +impl<'tcx> ut::UnifyValue for ConstVariableValue<'tcx> { + type Error = (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>); + + fn unify_values(value1: &Self, value2: &Self) -> Result { + match (value1, value2) { + ( + &ConstVariableValue::Known { value: value1 }, + &ConstVariableValue::Known { value: value2 } + ) => { + match <&'tcx ty::LazyConst<'tcx>>::unify_values(&value1, &value2) { + Ok(value) => Ok(ConstVariableValue::Known { value }), + Err(err) => Err(err), + } + } + + // If one side is known, prefer that one. + (&ConstVariableValue::Known { .. }, &ConstVariableValue::Unknown { .. }) => Ok(*value1), + (&ConstVariableValue::Unknown { .. }, &ConstVariableValue::Known { .. }) => Ok(*value2), + + // If both sides are *unknown*, it hardly matters, does it? + (&ConstVariableValue::Unknown { universe: universe1 }, + &ConstVariableValue::Unknown { universe: universe2 }) => { + // If we unify two unbound variables, ?T and ?U, then whatever + // value they wind up taking (which must be the same value) must + // be nameable by both universes. Therefore, the resulting + // universe is the minimum of the two universes, because that is + // the one which contains the fewest names in scope. + let universe = cmp::min(universe1, universe2); + Ok(ConstVariableValue::Unknown { universe }) + } + } + } +} + +impl<'tcx> ut::EqUnifyValue for &'tcx ty::LazyConst<'tcx> {} + +impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { + type Value = ConstVariableData; + type Undo = Instantiate<'tcx>; + + fn reverse(_values: &mut Vec, _action: Instantiate<'tcx>) { + // We don't actually have to *do* anything to reverse an + // instantiation; the value for a variable is stored in the + // `relations` and hence its rollback code will handle + // it. + } +} From d7fdeffafce754e0abb2bdac23f01d44ec526eb8 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:15:23 +0000 Subject: [PATCH 05/47] Add generic consts to `BottomUpFolder` Co-Authored-By: Gabriel Smith --- src/librustc/infer/opaque_types/mod.rs | 5 +-- src/librustc/ty/fold.rs | 22 +++++++++----- src/librustc_typeck/check/wfcheck.rs | 5 +-- src/librustc_typeck/check/writeback.rs | 42 ++++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index b1d009146473f..6d8558211818b 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -676,8 +676,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { let tcx = self.infcx.tcx; value.fold_with(&mut BottomUpFolder { tcx, - reg_op: |reg| reg, - fldop: |ty| { + ty_op: |ty| { if let ty::Opaque(def_id, substs) = ty.sty { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose @@ -776,6 +775,8 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { ty }, + lt_op: |lt| lt, + ct_op: |ct| ct, }) } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 7f58a436fcf0d..afd94757b2329 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -193,29 +193,37 @@ pub trait TypeVisitor<'tcx> : Sized { /////////////////////////////////////////////////////////////////////////// // Some sample folders -pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G> +pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G, H> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, + H: FnMut(&'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx>, { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, - pub fldop: F, - pub reg_op: G, + pub ty_op: F, + pub lt_op: G, + pub ct_op: H, } -impl<'a, 'gcx, 'tcx, F, G> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G> +impl<'a, 'gcx, 'tcx, F, G, H> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G, H> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, + H: FnMut(&'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx>, { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let t1 = ty.super_fold_with(self); - (self.fldop)(t1) + let t = ty.super_fold_with(self); + (self.ty_op)(t) } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let r = r.super_fold_with(self); - (self.reg_op)(r) + (self.lt_op)(r) + } + + fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + let c = c.super_fold_with(self); + (self.ct_op)(c) } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 37be1c3b5b7fa..8ee30c0d2d31d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -616,7 +616,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( let mut substituted_predicates = Vec::new(); ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: fcx.tcx, - fldop: |ty| { + ty_op: |ty| { if let ty::Opaque(def_id, substs) = ty.sty { trace!("check_existential_types: opaque_ty, {:?}, {:?}", def_id, substs); let generics = tcx.generics_of(def_id); @@ -739,7 +739,8 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } // if let Opaque ty }, - reg_op: |reg| reg, + lt_op: |lt| lt, + ct_op: |ct| ct, }); substituted_predicates } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 80da3fd975124..d16d69e923326 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -11,7 +11,8 @@ use rustc::infer::InferCtxt; use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; use rustc::ty::subst::UnpackedKind; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, Const, LazyConst}; +use rustc::mir::interpret::ConstValue; use rustc::util::nodemap::DefIdSet; use rustc_data_structures::sync::Lrc; use std::mem; @@ -488,7 +489,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // figures out the concrete type with `U`, but the stored type is with `T` instantiated_ty.fold_with(&mut BottomUpFolder { tcx: self.tcx().global_tcx(), - fldop: |ty| { + ty_op: |ty| { trace!("checking type {:?}", ty); // find a type parameter if let ty::Param(..) = ty.sty { @@ -520,7 +521,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } ty }, - reg_op: |region| { + lt_op: |region| { match region { // ignore static regions ty::ReStatic => region, @@ -564,6 +565,41 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } }, + ct_op: |ct| { + trace!("checking const {:?}", ct); + // find a const parameter + if let LazyConst::Evaluated(Const { ty, val }) = ct { + if let ConstValue::Param(..) = val { + // look it up in the substitution list + assert_eq!(opaque_defn.substs.len(), generics.params.len()); + for (subst, param) in opaque_defn.substs.iter() + .zip(&generics.params) { + if let UnpackedKind::Const(subst) = subst.unpack() { + if subst == ct { + // found it in the substitution list, replace with the + // parameter from the existential type + return self.tcx() + .global_tcx() + .mk_const_param(param.index, param.name, ty); + } + } + } + self.tcx() + .sess + .struct_span_err( + span, + &format!( + "const parameter `{}` is part of concrete type but not \ + used in parameter list for existential type", + ct, + ), + ) + .emit(); + return self.tcx().types.ct_err; + } + } + ct + } }) }; From 0728b62aca9f8c141ac90184c24f404a05f5a520 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:15:37 +0000 Subject: [PATCH 06/47] Add `ct_err` Co-Authored-By: Gabriel Smith --- src/librustc/ty/context.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index b1500456991dd..eab98305ebffa 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -231,6 +231,8 @@ pub struct CommonLifetimes<'tcx> { pub re_empty: Region<'tcx>, pub re_static: Region<'tcx>, pub re_erased: Region<'tcx>, + + pub ct_err: &'tcx LazyConst<'tcx>, } pub struct LocalTableInContext<'a, V: 'a> { @@ -943,7 +945,7 @@ impl<'tcx> CommonTypes<'tcx> { bool: mk(Bool), char: mk(Char), never: mk(Never), - err: mk(Error), + err, isize: mk(Int(ast::IntTy::Isize)), i8: mk(Int(ast::IntTy::I8)), i16: mk(Int(ast::IntTy::I16)), From 14f906f24e616c749e9056511e81c464f3c6df25 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:16:18 +0000 Subject: [PATCH 07/47] Define `canonicalize_const_var` Co-Authored-By: Gabriel Smith --- src/librustc/infer/canonical/canonicalizer.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 7cd55951cdaf4..9bd7f4c02d7be 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -633,4 +633,34 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { self.tcx().mk_ty(ty::Bound(self.binder_index, var.into())) } } + + /// Given a type variable `const_var` of the given kind, first check + /// if `const_var` is bound to anything; if so, canonicalize + /// *that*. Otherwise, create a new canonical variable for + /// `const_var`. + fn canonicalize_const_var( + &mut self, + info: CanonicalVarInfo, + const_var: &'tcx ty::LazyConst<'tcx> + ) -> &'tcx ty::LazyConst<'tcx> { + let infcx = self.infcx.expect("encountered const-var without infcx"); + let bound_to = infcx.resolve_const_var(const_var); + if bound_to != const_var { + self.fold_const(bound_to) + } else { + let ty = match const_var { + ty::LazyConst::Unevaluated(def_id, _) => { + self.tcx.type_of(*def_id) + } + ty::LazyConst::Evaluated(ty::Const { ty, .. }) => ty, + }; + let var = self.canonical_var(info, const_var.into()); + self.tcx().mk_lazy_const( + ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(self.binder_index, var.into())), + ty, + }) + ) + } + } } From d4e0951fff2161827e7fb83e346af37718759a2b Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:16:54 +0000 Subject: [PATCH 08/47] Add `CanonicalVarKind::Const` Co-Authored-By: Gabriel Smith --- src/librustc/infer/canonical/mod.rs | 36 +++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index fe6b8ac1cdc7e..e8c881fcae7ef 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -21,7 +21,8 @@ //! //! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html -use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin}; +use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, ConstVariableOrigin}; +use crate::mir::interpret::ConstValue; use rustc_data_structures::indexed_vec::IndexVec; use rustc_macros::HashStable; use serialize::UseSpecializedDecodable; @@ -30,7 +31,7 @@ use std::ops::Index; use syntax::source_map::Span; use crate::ty::fold::TypeFoldable; use crate::ty::subst::Kind; -use crate::ty::{self, BoundVar, Lift, List, Region, TyCtxt}; +use crate::ty::{self, BoundVar, InferConst, Lift, List, Region, TyCtxt}; mod canonicalizer; @@ -115,6 +116,7 @@ impl CanonicalVarInfo { CanonicalVarKind::PlaceholderTy(_) => false, CanonicalVarKind::Region(_) => true, CanonicalVarKind::PlaceholderRegion(..) => false, + CanonicalVarKind::Const(_) => true, } } } @@ -137,6 +139,9 @@ pub enum CanonicalVarKind { /// are solving a goal like `for<'a> T: Foo<'a>` to represent the /// bound region `'a`. PlaceholderRegion(ty::PlaceholderRegion), + + /// Some kind of const inference variable. + Const(ty::UniverseIndex), } impl CanonicalVarKind { @@ -150,6 +155,7 @@ impl CanonicalVarKind { CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe, CanonicalVarKind::Region(ui) => ui, CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, + CanonicalVarKind::Const(ui) => ui, } } } @@ -388,6 +394,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { }; self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into() } + + CanonicalVarKind::Const(ui) => { + self.next_const_var_in_universe( + self.next_ty_var_in_universe( + TypeVariableOrigin::MiscVariable(span), + universe_map(ui), + ), + ConstVariableOrigin::MiscVariable(span), + universe_map(ui), + ).into() + } } } } @@ -443,8 +460,19 @@ impl<'tcx> CanonicalVarValues<'tcx> { UnpackedKind::Lifetime(..) => tcx.mk_region( ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i)) ).into(), - UnpackedKind::Const(..) => { - unimplemented!() // FIXME(const_generics) + UnpackedKind::Const(ct) => { + let ty = match ct { + ty::LazyConst::Unevaluated(def_id, _) => { + tcx.type_of(*def_id) + } + ty::LazyConst::Evaluated(ty::Const { ty, .. }) => ty, + }; + tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const { + ty: ty, + val: ConstValue::Infer( + InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from_u32(i)) + ), + })).into() } }) .collect() From 05ac3ac575c2b11fbf493ac929ab60448a20e07e Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:17:18 +0000 Subject: [PATCH 09/47] Define `super_combine_consts` Co-Authored-By: Gabriel Smith --- src/librustc/infer/combine.rs | 63 +++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 885b439ef1ca5..16b0595b23371 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -28,11 +28,13 @@ use super::{InferCtxt, MiscVariable, TypeTrace}; use super::lub::Lub; use super::sub::Sub; use super::type_variable::TypeVariableValue; +use super::const_variable::ConstVariableValue; use crate::hir::def_id::DefId; +use crate::mir::interpret::ConstValue; use crate::ty::{IntType, UintType}; -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::error::TypeError; +use crate::ty::{self, Ty, TyCtxt, InferConst, LazyConst}; +use crate::ty::error::{ConstError, TypeError}; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::ty::subst::SubstsRef; use crate::traits::{Obligation, PredicateObligations}; @@ -107,13 +109,68 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b))) } - _ => { ty::relate::super_relate_tys(relation, a, b) } } } + pub fn super_combine_consts( + &self, + relation: &mut R, + a: &'tcx LazyConst<'tcx>, + b: &'tcx LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx LazyConst<'tcx>> + where + R: TypeRelation<'infcx, 'gcx, 'tcx>, + { + let a_is_expected = relation.a_is_expected(); + + if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { + match (a_eval.val, b_eval.val) { + (ConstValue::Infer(InferConst::Var(a_vid)), + ConstValue::Infer(InferConst::Var(b_vid))) => { + self.const_unification_table + .borrow_mut() + .unify_var_var(a_vid, b_vid) + .map_err(|e| const_unification_error(a_is_expected, e))?; + return Ok(a); + } + + // All other cases of inference with other variables are errors. + (ConstValue::Infer(InferConst::Var(_)), ConstValue::Infer(_)) | + (ConstValue::Infer(_), ConstValue::Infer(InferConst::Var(_))) => { + bug!("tried to combine ConstValue::Infer/ConstValue::Infer(InferConst::Var)") + } + + (ConstValue::Infer(InferConst::Var(vid)), _) => { + return self.unify_const_variable(a_is_expected, vid, b); + } + + (_, ConstValue::Infer(InferConst::Var(vid))) => { + return self.unify_const_variable(!a_is_expected, vid, a); + } + + _ => {} + } + } + + ty::relate::super_relate_consts(relation, a, b) + } + + pub fn unify_const_variable( + &self, + vid_is_expected: bool, + vid: ty::ConstVid<'tcx>, + value: &'tcx LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx LazyConst<'tcx>> { + self.const_unification_table + .borrow_mut() + .unify_var_value(vid, ConstVariableValue::Known { value }) + .map_err(|e| const_unification_error(vid_is_expected, e))?; + Ok(value) + } + fn unify_integral_variable(&self, vid_is_expected: bool, vid: ty::IntVid, From b9b9994c7258c1411656d69462b582ea4be12227 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:17:28 +0000 Subject: [PATCH 10/47] Define `const_unification_error` Co-Authored-By: Gabriel Smith --- src/librustc/infer/combine.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 16b0595b23371..f212f6298be53 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -597,6 +597,15 @@ impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'t } } +pub fn const_unification_error<'tcx>( + a_is_expected: bool, + (a, b): (&'tcx LazyConst<'tcx>, &'tcx LazyConst<'tcx>), +) -> TypeError<'tcx> { + TypeError::ConstError( + ConstError::Mismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) + ) +} + fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue)) -> TypeError<'tcx> { From 7d71a1c8a4ac424a1d77fa94746ca3d7aa72335e Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:18:02 +0000 Subject: [PATCH 11/47] Add const generics to unification tables Co-Authored-By: Gabriel Smith --- src/librustc/infer/mod.rs | 170 ++++++++++++++++++++++++++++---------- 1 file changed, 128 insertions(+), 42 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e9b80c56e0c5c..12321f2e355c3 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -13,14 +13,15 @@ use crate::infer::canonical::{Canonical, CanonicalVarValues}; use crate::middle::free_region::RegionRelations; use crate::middle::lang_items; use crate::middle::region; +use crate::mir::interpret::ConstValue; use crate::session::config::BorrowckMode; use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use crate::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use crate::ty::fold::TypeFoldable; use crate::ty::relate::RelateResult; use crate::ty::subst::{Kind, InternalSubsts, SubstsRef}; -use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, CtxtInterners}; -use crate::ty::{FloatVid, IntVid, TyVid}; +use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, CtxtInterners, InferConst}; +use crate::ty::{FloatVid, IntVid, TyVid, ConstVid}; use crate::util::nodemap::FxHashMap; use arena::SyncDroplessArena; @@ -34,6 +35,7 @@ use syntax_pos::symbol::InternedString; use syntax_pos::Span; use self::combine::CombineFields; +use self::const_variable::ConstVariableOrigin; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; @@ -60,6 +62,7 @@ pub mod region_constraints; pub mod resolve; mod sub; pub mod type_variable; +pub mod const_variable; pub mod unify_key; #[must_use] @@ -72,7 +75,7 @@ pub type InferResult<'tcx, T> = Result, TypeError<'tcx>>; pub type Bound = Option; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" -pub type FixupResult = Result; // "fixup result" +pub type FixupResult<'tcx, T> = Result>; // "fixup result" /// A flag that is used to suppress region errors. This is normally /// false, but sometimes -- when we are doing region checks that the @@ -122,7 +125,10 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { /// order, represented by its upper and lower bounds. pub type_variables: RefCell>, - /// Map from integral variable to the kind of integer it represents + /// Map from const parameter variable to the kind of const it represents. + const_unification_table: RefCell>, + + /// Map from integral variable to the kind of integer it represents. int_unification_table: RefCell>>, /// Map from floating variable to the kind of float it represents @@ -422,10 +428,11 @@ impl NLLRegionVariableOrigin { } #[derive(Copy, Clone, Debug)] -pub enum FixupError { +pub enum FixupError<'tcx> { UnresolvedIntTy(IntVid), UnresolvedFloatTy(FloatVid), UnresolvedTy(TyVid), + UnresolvedConst(ConstVid<'tcx>), } /// See the `region_obligations` field for more information. @@ -436,7 +443,7 @@ pub struct RegionObligation<'tcx> { pub origin: SubregionOrigin<'tcx>, } -impl fmt::Display for FixupError { +impl<'tcx> fmt::Display for FixupError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::FixupError::*; @@ -452,6 +459,7 @@ impl fmt::Display for FixupError { add a suffix to specify the type explicitly" ), UnresolvedTy(_) => write!(f, "unconstrained type"), + UnresolvedConst(_) => write!(f, "unconstrained const value"), } } } @@ -524,6 +532,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { in_progress_tables, projection_cache: Default::default(), type_variables: RefCell::new(type_variable::TypeVariableTable::new()), + const_unification_table: RefCell::new(const_variable::ConstVariableTable::new()), int_unification_table: RefCell::new(ut::UnificationTable::new()), float_unification_table: RefCell::new(ut::UnificationTable::new()), region_constraints: RefCell::new(Some(RegionConstraintCollector::new())), @@ -589,6 +598,7 @@ impl<'tcx> InferOk<'tcx, ()> { pub struct CombinedSnapshot<'a, 'tcx: 'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, type_snapshot: type_variable::Snapshot<'tcx>, + const_snapshot: const_variable::Snapshot<'tcx>, int_snapshot: ut::Snapshot>, float_snapshot: ut::Snapshot>, region_constraints_snapshot: RegionSnapshot, @@ -652,6 +662,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut type_variables = self.type_variables.borrow_mut(); let mut int_unification_table = self.int_unification_table.borrow_mut(); let mut float_unification_table = self.float_unification_table.borrow_mut(); + // FIXME(const_generics): should there be an equivalent function for const variables? type_variables .unsolved_variables() @@ -722,6 +733,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { CombinedSnapshot { projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(), type_snapshot: self.type_variables.borrow_mut().snapshot(), + const_snapshot: self.const_unification_table.borrow_mut().snapshot(), int_snapshot: self.int_unification_table.borrow_mut().snapshot(), float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_constraints_snapshot: self.borrow_region_constraints().start_snapshot(), @@ -739,6 +751,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let CombinedSnapshot { projection_cache_snapshot, type_snapshot, + const_snapshot, int_snapshot, float_snapshot, region_constraints_snapshot, @@ -751,21 +764,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.in_snapshot.set(was_in_snapshot); self.universe.set(universe); - self.projection_cache - .borrow_mut() - .rollback_to(projection_cache_snapshot); + self.projection_cache.borrow_mut().rollback_to(projection_cache_snapshot); self.type_variables.borrow_mut().rollback_to(type_snapshot); - self.int_unification_table - .borrow_mut() - .rollback_to(int_snapshot); - self.float_unification_table - .borrow_mut() - .rollback_to(float_snapshot); - self.region_obligations - .borrow_mut() - .truncate(region_obligations_snapshot); - self.borrow_region_constraints() - .rollback_to(region_constraints_snapshot); + self.const_unification_table.borrow_mut().rollback_to(const_snapshot); + self.int_unification_table.borrow_mut().rollback_to(int_snapshot); + self.float_unification_table.borrow_mut().rollback_to(float_snapshot); + self.region_obligations.borrow_mut().truncate(region_obligations_snapshot); + self.borrow_region_constraints().rollback_to(region_constraints_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { @@ -773,6 +778,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let CombinedSnapshot { projection_cache_snapshot, type_snapshot, + const_snapshot, int_snapshot, float_snapshot, region_constraints_snapshot, @@ -784,16 +790,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.in_snapshot.set(was_in_snapshot); - self.projection_cache - .borrow_mut() - .commit(projection_cache_snapshot); + self.projection_cache.borrow_mut().commit(projection_cache_snapshot); self.type_variables.borrow_mut().commit(type_snapshot); + self.const_unification_table.borrow_mut().commit(const_snapshot); self.int_unification_table.borrow_mut().commit(int_snapshot); - self.float_unification_table - .borrow_mut() - .commit(float_snapshot); - self.borrow_region_constraints() - .commit(region_constraints_snapshot); + self.float_unification_table.borrow_mut().commit(float_snapshot); + self.borrow_region_constraints().commit(region_constraints_snapshot); } /// Executes `f` and commit the bindings. @@ -918,17 +920,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { predicate: &ty::PolySubtypePredicate<'tcx>, ) -> Option> { // Subtle: it's ok to skip the binder here and resolve because - // `shallow_resolve` just ignores anything that is not a type + // `shallow_resolve_type` just ignores anything that is not a type // variable, and because type variable's can't (at present, at // least) capture any of the things bound by this binder. // // Really, there is no *particular* reason to do this - // `shallow_resolve` here except as a + // `shallow_resolve_type` here except as a // micro-optimization. Naturally I could not // resist. -nmatsakis let two_unbound_type_vars = { - let a = self.shallow_resolve(predicate.skip_binder().a); - let b = self.shallow_resolve(predicate.skip_binder().b); + let a = self.shallow_resolve_type(predicate.skip_binder().a); + let b = self.shallow_resolve_type(predicate.skip_binder().b); a.is_ty_var() && b.is_ty_var() }; @@ -999,6 +1001,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_ty_var(self.next_ty_var_id(true, origin)) } + pub fn next_const_var( + &self, + ty: Ty<'tcx>, + origin: ConstVariableOrigin + ) -> &'tcx ty::LazyConst<'tcx> { + self.tcx.mk_const_var(self.next_const_var_id(origin), ty) + } + + pub fn next_const_var_in_universe( + &self, + ty: Ty<'tcx>, + origin: ConstVariableOrigin, + universe: ty::UniverseIndex, + ) -> &'tcx ty::LazyConst<'tcx> { + let vid = self.const_unification_table + .borrow_mut() + .new_var(universe, origin); + self.tcx.mk_const_var(vid, ty) + } + + pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { + self.const_unification_table + .borrow_mut() + .new_var(self.universe(), origin) + } + fn next_int_var_id(&self) -> IntVid { self.int_unification_table.borrow_mut().new_key(None) } @@ -1092,7 +1120,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_ty_var(ty_var_id).into() } GenericParamDefKind::Const { .. } => { - unimplemented!() // FIXME(const_generics) + let const_var_id = + self.const_unification_table + .borrow_mut() + .new_var( + self.universe(), + ConstVariableOrigin::ConstParameterDefinition(span, param.name), + ); + self.tcx.mk_const_var(const_var_id, self.tcx.type_of(param.def_id)).into() } } } @@ -1233,11 +1268,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.resolve_type_vars_if_possible(t).to_string() } - // We have this force-inlined variant of shallow_resolve() for the one + // We have this force-inlined variant of `shallow_resolve_type` for the one // callsite that is extremely hot. All other callsites use the normal // variant. #[inline(always)] - pub fn inlined_shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { + pub fn inlined_shallow_resolve_type(&self, typ: Ty<'tcx>) -> Ty<'tcx> { match typ.sty { ty::Infer(ty::TyVar(v)) => { // Not entirely obvious: if `typ` is a type variable, @@ -1253,7 +1288,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .borrow_mut() .probe(v) .known() - .map(|t| self.shallow_resolve(t)) + .map(|t| self.shallow_resolve_type(t)) .unwrap_or(typ) } @@ -1284,8 +1319,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - self.inlined_shallow_resolve(typ) + pub fn shallow_resolve_type(&self, typ: Ty<'tcx>) -> Ty<'tcx> { + self.inlined_shallow_resolve_type(typ) } pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { @@ -1323,9 +1358,60 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { r.first_unresolved } - pub fn fully_resolve>(&self, value: &T) -> FixupResult { + pub fn probe_const_var( + &self, + vid: ty::ConstVid<'tcx> + ) -> Result<&'tcx ty::LazyConst<'tcx>, ty::UniverseIndex> { + use self::const_variable::ConstVariableValue; + + match self.const_unification_table.borrow_mut().probe(vid) { + ConstVariableValue::Known { value } => Ok(value), + ConstVariableValue::Unknown { universe } => Err(universe), + } + } + + pub fn resolve_const_var( + &self, + ct: &'tcx ty::LazyConst<'tcx> + ) -> &'tcx ty::LazyConst<'tcx> { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Var(v)), + .. + }) = ct { + self.const_unification_table + .borrow_mut() + .probe(*v) + .known() + .map(|c| self.resolve_const_var(c)) + .unwrap_or(ct) + } else { + ct + } + } + + pub fn shallow_resolve_const( + &self, + ct: &'tcx ty::LazyConst<'tcx> + ) -> &'tcx ty::LazyConst<'tcx> { + match ct { + ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Var(vid)), + .. + }) => { + self.const_unification_table + .borrow_mut() + .probe(*vid) + .known() + .map(|c| self.shallow_resolve_const(c)) + .unwrap_or(ct) + } + _ => ct, + } + } + + pub fn fully_resolve>(&self, value: &T) -> FixupResult<'tcx, T> { /*! - * Attempts to resolve all type/region variables in + * Attempts to resolve all type/region/const variables in * `value`. Region inference must have been run already (e.g., * by calling `resolve_regions_and_report_errors`). If some * variable was never unified, an `Err` results. @@ -1441,7 +1527,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { closure_substs: ty::ClosureSubsts<'tcx>, ) -> Option { let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx); - let closure_kind_ty = self.shallow_resolve(&closure_kind_ty); + let closure_kind_ty = self.shallow_resolve_type(&closure_kind_ty); closure_kind_ty.to_opt_closure_kind() } @@ -1455,7 +1541,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { substs: ty::ClosureSubsts<'tcx>, ) -> ty::PolyFnSig<'tcx> { let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx); - let closure_sig_ty = self.shallow_resolve(&closure_sig_ty); + let closure_sig_ty = self.shallow_resolve_type(&closure_sig_ty); closure_sig_ty.fn_sig(self.tcx) } From bfc39b9b876e8a0ebf65b1cc8431c8abdb0a37f2 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:19:13 +0000 Subject: [PATCH 12/47] Implement TypeRelation::consts Co-Authored-By: Gabriel Smith --- src/librustc/infer/canonical/canonicalizer.rs | 53 ++++++++++++++++++- src/librustc/infer/combine.rs | 28 +++++++++- src/librustc/infer/equate.rs | 48 +++++++++++++++-- src/librustc/infer/glb.rs | 13 +++++ src/librustc/infer/lub.rs | 13 +++++ src/librustc/infer/nll_relate/mod.rs | 50 ++++++++++++++--- src/librustc/infer/sub.rs | 49 ++++++++++++++++- src/librustc/ty/_match.rs | 34 +++++++++++- .../chalk_context/resolvent_ops.rs | 45 +++++++++++++++- 9 files changed, 315 insertions(+), 18 deletions(-) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 9bd7f4c02d7be..0fc13bdaee65f 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -10,10 +10,11 @@ use crate::infer::canonical::{ OriginalQueryValues, }; use crate::infer::InferCtxt; +use crate::mir::interpret::ConstValue; use std::sync::atomic::Ordering; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::subst::Kind; -use crate::ty::{self, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags}; +use crate::ty::{self, BoundVar, InferConst, Lift, List, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; @@ -432,6 +433,54 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> } } } + + fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + if let ty::LazyConst::Evaluated(ct) = c { + match ct.val { + ConstValue::Infer(InferConst::Var(vid)) => { + debug!("canonical: const var found with vid {:?}", vid); + match self.infcx.unwrap().probe_const_var(vid) { + Ok(c) => { + debug!("(resolved to {:?})", c); + return self.fold_const(c); + } + + // `ConstVar(vid)` is unresolved, track its universe index in the + // canonicalized result + Err(mut ui) => { + if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk { + // FIXME: perf problem described in #55921. + ui = ty::UniverseIndex::ROOT; + } + return self.canonicalize_const_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Const(ui) + }, + c + ); + } + } + } + ConstValue::Infer(InferConst::Fresh(_)) => { + bug!("encountered a fresh const during canonicalization") + } + ConstValue::Infer(InferConst::Canonical(debruijn, _)) => { + if debruijn >= self.binder_index { + bug!("escaping bound type during canonicalization") + } else { + return c; + } + } + _ => {} + } + } + + if c.type_flags().intersects(self.needs_canonical_flags) { + c.super_fold_with(self) + } else { + c + } + } } impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { @@ -625,7 +674,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { /// `ty_var`. fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.infcx.expect("encountered ty-var without infcx"); - let bound_to = infcx.shallow_resolve(ty_var); + let bound_to = infcx.shallow_resolve_type(ty_var); if bound_to != ty_var { self.fold_ty(bound_to) } else { diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index f212f6298be53..203fd25c84280 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -464,7 +464,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' debug!("generalize: t={:?}", t); - // Check to see whether the type we are genealizing references + // Check to see whether the type we are generalizing references // any other type variable related to `vid` via // subtyping. This is basically our "occurs check", preventing // us from creating infinitely sized types. @@ -576,6 +576,32 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' // very descriptive origin for this region variable. Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) } + + fn consts( + &mut self, + c: &'tcx ty::LazyConst<'tcx>, + c2: &'tcx ty::LazyConst<'tcx> + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == + + match c { + LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Var(vid)), + .. + }) => { + let mut variable_table = self.infcx.const_unification_table.borrow_mut(); + match variable_table.probe(*vid).known() { + Some(u) => { + self.relate(&u, &u) + } + None => Ok(c), + } + } + _ => { + relate::super_relate_consts(self, c, c) + } + } + } } pub trait RelateResultCompare<'tcx, T> { diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 31b01eecf5cb6..e94996a0b99a3 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -1,12 +1,13 @@ -use super::combine::{CombineFields, RelationDir}; -use super::{Subtype}; +use super::combine::{CombineFields, RelationDir, const_unification_error}; +use super::Subtype; use crate::hir::def_id::DefId; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt, InferConst}; use crate::ty::TyVar; use crate::ty::subst::SubstsRef; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use crate::mir::interpret::ConstValue; /// Ensures `a` is made equal to `b`. Returns `a` on success. pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { @@ -100,6 +101,47 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> Ok(a) } + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + debug!("{}.consts({:?}, {:?})", self.tag(), a, b); + if a == b { return Ok(a); } + + let infcx = self.fields.infcx; + let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a); + let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b); + let a_is_expected = self.a_is_expected(); + if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { + match (a_eval.val, b_eval.val) { + (ConstValue::Infer(InferConst::Var(a_vid)), + ConstValue::Infer(InferConst::Var(b_vid))) => { + infcx.const_unification_table + .borrow_mut() + .unify_var_var(a_vid, b_vid) + .map_err(|e| const_unification_error(a_is_expected, e))?; + return Ok(a); + } + + (ConstValue::Infer(InferConst::Var(a_id)), _) => { + self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?; + return Ok(a); + } + + (_, ConstValue::Infer(InferConst::Var(b_id))) => { + self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?; + return Ok(a); + } + + _ => {} + } + } + + self.fields.infcx.super_combine_consts(self, a, b)?; + Ok(a) + } + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 910c6571853dc..dde43d2072271 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -60,6 +60,19 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> Ok(self.fields.infcx.borrow_region_constraints().glb_regions(self.tcx(), origin, a, b)) } + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + debug!("{}.consts({:?}, {:?})", self.tag(), a, b); + if a == b { + return Ok(a); + } + + self.fields.infcx.super_combine_consts(self, a, b) + } + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index f9eb60d82d17b..2a06886d94b68 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -60,6 +60,19 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> Ok(self.fields.infcx.borrow_region_constraints().lub_regions(self.tcx(), origin, a, b)) } + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + debug!("{}.consts({:?}, {:?})", self.tag(), a, b); + if a == b { + return Ok(a); + } + + self.fields.infcx.super_combine_consts(self, a, b) + } + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index 753fd04aac38a..91a1e0a13bc2f 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -27,7 +27,7 @@ use crate::ty::error::TypeError; use crate::ty::fold::{TypeFoldable, TypeVisitor}; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::ty::subst::Kind; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt, InferConst}; use rustc_data_structures::fx::FxHashMap; use std::fmt::Debug; @@ -537,10 +537,10 @@ where } fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let a = self.infcx.shallow_resolve(a); + let a = self.infcx.shallow_resolve_type(a); if !D::forbid_inference_vars() { - b = self.infcx.shallow_resolve(b); + b = self.infcx.shallow_resolve_type(b); } match (&a.sty, &b.sty) { @@ -608,6 +608,24 @@ where Ok(a) } + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(_, _)), + .. + }) = a { + // FIXME(const_generics): I'm unsure how this branch should actually be handled, + // so this is probably not correct. + self.infcx.super_combine_consts(self, a, b) + } else { + debug!("consts(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); + relate::super_relate_consts(self, a, b) + } + } + fn binders( &mut self, a: &ty::Binder, @@ -853,7 +871,7 @@ where fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { use crate::infer::type_variable::TypeVariableValue; - debug!("TypeGeneralizer::tys(a={:?})", a,); + debug!("TypeGeneralizer::tys(a={:?})", a); match a.sty { ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) @@ -934,7 +952,7 @@ where a: ty::Region<'tcx>, _: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("TypeGeneralizer::regions(a={:?})", a,); + debug!("TypeGeneralizer::regions(a={:?})", a); if let ty::ReLateBound(debruijn, _) = a { if *debruijn < self.first_free_index { @@ -963,6 +981,26 @@ where Ok(replacement_region_vid) } + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + _: &'tcx ty::LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + debug!("TypeGeneralizer::consts(a={:?})", a); + + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(_, _)), + .. + }) = a { + bug!( + "unexpected inference variable encountered in NLL generalization: {:?}", + a + ); + } else { + relate::super_relate_consts(self, a, a) + } + } + fn binders( &mut self, a: &ty::Binder, @@ -971,7 +1009,7 @@ where where T: Relate<'tcx>, { - debug!("TypeGeneralizer::binders(a={:?})", a,); + debug!("TypeGeneralizer::binders(a={:?})", a); self.first_free_index.shift_in(1); let result = self.relate(a.skip_binder(), a.skip_binder())?; diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 0cff42742c30a..b285d59729110 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -1,11 +1,12 @@ use super::SubregionOrigin; -use super::combine::{CombineFields, RelationDir}; +use super::combine::{CombineFields, RelationDir, const_unification_error}; use crate::traits::Obligation; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt, InferConst}; use crate::ty::TyVar; use crate::ty::fold::TypeFoldable; use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; +use crate::mir::interpret::ConstValue; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. @@ -133,6 +134,50 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> Ok(a) } + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + debug!("{}.consts({:?}, {:?})", self.tag(), a, b); + if a == b { return Ok(a); } + + let infcx = self.fields.infcx; + let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a); + let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b); + + // Consts can only be equal or unequal to each other: there's no subtyping + // relation, so we're just going to perform equating here instead. + let a_is_expected = self.a_is_expected(); + if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { + match (a_eval.val, b_eval.val) { + (ConstValue::Infer(InferConst::Var(a_vid)), + ConstValue::Infer(InferConst::Var(b_vid))) => { + infcx.const_unification_table + .borrow_mut() + .unify_var_var(a_vid, b_vid) + .map_err(|e| const_unification_error(a_is_expected, e))?; + return Ok(a); + } + + (ConstValue::Infer(InferConst::Var(a_id)), _) => { + self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?; + return Ok(a); + } + + (_, ConstValue::Infer(InferConst::Var(b_id))) => { + self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?; + return Ok(a); + } + + _ => {} + } + } + + self.fields.infcx.super_combine_consts(self, a, b)?; + Ok(a) + } + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index 07fa441bb8076..fdc6956101410 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -1,6 +1,7 @@ -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::error::TypeError; +use crate::ty::{self, Ty, TyCtxt, InferConst}; +use crate::ty::error::{TypeError, ConstError}; use crate::ty::relate::{self, Relate, TypeRelation, RelateResult}; +use crate::mir::interpret::ConstValue; /// A type "A" *matches* "B" if the fresh types in B could be /// substituted with values so as to make it equal to A. Matching is @@ -78,6 +79,35 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> { } } + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + debug!("{}.consts({:?}, {:?})", self.tag(), a, b); + if a == b { + return Ok(a); + } + + if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { + match (a_eval.val, b_eval.val) { + (_, ConstValue::Infer(InferConst::Fresh(_))) => { + return Ok(a); + } + + (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { + return Err(TypeError::ConstError( + ConstError::Mismatch(relate::expected_found(self, &a, &b)) + )); + } + + _ => {} + } + } + + relate::super_relate_consts(self, a, b) + } + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs index 4f5a4996db537..7fc0530875406 100644 --- a/src/librustc_traits/chalk_context/resolvent_ops.rs +++ b/src/librustc_traits/chalk_context/resolvent_ops.rs @@ -16,9 +16,10 @@ use rustc::traits::{ Environment, InEnvironment, }; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, InferConst}; use rustc::ty::subst::Kind; use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc::mir::interpret::ConstValue; use syntax_pos::DUMMY_SP; use super::{ChalkInferenceContext, ChalkArenas, ChalkExClause, ConstrainedSubst}; @@ -203,7 +204,7 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { } fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let b = self.infcx.shallow_resolve(b); + let b = self.infcx.shallow_resolve_type(b); debug!("AnswerSubstitutor::tys(a = {:?}, b = {:?})", a, b); if let &ty::Bound(debruijn, bound_ty) = &a.sty { @@ -275,4 +276,44 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { Ok(a) } + + fn consts( + &mut self, + a: &'tcx ty::LazyConst<'tcx>, + b: &'tcx ty::LazyConst<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)), + .. + }) = a { + if *debruijn == self.binder_index { + self.unify_free_answer_var(*bound_ct, b.into())?; + return Ok(b); + } + } + + match (a, b) { + ( + ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(a_debruijn, a_bound)), + .. + }), + ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(b_debruijn, b_bound)), + .. + }), + ) => { + assert_eq!(a_debruijn, b_debruijn); + assert_eq!(a_bound, b_bound); + Ok(a) + } + + // Everything else should just be a perfect match as well, + // and we forbid inference variables. + _ => match ty::relate::super_relate_consts(self, a, b) { + Ok(ct) => Ok(ct), + Err(err) => bug!("const mismatch in `AnswerSubstitutor`: {}", err), + } + } + } } From 69423b334503c1f860f0dd7b8568dd99fa380e3b Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:19:53 +0000 Subject: [PATCH 13/47] Add stubs for `fold_const` Co-Authored-By: Gabriel Smith --- src/librustc/infer/freshen.rs | 4 ++++ src/librustc/infer/fudge.rs | 4 ++++ src/librustc/infer/opaque_types/mod.rs | 4 ++++ src/librustc/ty/fold.rs | 8 ++++++++ 4 files changed, 20 insertions(+) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 27ed36ab98b0f..dcc4917f6a159 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -192,4 +192,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::Bound(..) => bug!("unexpected type {:?}", t), } } + + fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + ct // FIXME(const_generics) + } } diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 7788ae2b88f21..4bab0bedbd66e 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -174,4 +174,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> } r } + + fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + ct // FIXME(const_generics) + } } diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 6d8558211818b..0b35b239c870f 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -659,6 +659,10 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> _ => ty.super_fold_with(self), } } + + fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + ct // FIXME(const_generics) + } } struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index afd94757b2329..dd936efb3c807 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -505,6 +505,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> _ => r } } + + fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + ct // FIXME(const_generics) + } } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -740,6 +744,10 @@ impl TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { _ => ty.super_fold_with(self), } } + + fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + ct // FIXME(const_generics) + } } pub fn shift_region<'a, 'gcx, 'tcx>( From d113ff8ada02d4ea253d78b77186637a7d7344bb Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:20:33 +0000 Subject: [PATCH 14/47] Handle generic consts in relate and infer Co-Authored-By: Gabriel Smith --- .../infer/canonical/query_response.rs | 16 ++++-- src/librustc/infer/resolve.rs | 52 ++++++++++++++++--- src/librustc/ty/relate.rs | 26 ++++++++-- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index e605aae0fae0d..65c579aedf2f4 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -16,6 +16,7 @@ use crate::infer::canonical::{ use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxtBuilder; use crate::infer::{InferCtxt, InferOk, InferResult}; +use crate::mir::interpret::ConstValue; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use std::fmt::Debug; @@ -25,7 +26,7 @@ use crate::traits::TraitEngine; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::ty::fold::TypeFoldable; use crate::ty::subst::{Kind, UnpackedKind}; -use crate::ty::{self, BoundVar, Lift, Ty, TyCtxt}; +use crate::ty::{self, BoundVar, InferConst, Lift, Ty, TyCtxt}; use crate::util::captures::Captures; impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> { @@ -479,8 +480,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { opt_values[br.assert_bound_var()] = Some(*original_value); } } - UnpackedKind::Const(..) => { - unimplemented!() // FIXME(const_generics) + UnpackedKind::Const(result_value) => { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Canonical(debrujin, b)), + .. + }) = result_value { + // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. + + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(*debrujin, ty::INNERMOST); + opt_values[*b] = Some(*original_value); + } } } } diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 6adbf2bcef866..30a398de19ae7 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -1,5 +1,6 @@ use super::{InferCtxt, FixupError, FixupResult, Span, type_variable::TypeVariableOrigin}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use crate::mir::interpret::ConstValue; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable, InferConst}; use crate::ty::fold::{TypeFolder, TypeVisitor}; /////////////////////////////////////////////////////////////////////////// @@ -7,7 +8,7 @@ use crate::ty::fold::{TypeFolder, TypeVisitor}; /// The opportunistic type resolver can be used at any time. It simply replaces /// type variables that have been unified with the things they have -/// been unified with (similar to `shallow_resolve`, but deep). This is +/// been unified with (similar to `shallow_resolve_type`, but deep). This is /// useful for printing messages etc but also required at various /// points for correctness. pub struct OpportunisticTypeResolver<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { @@ -30,7 +31,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeResolver<'a, 'g if !t.has_infer_types() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { - let t0 = self.infcx.shallow_resolve(t); + let t0 = self.infcx.shallow_resolve_type(t); t0.super_fold_with(self) } } @@ -58,7 +59,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv if !t.needs_infer() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { - let t0 = self.infcx.shallow_resolve(t); + let t0 = self.infcx.shallow_resolve_type(t); t0.super_fold_with(self) } } @@ -72,6 +73,15 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv r, } } + + fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + if !ct.needs_infer() { + ct // micro-optimize -- if there is nothing in this const that this fold affects... + } else { + let c0 = self.infcx.shallow_resolve_const(ct); + c0.super_fold_with(self) + } + } } /////////////////////////////////////////////////////////////////////////// @@ -96,7 +106,7 @@ impl<'a, 'gcx, 'tcx> UnresolvedTypeFinder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'gcx, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - let t = self.infcx.shallow_resolve(t); + let t = self.infcx.shallow_resolve_type(t); if t.has_infer_types() { if let ty::Infer(infer_ty) = t.sty { // Since we called `shallow_resolve` above, this must @@ -136,7 +146,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'gcx, 'tcx> /// their concrete results. If any variable cannot be replaced (never unified, etc) /// then an `Err` result is returned. pub fn fully_resolve<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - value: &T) -> FixupResult + value: &T) -> FixupResult<'tcx, T> where T : TypeFoldable<'tcx> { let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; @@ -151,7 +161,7 @@ pub fn fully_resolve<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // `err` field is not enforcable otherwise. struct FullTypeResolver<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - err: Option, + err: Option>, } impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> { @@ -165,7 +175,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> // ^ we need to have the `keep_local` check to un-default // defaulted tuples. } else { - let t = self.infcx.shallow_resolve(t); + let t = self.infcx.shallow_resolve_type(t); match t.sty { ty::Infer(ty::TyVar(vid)) => { self.err = Some(FixupError::UnresolvedTy(vid)); @@ -199,4 +209,30 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> _ => r, } } + + fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + if !c.needs_infer() && !ty::keep_local(&c) { + c // micro-optimize -- if there is nothing in this const that this fold affects... + // ^ we need to have the `keep_local` check to un-default + // defaulted tuples. + } else { + let c = self.infcx.shallow_resolve_const(c); + match c { + ty::LazyConst::Evaluated(ty::Const { val, .. }) => { + match val { + ConstValue::Infer(InferConst::Var(vid)) => { + self.err = Some(FixupError::UnresolvedConst(*vid)); + return self.tcx().types.ct_err; + } + ConstValue::Infer(InferConst::Fresh(_)) => { + bug!("Unexpected const in full const resolver: {:?}", c); + } + _ => {} + } + } + _ => {} + } + c.super_fold_with(self) + } + } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2034795a0b582..5980192a5070f 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -7,8 +7,8 @@ use crate::hir::def_id::DefId; use crate::ty::subst::{Kind, UnpackedKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; -use crate::ty::error::{ExpectedFound, TypeError}; -use crate::mir::interpret::{GlobalId, ConstValue}; +use crate::ty::error::{ExpectedFound, TypeError, ConstError}; +use crate::mir::interpret::{GlobalId, ConstValue, Scalar}; use crate::util::common::ErrorReported; use syntax_pos::DUMMY_SP; use std::rc::Rc; @@ -476,6 +476,8 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let t = relation.relate(&a_t, &b_t)?; let to_u64 = |x: ty::Const<'tcx>| -> Result { match x.val { + // FIXME(const_generics): this doesn't work right now, + // because it tries to relate an `Infer` to a `Param`. ConstValue::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. let param_env = ty::ParamEnv::empty(); @@ -489,7 +491,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, if let Some(instance) = instance { let cid = GlobalId { instance, - promoted: None + promoted: None, }; if let Some(s) = tcx.const_eval(param_env.and(cid)) .ok() @@ -718,6 +720,17 @@ impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { } } +impl<'tcx> Relate<'tcx> for &'tcx ty::LazyConst<'tcx> { + fn relate<'a, 'gcx, R>(relation: &mut R, + a: &&'tcx ty::LazyConst<'tcx>, + b: &&'tcx ty::LazyConst<'tcx>) + -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a + { + relation.consts(*a, *b) + } +} + impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder { fn relate<'a, 'gcx, R>(relation: &mut R, a: &ty::Binder, @@ -771,14 +784,17 @@ impl<'tcx> Relate<'tcx> for Kind<'tcx> { (UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => { Ok(relation.relate(&a_ty, &b_ty)?.into()) } + (UnpackedKind::Const(a_ct), UnpackedKind::Const(b_ct)) => { + Ok(relation.relate(&a_ct, &b_ct)?.into()) + } (UnpackedKind::Lifetime(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } (UnpackedKind::Type(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (UnpackedKind::Const(_), _) => { - unimplemented!() // FIXME(const_generics) + (UnpackedKind::Const(unpacked), x) => { + bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } } } From 3f675ab038cfd82550fe54b7d659f26753987d34 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:20:58 +0000 Subject: [PATCH 15/47] Drive-by comment fixes Co-Authored-By: Gabriel Smith --- src/librustc/infer/type_variable.rs | 4 ++-- src/librustc/infer/unify_key.rs | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 1393e4f67eb92..88933312b0d40 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -17,7 +17,7 @@ pub struct TypeVariableTable<'tcx> { /// the known value. eq_relations: ut::UnificationTable>>, - /// Two variables are unified in `eq_relations` when we have a + /// Two variables are unified in `sub_relations` when we have a /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second /// table exists only to help with the occurs check. In particular, /// we want to report constraints like these as an occurs check @@ -365,7 +365,7 @@ impl sv::SnapshotVecDelegate for Delegate { 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 + // instantiation; 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 diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index 09f800d9f9bfc..208c553aa327f 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -12,8 +12,7 @@ impl UnifyKey for ty::IntVid { fn tag() -> &'static str { "IntVid" } } -impl EqUnifyValue for IntVarValue { -} +impl EqUnifyValue for IntVarValue {} #[derive(PartialEq, Copy, Clone, Debug)] pub struct RegionVidKey { @@ -62,8 +61,7 @@ impl UnifyKey for ty::FloatVid { fn tag() -> &'static str { "FloatVid" } } -impl EqUnifyValue for FloatVarValue { -} +impl EqUnifyValue for FloatVarValue {} impl ToType for FloatVarValue { fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { From ed3dae4acaa856a426c58a45ef6a843420f1e4a9 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:21:19 +0000 Subject: [PATCH 16/47] Rename *shallow_resolve to *shallow_resolve_type Co-Authored-By: Gabriel Smith --- src/librustc/traits/fulfill.rs | 4 ++-- src/librustc/traits/project.rs | 6 +++--- src/librustc/traits/select.rs | 18 +++++++++--------- src/librustc/ty/wf.rs | 2 +- src/librustc_typeck/check/_match.rs | 4 ++-- src/librustc_typeck/check/coercion.rs | 14 +++++++------- src/librustc_typeck/check/mod.rs | 4 ++-- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index e725ebb797e37..59a9fd11e1d57 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -255,8 +255,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, // doing more work yet if !pending_obligation.stalled_on.is_empty() { if pending_obligation.stalled_on.iter().all(|&ty| { - // Use the force-inlined variant of shallow_resolve() because this code is hot. - let resolved_ty = self.selcx.infcx().inlined_shallow_resolve(&ty); + // Use the force-inlined variant of shallow_resolve_type() because this code is hot. + let resolved_ty = self.selcx.infcx().inlined_shallow_resolve_type(&ty); resolved_ty == ty // nothing changed here }) { debug!("process_predicate: pending obligation {:?} still stalled on {:?}", diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 882635e21f57c..763fa40d8f3bb 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1229,7 +1229,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( -> Progress<'tcx> { let self_ty = obligation_trait_ref.self_ty(); - let object_ty = selcx.infcx().shallow_resolve(self_ty); + let object_ty = selcx.infcx().shallow_resolve_type(self_ty); debug!("confirm_object_candidate(object_ty={:?})", object_ty); let data = match object_ty.sty { @@ -1346,7 +1346,7 @@ fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>) -> Progress<'tcx> { - let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); + let fn_type = selcx.infcx().shallow_resolve_type(fn_pointer_vtable.fn_ty); let sig = fn_type.fn_sig(selcx.tcx()); let Normalized { value: sig, @@ -1371,7 +1371,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>( let tcx = selcx.tcx(); let infcx = selcx.infcx(); let closure_sig_ty = vtable.substs.closure_sig_ty(vtable.closure_def_id, tcx); - let closure_sig = infcx.shallow_resolve(&closure_sig_ty).fn_sig(tcx); + let closure_sig = infcx.shallow_resolve_type(&closure_sig_ty).fn_sig(tcx); let Normalized { value: closure_sig, obligations diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 8beabe058cf4f..18ac30b7f1eb2 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2403,7 +2403,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // NOTE: binder moved to (*) let self_ty = self.infcx - .shallow_resolve(obligation.predicate.skip_binder().self_ty()); + .shallow_resolve_type(obligation.predicate.skip_binder().self_ty()); match self_ty.sty { ty::Infer(ty::IntVar(_)) @@ -2467,7 +2467,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ) -> BuiltinImplConditions<'tcx> { // NOTE: binder moved to (*) let self_ty = self.infcx - .shallow_resolve(obligation.predicate.skip_binder().self_ty()); + .shallow_resolve_type(obligation.predicate.skip_binder().self_ty()); use self::BuiltinImplConditions::{Ambiguous, None, Where}; @@ -2866,7 +2866,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ); let types = obligation.predicate.map_bound(|inner| { - let self_ty = self.infcx.shallow_resolve(inner.self_ty()); + let self_ty = self.infcx.shallow_resolve_type(inner.self_ty()); self.constituent_types_for_ty(self_ty) }); self.vtable_auto_impl(obligation, trait_def_id, types) @@ -2990,7 +2990,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // from the object. Have to try to make a broken test case that // results. let self_ty = self.infcx - .shallow_resolve(*obligation.self_ty().skip_binder()); + .shallow_resolve_type(*obligation.self_ty().skip_binder()); let poly_trait_ref = match self_ty.sty { ty::Dynamic(ref data, ..) => data.principal().unwrap_or_else(|| { @@ -3045,7 +3045,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // OK to skip binder; it is reintroduced below let self_ty = self.infcx - .shallow_resolve(*obligation.self_ty().skip_binder()); + .shallow_resolve_type(*obligation.self_ty().skip_binder()); let sig = self_ty.fn_sig(self.tcx()); let trait_ref = self.tcx() .closure_trait_ref_and_return_type( @@ -3125,7 +3125,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters let self_ty = self.infcx - .shallow_resolve(obligation.self_ty().skip_binder()); + .shallow_resolve_type(obligation.self_ty().skip_binder()); let (generator_def_id, substs) = match self_ty.sty { ty::Generator(id, substs, _) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), @@ -3183,7 +3183,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters let self_ty = self.infcx - .shallow_resolve(obligation.self_ty().skip_binder()); + .shallow_resolve_type(obligation.self_ty().skip_binder()); let (closure_def_id, substs) = match self_ty.sty { ty::Closure(id, substs) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), @@ -3278,14 +3278,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // assemble_candidates_for_unsizing should ensure there are no late bound // regions here. See the comment there for more details. let source = self.infcx - .shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); + .shallow_resolve_type(obligation.self_ty().no_bound_vars().unwrap()); let target = obligation .predicate .skip_binder() .trait_ref .substs .type_at(1); - let target = self.infcx.shallow_resolve(target); + let target = self.infcx.shallow_resolve_type(target); debug!( "confirm_builtin_unsize_candidate(source={:?}, target={:?})", diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index b793b37fb2ae1..c8ee3fd482b3f 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -406,7 +406,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // moving. (Goal is that an "inductive hypothesis" // is satisfied to ensure termination.) ty::Infer(_) => { - let ty = self.infcx.shallow_resolve(ty); + let ty = self.infcx.shallow_resolve_type(ty); if let ty::Infer(_) = ty.sty { // not yet resolved... if ty == ty0 { // ...this is the type we started from! no progress. return false; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 8cdfbf5f55ca0..f03a3bde84e4c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -350,7 +350,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } PatKind::Ref(ref inner, mutbl) => { - let expected = self.shallow_resolve(expected); + let expected = self.shallow_resolve_type(expected); if self.check_dereferencable(pat.span, expected, &inner) { // `demand::subtype` would be good enough, but using // `eqtype` turns out to be equally general. See (*) @@ -519,7 +519,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { if let PatKind::Binding(..) = inner.node { - if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { + if let Some(mt) = self.shallow_resolve_type(expected).builtin_deref(true) { if let ty::Dynamic(..) = mt.ty.sty { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box", an error. diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 85eb0f9d49966..1c6601536eea1 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -154,7 +154,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - let a = self.shallow_resolve(a); + let a = self.shallow_resolve_type(a); debug!("Coerce.tys({:?} => {:?})", a, b); // Just ignore error types. @@ -170,8 +170,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // let _: Option = Some({ return; }); // // here, we would coerce from `!` to `?T`. - let b = self.shallow_resolve(b); - return if self.shallow_resolve(b).is_ty_var() { + let b = self.shallow_resolve_type(b); + return if self.shallow_resolve_type(b).is_ty_var() { // micro-optimization: no need for this if `b` is // already resolved in some way. let diverging_ty = self.next_diverging_ty_var( @@ -659,7 +659,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { //! into a closure or a `proc`. //! - let b = self.shallow_resolve(b); + let b = self.shallow_resolve_type(b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); self.coerce_from_safe_fn(a, fn_ty_a, b, @@ -673,7 +673,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { //! Attempts to coerce from the type of a Rust function item //! into a closure or a `proc`. - let b = self.shallow_resolve(b); + let b = self.shallow_resolve_type(b); debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); match b.sty { @@ -719,7 +719,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { //! into a function pointer. //! - let b = self.shallow_resolve(b); + let b = self.shallow_resolve_type(b); let hir_id_a = self.tcx.hir().as_local_hir_id(def_id_a).unwrap(); match b.sty { @@ -1128,7 +1128,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> // compatibility (hopefully that is true) by helping us // uncover never types better. if expression_ty.is_ty_var() { - expression_ty = fcx.infcx.shallow_resolve(expression_ty); + expression_ty = fcx.infcx.shallow_resolve_type(expression_ty); } // If we see any error types, just propagate that error diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d2d486b52b3f8..4b772abc5f09e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -281,7 +281,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Expectation<'tcx> { match *self { ExpectHasType(ety) => { - let ety = fcx.shallow_resolve(ety); + let ety = fcx.shallow_resolve_type(ety); if !ety.is_ty_var() { ExpectHasType(ety) } else { @@ -2792,7 +2792,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, expected_vid: ty::TyVid, ) -> bool { - let self_ty = self.shallow_resolve(trait_ref.self_ty()); + let self_ty = self.shallow_resolve_type(trait_ref.self_ty()); debug!( "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", trait_ref, self_ty, expected_vid From ef1b2acf12319b060c26722ddae93c45801a1fce Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 8 Mar 2019 01:25:57 +0000 Subject: [PATCH 17/47] Remove `fold_const` override for `ReverseMapper` Co-Authored-By: Gabriel Smith --- src/librustc/infer/opaque_types/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 0b35b239c870f..6d8558211818b 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -659,10 +659,6 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> _ => ty.super_fold_with(self), } } - - fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - ct // FIXME(const_generics) - } } struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> { From 7bf175f30cd605f9be6d45b1d9f8f90d6f91ceb1 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Thu, 28 Feb 2019 22:52:13 -0500 Subject: [PATCH 18/47] impl fold_const for RegionFudger Signed-off-by: Gabriel Smith --- src/librustc/infer/const_variable.rs | 29 +++++++++++++++++++++++++++ src/librustc/infer/fudge.rs | 30 +++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/const_variable.rs b/src/librustc/infer/const_variable.rs index 5691bf08eae1c..ac758add872fe 100644 --- a/src/librustc/infer/const_variable.rs +++ b/src/librustc/infer/const_variable.rs @@ -5,6 +5,7 @@ use crate::ty::{self, InferConst}; use std::cmp; use std::marker::PhantomData; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; @@ -23,6 +24,8 @@ pub enum ConstVariableOrigin { SubstitutionPlaceholder(Span), } +pub type ConstVariableMap<'tcx> = FxHashMap, ConstVariableOrigin>; + struct ConstVariableData { origin: ConstVariableOrigin, } @@ -184,6 +187,32 @@ impl<'tcx> ConstVariableTable<'tcx> { self.values.commit(snapshot); self.relations.commit(relation_snapshot); } + + /// Returns a map `{V1 -> V2}`, where the keys `{V1}` are + /// const-variables created during the snapshot, and the values + /// `{V2}` are the root variables that they were unified with, + /// along with their origin. + pub fn consts_created_since_snapshot( + &mut self, + s: &Snapshot<'tcx> + ) -> ConstVariableMap<'tcx> { + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + + actions_since_snapshot + .iter() + .filter_map(|action| match action { + &sv::UndoLog::NewElem(index) => Some(ty::ConstVid { + index: index as u32, + phantom: PhantomData, + }), + _ => None, + }) + .map(|vid| { + let origin = self.values.get(vid.index as usize).origin.clone(); + (vid, origin) + }) + .collect() + } } impl<'tcx> ut::UnifyKey for ty::ConstVid<'tcx> { diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 4bab0bedbd66e..5bb007dbb0081 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -1,5 +1,6 @@ use crate::ty::{self, Ty, TyCtxt, TyVid, IntVid, FloatVid, RegionVid}; use crate::ty::fold::{TypeFoldable, TypeFolder}; +use crate::mir::interpret::ConstValue; use super::InferCtxt; use super::RegionVariableOrigin; @@ -176,6 +177,33 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> } fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - ct // FIXME(const_generics) + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(ty::InferConst::Var(vid)), + ty, + }) = *ct { + match self.const_variables.get(&vid) { + None => { + // This variable was created before the + // "fudging". Since we refresh all + // variables to their binding anyhow, we know + // that it is unbound, so we can just return + // it. + debug_assert!( + self.infcx.const_unification_table.borrow_mut() + .probe(vid) + .is_unknown() + ); + ct + } + Some(&origin) => { + // This variable was created during the + // fudging. Recreate it with a fresh variable + // here. + self.infcx.next_const_var(ty, origin) + } + } + } else { + ct.super_fold_with(self) + } } } From bd2fa222c0d1b768f2c4d3eb17828184b4a26d1c Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Thu, 28 Feb 2019 23:02:32 -0500 Subject: [PATCH 19/47] Rename mk_infer to mk_ty_infer Signed-off-by: Gabriel Smith --- src/librustc/infer/freshen.rs | 2 +- src/librustc/traits/error_reporting.rs | 4 ++-- src/librustc/ty/context.rs | 8 ++++---- src/librustc/ty/wf.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index dcc4917f6a159..a45f01043f339 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -72,7 +72,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { Entry::Vacant(entry) => { let index = self.freshen_count; self.freshen_count += 1; - let t = self.infcx.tcx.mk_infer(freshener(index)); + let t = self.infcx.tcx.mk_ty_infer(freshener(index)); entry.insert(t); t } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 47d96708ebea3..007ff32f32776 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1248,7 +1248,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let sig = if let ty::Tuple(inputs) = inputs.sty { tcx.mk_fn_sig( inputs.iter().map(|k| k.expect_ty()), - tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, ::rustc_target::spec::abi::Abi::Rust @@ -1256,7 +1256,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } else { tcx.mk_fn_sig( ::std::iter::once(inputs), - tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, ::rustc_target::spec::abi::Abi::Rust diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index eab98305ebffa..150138ae0b9dc 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2652,7 +2652,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { - self.mk_infer(TyVar(v)) + self.mk_ty_infer(TyVar(v)) } #[inline] @@ -2665,16 +2665,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> { - self.mk_infer(IntVar(v)) + self.mk_ty_infer(IntVar(v)) } #[inline] pub fn mk_float_var(self, v: FloatVid) -> Ty<'tcx> { - self.mk_infer(FloatVar(v)) + self.mk_ty_infer(FloatVar(v)) } #[inline] - pub fn mk_infer(self, it: InferTy) -> Ty<'tcx> { + pub fn mk_ty_infer(self, it: InferTy) -> Ty<'tcx> { self.mk_ty(Infer(it)) } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c8ee3fd482b3f..fc8fcff7475c4 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -516,7 +516,7 @@ pub fn object_region_bounds<'a, 'gcx, 'tcx>( // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a placeholder type. - let open_ty = tcx.mk_infer(ty::FreshTy(0)); + let open_ty = tcx.mk_ty_infer(ty::FreshTy(0)); let predicates = existential_predicates.iter().filter_map(|predicate| { if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() { From e965b756035f5c746f79d04369e0b33ffa71e10e Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Thu, 28 Feb 2019 23:03:37 -0500 Subject: [PATCH 20/47] impl mk_const_infer Signed-off-by: Gabriel Smith --- src/librustc/ty/context.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 150138ae0b9dc..ef94008811afd 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2678,6 +2678,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(Infer(it)) } + #[inline] + pub fn mk_const_infer( + self, + ic: InferConst<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx LazyConst<'tcx> { + self.mk_lazy_const(LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(ic), + ty, + })) + } + #[inline] pub fn mk_ty_param(self, index: u32, From c13aa09d498eb02c271e89da266c40686524a7dc Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Thu, 28 Feb 2019 23:05:47 -0500 Subject: [PATCH 21/47] impl fold_const for TypeFreshener Signed-off-by: Gabriel Smith --- src/librustc/infer/freshen.rs | 114 +++++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 22 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index a45f01043f339..b43f78efffb60 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -31,6 +31,7 @@ //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type //! inferencer knows "so far". +use crate::mir::interpret::ConstValue; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use crate::ty::fold::TypeFolder; use crate::util::nodemap::FxHashMap; @@ -42,8 +43,10 @@ use super::unify_key::ToType; pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - freshen_count: u32, - freshen_map: FxHashMap>, + ty_freshen_count: u32, + const_freshen_count: u32, + ty_freshen_map: FxHashMap>, + const_freshen_map: FxHashMap, &'tcx ty::LazyConst<'tcx>>, } impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { @@ -51,33 +54,63 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { -> TypeFreshener<'a, 'gcx, 'tcx> { TypeFreshener { infcx, - freshen_count: 0, - freshen_map: Default::default(), + ty_freshen_count: 0, + const_freshen_count: 0, + ty_freshen_map: Default::default(), + const_freshen_map: Default::default(), } } - fn freshen(&mut self, - opt_ty: Option>, - key: ty::InferTy, - freshener: F) - -> Ty<'tcx> where + fn freshen_ty( + &mut self, + opt_ty: Option>, + key: ty::InferTy, + freshener: F, + ) -> Ty<'tcx> + where F: FnOnce(u32) -> ty::InferTy, { if let Some(ty) = opt_ty { return ty.fold_with(self); } - match self.freshen_map.entry(key) { + match self.ty_freshen_map.entry(key) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { - let index = self.freshen_count; - self.freshen_count += 1; + let index = self.ty_freshen_count; + self.ty_freshen_count += 1; let t = self.infcx.tcx.mk_ty_infer(freshener(index)); entry.insert(t); t } } } + + fn freshen_const( + &mut self, + opt_ct: Option<&'tcx ty::LazyConst<'tcx>>, + key: ty::InferConst<'tcx>, + freshener: F, + ty: Ty<'tcx>, + ) -> &'tcx ty::LazyConst<'tcx> + where + F: FnOnce(u32) -> ty::InferConst<'tcx>, + { + if let Some(ct) = opt_ct { + return ct.fold_with(self); + } + + match self.const_freshen_map.entry(key) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let index = self.const_freshen_count; + self.const_freshen_count += 1; + let ct = self.infcx.tcx.mk_const_infer(freshener(index), ty); + entry.insert(ct); + ct + } + } + } } impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { @@ -124,14 +157,14 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { match t.sty { ty::Infer(ty::TyVar(v)) => { let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known(); - self.freshen( + self.freshen_ty( opt_ty, ty::TyVar(v), ty::FreshTy) } ty::Infer(ty::IntVar(v)) => { - self.freshen( + self.freshen_ty( self.infcx.int_unification_table.borrow_mut() .probe_value(v) .map(|v| v.to_type(tcx)), @@ -140,7 +173,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { } ty::Infer(ty::FloatVar(v)) => { - self.freshen( + self.freshen_ty( self.infcx.float_unification_table.borrow_mut() .probe_value(v) .map(|v| v.to_type(tcx)), @@ -148,14 +181,14 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::FreshFloatTy) } - ty::Infer(ty::FreshTy(c)) | - ty::Infer(ty::FreshIntTy(c)) | - ty::Infer(ty::FreshFloatTy(c)) => { - if c >= self.freshen_count { + ty::Infer(ty::FreshTy(ct)) | + ty::Infer(ty::FreshIntTy(ct)) | + ty::Infer(ty::FreshFloatTy(ct)) => { + if ct >= self.ty_freshen_count { bug!("Encountered a freshend type with id {} \ but our counter is only at {}", - c, - self.freshen_count); + ct, + self.ty_freshen_count); } t } @@ -194,6 +227,43 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { } fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - ct // FIXME(const_generics) + if let ty::LazyConst::Evaluated(ty::Const{ val, ty }) = ct { + match val { + ConstValue::Infer(ty::InferConst::Var(v)) => { + let opt_ct = self.infcx.const_unification_table + .borrow_mut() + .probe(*v) + .known(); + return self.freshen_const( + opt_ct, + ty::InferConst::Var(*v), + ty::InferConst::Fresh, + ty, + ); + } + ConstValue::Infer(ty::InferConst::Fresh(i)) => { + if *i >= self.const_freshen_count { + bug!( + "Encountered a freshend const with id {} \ + but our counter is only at {}", + i, + self.const_freshen_count, + ); + } + return ct; + } + + ConstValue::Infer(ty::InferConst::Canonical(..)) => { + bug!("unexpected const {:?}", ct) + } + + ConstValue::Param(_) | + ConstValue::Scalar(_) | + ConstValue::Slice(..) | + ConstValue::ByRef(..) => {} + } + } + + ct.super_fold_with(self) } } From 57d3a5a32de7a10ed7af886dc6ddd3754c9a394c Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Thu, 28 Feb 2019 23:09:44 -0500 Subject: [PATCH 22/47] impl visit_const for HasEscapingVarsVisitor Signed-off-by: Gabriel Smith --- src/librustc/ty/fold.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index dd936efb3c807..96705124b2823 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -32,6 +32,7 @@ //! looking for, and does not need to visit anything else. use crate::hir::def_id::DefId; +use crate::mir::interpret::ConstValue; use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags, flags::FlagComputation}; use std::collections::BTreeMap; @@ -840,6 +841,17 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { // visited. r.bound_at_or_above_binder(self.outer_index) } + + fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)), + .. + }) = *c { + debruijn >= self.outer_index + } else { + false + } + } } struct HasTypeFlagsVisitor { From fa394c2283b6bdfc87711812739a59da29a2fd2a Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Fri, 1 Mar 2019 01:16:04 -0500 Subject: [PATCH 23/47] impl fold_const for Shifter Signed-off-by: Gabriel Smith --- src/librustc/ty/fold.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 96705124b2823..462bba94dd3f4 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -222,9 +222,9 @@ impl<'a, 'gcx, 'tcx, F, G, H> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx (self.lt_op)(r) } - fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - let c = c.super_fold_with(self); - (self.ct_op)(c) + fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + let ct = ct.super_fold_with(self); + (self.ct_op)(ct) } } @@ -747,7 +747,25 @@ impl TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { } fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - ct // FIXME(const_generics) + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)), + ty, + }) = *ct { + if self.amount == 0 || debruijn < self.current_index { + ct + } else { + let debruijn = match self.direction { + Direction::In => debruijn.shifted_in(self.amount), + Direction::Out => { + assert!(debruijn.as_u32() >= self.amount); + debruijn.shifted_out(self.amount) + } + }; + self.tcx.mk_const_infer(ty::InferConst::Canonical(debruijn, bound_const), ty) + } + } else { + ct.super_fold_with(self) + } } } @@ -842,11 +860,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { r.bound_at_or_above_binder(self.outer_index) } - fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool { + fn visit_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> bool { if let ty::LazyConst::Evaluated(ty::Const { val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)), .. - }) = *c { + }) = *ct { debruijn >= self.outer_index } else { false From cf1a719c19c184ca3014204b21cbd0577dfbc2a4 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 9 Mar 2019 16:54:50 +0000 Subject: [PATCH 24/47] Implement fold_const for BoundVarReplacer --- src/librustc/infer/canonical/substitute.rs | 9 ++- src/librustc/infer/higher_ranked/mod.rs | 15 ++++- src/librustc/infer/mod.rs | 3 +- src/librustc/ty/fold.rs | 72 +++++++++++++++++----- 4 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc/infer/canonical/substitute.rs index 5af4e8366818b..6b716d6c3b8ea 100644 --- a/src/librustc/infer/canonical/substitute.rs +++ b/src/librustc/infer/canonical/substitute.rs @@ -70,6 +70,13 @@ where } }; - tcx.replace_escaping_bound_vars(value, fld_r, fld_t).0 + let fld_c = |bound_ct: ty::BoundVar, _| { + match var_values.var_values[bound_ct].unpack() { + UnpackedKind::Const(ct) => ct, + c => bug!("{:?} is a const but value is {:?}", bound_ct, c), + } + }; + + tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c).0 } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 7c83fe7fd6946..ec77bb39e7d2a 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -4,10 +4,12 @@ use super::combine::CombineFields; use super::{HigherRankedType, InferCtxt, PlaceholderMap}; -use crate::infer::CombinedSnapshot; +use crate::infer::{CombinedSnapshot, ConstVariableOrigin}; use crate::ty::relate::{Relate, RelateResult, TypeRelation}; use crate::ty::{self, Binder, TypeFoldable}; +use syntax_pos::DUMMY_SP; + impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { pub fn higher_ranked_sub( &mut self, @@ -99,7 +101,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { })) }; - let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t); + let fld_c = |_: ty::BoundVar, ty| { + self.next_const_var_in_universe( + ty, + // FIXME(const_generics): do we want a placeholder const? + ConstVariableOrigin::MiscVariable(DUMMY_SP), + next_universe, + ) + }; + + let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c); debug!( "replace_bound_vars_with_placeholders(\ diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 12321f2e355c3..80816100faed7 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1476,7 +1476,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { let fld_r = |br| self.next_region_var(LateBoundRegion(span, br, lbrct)); let fld_t = |_| self.next_ty_var(TypeVariableOrigin::MiscVariable(span)); - self.tcx.replace_bound_vars(value, fld_r, fld_t) + let fld_c = |_, ty| self.next_const_var(ty, ConstVariableOrigin::MiscVariable(span)); + self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c) } /// See the [`region_constraints::verify_generic_bound`] method. diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 462bba94dd3f4..13b5885f51d29 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -431,22 +431,26 @@ struct BoundVarReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), + fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx> + 'a), } impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> { - fn new( + fn new( tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F, - fld_t: &'a mut G + fld_t: &'a mut G, + fld_c: &'a mut H, ) -> Self where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - G: FnMut(ty::BoundTy) -> Ty<'tcx> + G: FnMut(ty::BoundTy) -> Ty<'tcx>, + H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx>, { BoundVarReplacer { tcx, current_index: ty::INNERMOST, fld_r, fld_t, + fld_c, } } } @@ -508,7 +512,29 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> } fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - ct // FIXME(const_generics) + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)), + ty, + }) = *ct { + if debruijn == self.current_index { + let fld_c = &mut self.fld_c; + let ct = fld_c(bound_const, ty); + ty::fold::shift_vars( + self.tcx, + &ct, + self.current_index.as_u32() + ) + } else { + ct + } + } else { + if !ct.has_vars_bound_at_or_above(self.current_index) { + // Nothing more to substitute. + ct + } else { + ct.super_fold_with(self) + } + } } } @@ -532,27 +558,34 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T: TypeFoldable<'tcx> { - // identity for bound types + // identity for bound types and consts let fld_t = |bound_ty| self.mk_ty(ty::Bound(ty::INNERMOST, bound_ty)); - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t) + let fld_c = |bound_ct, ty| { + self.mk_const_infer(ty::InferConst::Canonical(ty::INNERMOST, bound_ct), ty) + }; + self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) } /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping - /// bound regions while the `fld_t` closure replaces escaping bound types. - pub fn replace_escaping_bound_vars( + /// bound regions; the `fld_t` closure replaces escaping bound types and the `fld_c` + /// closure replaces escaping bound consts. + pub fn replace_escaping_bound_vars( self, value: &T, mut fld_r: F, - mut fld_t: G + mut fld_t: G, + mut fld_c: H, ) -> (T, BTreeMap>) where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, - T: TypeFoldable<'tcx> + H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx>, + T: TypeFoldable<'tcx>, { use rustc_data_structures::fx::FxHashMap; let mut region_map = BTreeMap::new(); let mut type_map = FxHashMap::default(); + let mut const_map = FxHashMap::default(); if !value.has_escaping_bound_vars() { (value.clone(), region_map) @@ -565,7 +598,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { *type_map.entry(bound_ty).or_insert_with(|| fld_t(bound_ty)) }; - let mut replacer = BoundVarReplacer::new(self, &mut real_fld_r, &mut real_fld_t); + let mut real_fld_c = |bound_ct, ty| { + *const_map.entry(bound_ct).or_insert_with(|| fld_c(bound_ct, ty)) + }; + + let mut replacer = BoundVarReplacer::new( + self, + &mut real_fld_r, + &mut real_fld_t, + &mut real_fld_c, + ); let result = value.fold_with(&mut replacer); (result, region_map) } @@ -574,17 +616,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Replaces all types or regions bound by the given `Binder`. The `fld_r` /// closure replaces bound regions while the `fld_t` closure replaces bound /// types. - pub fn replace_bound_vars( + pub fn replace_bound_vars( self, value: &Binder, fld_r: F, - fld_t: G + fld_t: G, + fld_c: H, ) -> (T, BTreeMap>) where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, + H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx>, T: TypeFoldable<'tcx> { - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t) + self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) } /// Replaces any late-bound regions bound in `value` with From 245a474ab7f782912255152e68a7e545718820bf Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 12 Mar 2019 19:27:06 +0000 Subject: [PATCH 25/47] Inline ConstError into TypeError --- src/librustc/infer/combine.rs | 6 ++---- src/librustc/ty/_match.rs | 6 ++---- src/librustc/ty/error.rs | 22 ++-------------------- src/librustc/ty/relate.rs | 8 ++------ src/librustc/ty/structural_impls.rs | 21 ++------------------- 5 files changed, 10 insertions(+), 53 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 203fd25c84280..670c44bef3dbf 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -34,7 +34,7 @@ use crate::hir::def_id::DefId; use crate::mir::interpret::ConstValue; use crate::ty::{IntType, UintType}; use crate::ty::{self, Ty, TyCtxt, InferConst, LazyConst}; -use crate::ty::error::{ConstError, TypeError}; +use crate::ty::error::TypeError; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::ty::subst::SubstsRef; use crate::traits::{Obligation, PredicateObligations}; @@ -627,9 +627,7 @@ pub fn const_unification_error<'tcx>( a_is_expected: bool, (a, b): (&'tcx LazyConst<'tcx>, &'tcx LazyConst<'tcx>), ) -> TypeError<'tcx> { - TypeError::ConstError( - ConstError::Mismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) - ) + TypeError::ConstMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) } fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue)) diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index fdc6956101410..82e802dc16407 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -1,5 +1,5 @@ use crate::ty::{self, Ty, TyCtxt, InferConst}; -use crate::ty::error::{TypeError, ConstError}; +use crate::ty::error::TypeError; use crate::ty::relate::{self, Relate, TypeRelation, RelateResult}; use crate::mir::interpret::ConstValue; @@ -96,9 +96,7 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> { } (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { - return Err(TypeError::ConstError( - ConstError::Mismatch(relate::expected_found(self, &a, &b)) - )); + return Err(TypeError::ConstMismatch(relate::expected_found(self, &a, &b))); } _ => {} diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5e3718b73bfd8..6a6708df5cb2e 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -45,13 +45,7 @@ pub enum TypeError<'tcx> { ProjectionBoundsLength(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), - ConstError(ConstError<'tcx>), -} - -// Data structure used in const unification -#[derive(Clone, Debug)] -pub enum ConstError<'tcx> { - Mismatch(ExpectedFound<&'tcx ty::LazyConst<'tcx>>), + ConstMismatch(ExpectedFound<&'tcx ty::LazyConst<'tcx>>), } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -171,19 +165,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { report_maybe_different(f, &format!("trait `{}`", values.expected), &format!("trait `{}`", values.found)) } - ConstError(ref err) => { - write!(f, "{}", err) - } - } - } -} - -impl<'tcx> fmt::Display for ConstError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::ConstError::*; - - match *self { - Mismatch(ref values) => { + ConstMismatch(ref values) => { write!(f, "expected `{:?}`, found `{:?}`", values.expected, values.found) } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 5980192a5070f..5b5eb783f5772 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -626,9 +626,7 @@ where ); } _ => { - Err(TypeError::ConstError( - ConstError::Mismatch(expected_found(relation, &a, &b)) - )) + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) } } } @@ -642,9 +640,7 @@ where Ok(tcx.mk_lazy_const(ty::LazyConst::Unevaluated(*a_def_id, substs))) } _ => { - Err(TypeError::ConstError( - ConstError::Mismatch(expected_found(relation, &a, &b)) - )) + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 548339ee68763..3057c529ddfd4 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -738,22 +738,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { ProjectionBoundsLength(x) => ProjectionBoundsLength(x), Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), - ConstError(ref x) => return tcx.lift(x).map(ConstError), + ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), }) } } -impl<'a, 'tcx> Lift<'tcx> for ty::error::ConstError<'a> { - type Lifted = ty::error::ConstError<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - use ty::error::ConstError::*; - - match *self { - Mismatch(ref x) => return tcx.lift(x).map(Mismatch), - } - } -} - impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { type Lifted = ty::InstanceDef<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -1332,13 +1321,7 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::ProjectionBoundsLength)(x), (ty::error::TypeError::Sorts)(x), (ty::error::TypeError::ExistentialMismatch)(x), - (ty::error::TypeError::ConstError)(x), - } -} - -EnumTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for ty::error::ConstError<'tcx> { - (ty::error::ConstError::Mismatch)(x), + (ty::error::TypeError::ConstMismatch)(x), } } From f5712d2de09e2c35843150b05fdf3672534dff00 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 12 Mar 2019 20:25:41 +0000 Subject: [PATCH 26/47] Add `ConstValue::Placeholder` --- src/librustc/infer/canonical/canonicalizer.rs | 6 ++++-- src/librustc/infer/freshen.rs | 3 ++- src/librustc/mir/interpret/value.rs | 1 + src/librustc/ty/flags.rs | 3 +++ src/librustc/ty/fold.rs | 6 +++++- src/librustc/ty/mod.rs | 4 +++- src/librustc/ty/relate.rs | 3 +++ src/librustc_codegen_ssa/mir/operand.rs | 1 + src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/monomorphize/item.rs | 2 +- 10 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 0fc13bdaee65f..22e5767df3339 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -499,11 +499,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { let needs_canonical_flags = if canonicalize_region_mode.any() { TypeFlags::KEEP_IN_LOCAL_TCX | TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` - TypeFlags::HAS_TY_PLACEHOLDER + TypeFlags::HAS_TY_PLACEHOLDER | + TypeFlags::HAS_CT_PLACEHOLDER } else { TypeFlags::KEEP_IN_LOCAL_TCX | TypeFlags::HAS_RE_PLACEHOLDER | - TypeFlags::HAS_TY_PLACEHOLDER + TypeFlags::HAS_TY_PLACEHOLDER | + TypeFlags::HAS_CT_PLACEHOLDER }; let gcx = tcx.global_tcx(); diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index b43f78efffb60..aa1a86361965a 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -253,7 +253,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { return ct; } - ConstValue::Infer(ty::InferConst::Canonical(..)) => { + ConstValue::Infer(ty::InferConst::Canonical(..)) | + ConstValue::Placeholder(_) => { bug!("unexpected const {:?}", ct) } diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 18c82ecd38edc..12178196cefab 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -58,6 +58,7 @@ impl<'tcx> ConstValue<'tcx> { match *self { ConstValue::Param(_) | ConstValue::Infer(_) | + ConstValue::Placeholder(_) | ConstValue::ByRef(..) | ConstValue::Unevaluated(..) | ConstValue::Slice(..) => None, diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index cb4724adc932c..8d7e7e16e85cb 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -254,6 +254,9 @@ impl FlagComputation { ConstValue::Param(_) => { self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_PARAMS); } + ConstValue::Placeholder(_) => { + self.add_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_CT_PLACEHOLDER); + } _ => {}, } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 13b5885f51d29..5d3c71f3eabb9 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -97,7 +97,11 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { ) } fn has_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER) + self.has_type_flags( + TypeFlags::HAS_RE_PLACEHOLDER | + TypeFlags::HAS_TY_PLACEHOLDER | + TypeFlags::HAS_CT_PLACEHOLDER + ) } fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6b938ea2fccdc..09fd7f2e79af5 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -455,6 +455,7 @@ bitflags! { const HAS_TY_PLACEHOLDER = 1 << 14; const HAS_CT_INFER = 1 << 15; + const HAS_CT_PLACEHOLDER = 1 << 16; const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_SELF.bits | @@ -477,7 +478,8 @@ bitflags! { TypeFlags::HAS_FREE_LOCAL_NAMES.bits | TypeFlags::KEEP_IN_LOCAL_TCX.bits | TypeFlags::HAS_RE_LATE_BOUND.bits | - TypeFlags::HAS_TY_PLACEHOLDER.bits; + TypeFlags::HAS_TY_PLACEHOLDER.bits | + TypeFlags::HAS_CT_PLACEHOLDER.bits; } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 5b5eb783f5772..e60edfeba1c27 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -615,6 +615,9 @@ where (ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => { Ok(a) } + (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => { + Ok(a) + } (ConstValue::Scalar(Scalar::Bits { .. }), _) if a == b => { Ok(a) } diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index c2b1021f816a6..3b8e5b4495383 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -79,6 +79,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { ConstValue::Unevaluated(..) => bug!("unevaluated constant in `OperandRef::from_const`"), ConstValue::Param(_) => bug!("encountered a ConstValue::Param in codegen"), ConstValue::Infer(_) => bug!("encountered a ConstValue::Infer in codegen"), + ConstValue::Placeholder(_) => bug!("encountered a ConstValue::Placeholder in codegen"), ConstValue::Scalar(x) => { let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 55c1bfb17dec3..df6d4568ab3e2 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -524,7 +524,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> layout: Option>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { let op = match val.val { - ConstValue::Param(_) | ConstValue::Infer(_) => bug!(), + ConstValue::Param(_) | ConstValue::Infer(_) | ConstValue::Placeholder(_) => bug!(), ConstValue::ByRef(ptr, alloc) => { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen -- and for `static mut`, we copy on demand anyway. diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 2fc0e08834a6e..b001a09529e5b 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -397,7 +397,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { // FIXME(const_generics): handle debug printing. pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) { match c.val { - ConstValue::Infer(..) => output.push_str("_"), + ConstValue::Infer(..) | ConstValue::Placeholder(_) => output.push_str("_"), ConstValue::Param(ParamConst { name, .. }) => { write!(output, "{}", name).unwrap(); } From e70797b575f4806528e24f7316cbfbacb27c6cf2 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 12 Mar 2019 20:26:16 +0000 Subject: [PATCH 27/47] Add `PlaceholderConst` --- src/librustc/infer/canonical/mod.rs | 12 ++++++++++++ src/librustc/mir/interpret/value.rs | 4 ++++ src/librustc/ty/mod.rs | 2 ++ 3 files changed, 18 insertions(+) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index e8c881fcae7ef..9fad1f47f1372 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -117,6 +117,7 @@ impl CanonicalVarInfo { CanonicalVarKind::Region(_) => true, CanonicalVarKind::PlaceholderRegion(..) => false, CanonicalVarKind::Const(_) => true, + CanonicalVarKind::PlaceholderConst(_) => false, } } } @@ -142,6 +143,9 @@ pub enum CanonicalVarKind { /// Some kind of const inference variable. Const(ty::UniverseIndex), + + /// A "placeholder" that represents "any const". + PlaceholderConst(ty::PlaceholderConst), } impl CanonicalVarKind { @@ -156,6 +160,7 @@ impl CanonicalVarKind { CanonicalVarKind::Region(ui) => ui, CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, CanonicalVarKind::Const(ui) => ui, + CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe, } } } @@ -405,6 +410,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { universe_map(ui), ).into() } + + CanonicalVarKind::PlaceholderConst( + ty::PlaceholderConst { universe, name }, + ) => { + let _ = (universe, name); + unimplemented!() // FIXME(const_generics) + } } } } diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 12178196cefab..7e45568725f35 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -2,6 +2,7 @@ use std::fmt; use rustc_macros::HashStable; use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}, subst::SubstsRef}; +use crate::ty::PlaceholderConst; use crate::hir::def_id::DefId; use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate}; @@ -26,6 +27,9 @@ pub enum ConstValue<'tcx> { /// Infer the value of the const. Infer(InferConst<'tcx>), + /// A placeholder const - universally quantified higher-ranked const. + Placeholder(PlaceholderConst), + /// Used only for types with `layout::abi::Scalar` ABI and ZSTs. /// /// Not using the enum `Value` to encode that this must not be `Undef`. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 09fd7f2e79af5..2cdf718c3ac57 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1632,6 +1632,8 @@ pub type PlaceholderRegion = Placeholder; pub type PlaceholderType = Placeholder; +pub type PlaceholderConst = Placeholder; + /// 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 2308d2d68aa726eac33e8a5a43e70ab1b002ed1b Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 12 Mar 2019 20:55:19 +0000 Subject: [PATCH 28/47] Handle `ConstValue::Placeholder` in `canonicalizer` --- src/librustc/infer/canonical/canonicalizer.rs | 12 ++++++++++-- src/librustc/infer/canonical/mod.rs | 13 +++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 22e5767df3339..95310996c1859 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -454,9 +454,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> } return self.canonicalize_const_var( CanonicalVarInfo { - kind: CanonicalVarKind::Const(ui) + kind: CanonicalVarKind::Const(ui), }, - c + c, ); } } @@ -471,6 +471,14 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> return c; } } + ConstValue::Placeholder(placeholder) => { + return self.canonicalize_const_var( + CanonicalVarInfo { + kind: CanonicalVarKind::PlaceholderConst(placeholder), + }, + c, + ); + } _ => {} } } diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 9fad1f47f1372..a5694818b9810 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -414,8 +414,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { CanonicalVarKind::PlaceholderConst( ty::PlaceholderConst { universe, name }, ) => { - let _ = (universe, name); - unimplemented!() // FIXME(const_generics) + let universe_mapped = universe_map(universe); + let placeholder_mapped = ty::PlaceholderConst { + universe: universe_mapped, + name, + }; + self.tcx.mk_lazy_const(ty::LazyConst::Evaluated( + ty::Const { + val: ConstValue::Placeholder(placeholder_mapped), + ty: self.tcx.types.err, // FIXME(const_generics) + } + )).into() } } } From c888af52be46ed87bb14043da02df486288701c6 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 13 Mar 2019 15:19:35 +0000 Subject: [PATCH 29/47] Replace ConstVariableTable with UnificationTable --- src/librustc/infer/combine.rs | 11 +- src/librustc/infer/const_variable.rs | 271 ------------------------ src/librustc/infer/equate.rs | 5 +- src/librustc/infer/freshen.rs | 3 +- src/librustc/infer/fudge.rs | 30 +-- src/librustc/infer/higher_ranked/mod.rs | 22 +- src/librustc/infer/mod.rs | 40 ++-- src/librustc/infer/sub.rs | 5 +- src/librustc/infer/unify_key.rs | 122 ++++++++++- 9 files changed, 181 insertions(+), 328 deletions(-) delete mode 100644 src/librustc/infer/const_variable.rs diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 670c44bef3dbf..7ee762d94ae6c 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -28,7 +28,7 @@ use super::{InferCtxt, MiscVariable, TypeTrace}; use super::lub::Lub; use super::sub::Sub; use super::type_variable::TypeVariableValue; -use super::const_variable::ConstVariableValue; +use super::unify_key::{ConstVarValue, ConstVariableValue, ConstVariableOrigin}; use crate::hir::def_id::DefId; use crate::mir::interpret::ConstValue; @@ -40,7 +40,7 @@ use crate::ty::subst::SubstsRef; use crate::traits::{Obligation, PredicateObligations}; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; #[derive(Clone)] pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { @@ -166,7 +166,10 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { ) -> RelateResult<'tcx, &'tcx LazyConst<'tcx>> { self.const_unification_table .borrow_mut() - .unify_var_value(vid, ConstVariableValue::Known { value }) + .unify_var_value(vid, ConstVarValue { + origin: ConstVariableOrigin::ConstInference(DUMMY_SP), + val: ConstVariableValue::Known { value }, + }) .map_err(|e| const_unification_error(vid_is_expected, e))?; Ok(value) } @@ -590,7 +593,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' .. }) => { let mut variable_table = self.infcx.const_unification_table.borrow_mut(); - match variable_table.probe(*vid).known() { + match variable_table.probe_value(*vid).val.known() { Some(u) => { self.relate(&u, &u) } diff --git a/src/librustc/infer/const_variable.rs b/src/librustc/infer/const_variable.rs deleted file mode 100644 index ac758add872fe..0000000000000 --- a/src/librustc/infer/const_variable.rs +++ /dev/null @@ -1,271 +0,0 @@ -use crate::mir::interpret::ConstValue; -use syntax::symbol::InternedString; -use syntax_pos::Span; -use crate::ty::{self, InferConst}; - -use std::cmp; -use std::marker::PhantomData; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::snapshot_vec as sv; -use rustc_data_structures::unify as ut; - -pub struct ConstVariableTable<'tcx> { - values: sv::SnapshotVec>, - - relations: ut::UnificationTable>>, -} - -/// Reasons to create a const inference variable -#[derive(Copy, Clone, Debug)] -pub enum ConstVariableOrigin { - MiscVariable(Span), - ConstInference(Span), - ConstParameterDefinition(Span, InternedString), - SubstitutionPlaceholder(Span), -} - -pub type ConstVariableMap<'tcx> = FxHashMap, ConstVariableOrigin>; - -struct ConstVariableData { - origin: ConstVariableOrigin, -} - -#[derive(Copy, Clone, Debug)] -pub enum ConstVariableValue<'tcx> { - Known { value: &'tcx ty::LazyConst<'tcx> }, - Unknown { universe: ty::UniverseIndex }, -} - -impl<'tcx> ConstVariableValue<'tcx> { - /// If this value is known, returns the const it is known to be. - /// Otherwise, `None`. - pub fn known(&self) -> Option<&'tcx ty::LazyConst<'tcx>> { - match *self { - ConstVariableValue::Unknown { .. } => None, - ConstVariableValue::Known { value } => Some(value), - } - } - - pub fn is_unknown(&self) -> bool { - match *self { - ConstVariableValue::Unknown { .. } => true, - ConstVariableValue::Known { .. } => false, - } - } -} - -pub struct Snapshot<'tcx> { - snapshot: sv::Snapshot, - relation_snapshot: ut::Snapshot>>, -} - -struct Instantiate<'tcx> { - _vid: ty::ConstVid<'tcx>, -} - -struct Delegate<'tcx> { - pub phantom: PhantomData<&'tcx ()>, -} - -impl<'tcx> ConstVariableTable<'tcx> { - pub fn new() -> ConstVariableTable<'tcx> { - ConstVariableTable { - values: sv::SnapshotVec::new(), - relations: ut::UnificationTable::new(), - } - } - - /// 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::ConstVid<'tcx>) -> &ConstVariableOrigin { - &self.values[vid.index as usize].origin - } - - pub fn unify_var_var( - &mut self, - a_id: ty::ConstVid<'tcx>, - b_id: ty::ConstVid<'tcx>, - ) -> Result<(), (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>)> { - self.relations.unify_var_var(a_id, b_id) - } - - pub fn unify_var_value( - &mut self, - a_id: ty::ConstVid<'tcx>, - b: ConstVariableValue<'tcx>, - ) -> Result<(), (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>)> { - self.relations.unify_var_value(a_id, b) - } - - /// Creates a new const variable. - /// - /// - `origin`: indicates *why* the const variable was created. - /// The code in this module doesn't care, but it can be useful - /// for improving error messages. - pub fn new_var( - &mut self, - universe: ty::UniverseIndex, - origin: ConstVariableOrigin, - ) -> ty::ConstVid<'tcx> { - let vid = self.relations.new_key(ConstVariableValue::Unknown{ universe }); - - let index = self.values.push(ConstVariableData { - origin, - }); - assert_eq!(vid.index, index as u32); - - debug!("new_var(index={:?}, origin={:?}", vid, origin); - - vid - } - - /// Retrieves the type to which `vid` has been instantiated, if - /// any. - pub fn probe( - &mut self, - vid: ty::ConstVid<'tcx> - ) -> ConstVariableValue<'tcx> { - self.relations.probe_value(vid) - } - - /// If `t` is a type-inference variable, and it has been - /// instantiated, then return the with which it was - /// instantiated. Otherwise, returns `t`. - pub fn replace_if_possible( - &mut self, - c: &'tcx ty::LazyConst<'tcx> - ) -> &'tcx ty::LazyConst<'tcx> { - if let ty::LazyConst::Evaluated(ty::Const { - val: ConstValue::Infer(InferConst::Var(vid)), - .. - }) = c { - match self.probe(*vid).known() { - Some(c) => c, - None => c, - } - } else { - c - } - } - - /// 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(), - relation_snapshot: self.relations.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) { - if let sv::UndoLog::NewElem(index) = *action { - debug!("inference variable _#{}t popped", index) - } - } - }); - - let Snapshot { snapshot, relation_snapshot } = s; - self.values.rollback_to(snapshot); - self.relations.rollback_to(relation_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, relation_snapshot } = s; - self.values.commit(snapshot); - self.relations.commit(relation_snapshot); - } - - /// Returns a map `{V1 -> V2}`, where the keys `{V1}` are - /// const-variables created during the snapshot, and the values - /// `{V2}` are the root variables that they were unified with, - /// along with their origin. - pub fn consts_created_since_snapshot( - &mut self, - s: &Snapshot<'tcx> - ) -> ConstVariableMap<'tcx> { - let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); - - actions_since_snapshot - .iter() - .filter_map(|action| match action { - &sv::UndoLog::NewElem(index) => Some(ty::ConstVid { - index: index as u32, - phantom: PhantomData, - }), - _ => None, - }) - .map(|vid| { - let origin = self.values.get(vid.index as usize).origin.clone(); - (vid, origin) - }) - .collect() - } -} - -impl<'tcx> ut::UnifyKey for ty::ConstVid<'tcx> { - type Value = ConstVariableValue<'tcx>; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } } - fn tag() -> &'static str { "ConstVid" } -} - -impl<'tcx> ut::UnifyValue for ConstVariableValue<'tcx> { - type Error = (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>); - - fn unify_values(value1: &Self, value2: &Self) -> Result { - match (value1, value2) { - ( - &ConstVariableValue::Known { value: value1 }, - &ConstVariableValue::Known { value: value2 } - ) => { - match <&'tcx ty::LazyConst<'tcx>>::unify_values(&value1, &value2) { - Ok(value) => Ok(ConstVariableValue::Known { value }), - Err(err) => Err(err), - } - } - - // If one side is known, prefer that one. - (&ConstVariableValue::Known { .. }, &ConstVariableValue::Unknown { .. }) => Ok(*value1), - (&ConstVariableValue::Unknown { .. }, &ConstVariableValue::Known { .. }) => Ok(*value2), - - // If both sides are *unknown*, it hardly matters, does it? - (&ConstVariableValue::Unknown { universe: universe1 }, - &ConstVariableValue::Unknown { universe: universe2 }) => { - // If we unify two unbound variables, ?T and ?U, then whatever - // value they wind up taking (which must be the same value) must - // be nameable by both universes. Therefore, the resulting - // universe is the minimum of the two universes, because that is - // the one which contains the fewest names in scope. - let universe = cmp::min(universe1, universe2); - Ok(ConstVariableValue::Unknown { universe }) - } - } - } -} - -impl<'tcx> ut::EqUnifyValue for &'tcx ty::LazyConst<'tcx> {} - -impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { - type Value = ConstVariableData; - type Undo = Instantiate<'tcx>; - - fn reverse(_values: &mut Vec, _action: Instantiate<'tcx>) { - // We don't actually have to *do* anything to reverse an - // instantiation; the value for a variable is stored in the - // `relations` and hence its rollback code will handle - // it. - } -} diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index e94996a0b99a3..226ab8b438e3f 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -8,6 +8,7 @@ use crate::ty::TyVar; use crate::ty::subst::SubstsRef; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::mir::interpret::ConstValue; +use crate::infer::unify_key::replace_if_possible; /// Ensures `a` is made equal to `b`. Returns `a` on success. pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { @@ -110,8 +111,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> if a == b { return Ok(a); } let infcx = self.fields.infcx; - let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a); - let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b); + let a = replace_if_possible(infcx.const_unification_table.borrow_mut(), a); + let b = replace_if_possible(infcx.const_unification_table.borrow_mut(), b); let a_is_expected = self.a_is_expected(); if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { match (a_eval.val, b_eval.val) { diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index aa1a86361965a..a1de088478871 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -232,7 +232,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ConstValue::Infer(ty::InferConst::Var(v)) => { let opt_ct = self.infcx.const_unification_table .borrow_mut() - .probe(*v) + .probe_value(*v) + .val .known(); return self.freshen_const( opt_ct, diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 5bb007dbb0081..43f4ecfb852bf 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -181,26 +181,16 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> val: ConstValue::Infer(ty::InferConst::Var(vid)), ty, }) = *ct { - match self.const_variables.get(&vid) { - None => { - // This variable was created before the - // "fudging". Since we refresh all - // variables to their binding anyhow, we know - // that it is unbound, so we can just return - // it. - debug_assert!( - self.infcx.const_unification_table.borrow_mut() - .probe(vid) - .is_unknown() - ); - ct - } - Some(&origin) => { - // This variable was created during the - // fudging. Recreate it with a fresh variable - // here. - self.infcx.next_const_var(ty, origin) - } + if self.const_variables.contains(&vid) { + // This variable was created during the + // fudging. Recreate it with a fresh variable + // here. + let origin = self.infcx.const_unification_table.borrow_mut() + .probe_value(vid) + .origin; + self.infcx.next_const_var(ty, origin) + } else { + ct } } else { ct.super_fold_with(self) diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index ec77bb39e7d2a..84ebe2d8b5292 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -4,11 +4,10 @@ use super::combine::CombineFields; use super::{HigherRankedType, InferCtxt, PlaceholderMap}; -use crate::infer::{CombinedSnapshot, ConstVariableOrigin}; +use crate::infer::CombinedSnapshot; use crate::ty::relate::{Relate, RelateResult, TypeRelation}; use crate::ty::{self, Binder, TypeFoldable}; - -use syntax_pos::DUMMY_SP; +use crate::mir::interpret::ConstValue; impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { pub fn higher_ranked_sub( @@ -101,13 +100,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { })) }; - let fld_c = |_: ty::BoundVar, ty| { - self.next_const_var_in_universe( - ty, - // FIXME(const_generics): do we want a placeholder const? - ConstVariableOrigin::MiscVariable(DUMMY_SP), - next_universe, - ) + let fld_c = |bound_var: ty::BoundVar, ty| { + self.tcx.mk_lazy_const(ty::LazyConst::Evaluated( + ty::Const { + val: ConstValue::Placeholder(ty::PlaceholderConst { + universe: next_universe, + name: bound_var, + }), + ty, + } + )) }; let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 80816100faed7..e013b2429e318 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -10,6 +10,7 @@ pub use crate::ty::IntVarValue; use crate::hir; use crate::hir::def_id::DefId; use crate::infer::canonical::{Canonical, CanonicalVarValues}; +use crate::infer::unify_key::{ConstVarValue, ConstVariableValue}; use crate::middle::free_region::RegionRelations; use crate::middle::lang_items; use crate::middle::region; @@ -35,13 +36,12 @@ use syntax_pos::symbol::InternedString; use syntax_pos::Span; use self::combine::CombineFields; -use self::const_variable::ConstVariableOrigin; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; use self::region_constraints::{RegionConstraintCollector, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; -use self::unify_key::ToType; +use self::unify_key::{ToType, ConstVariableOrigin}; pub mod at; pub mod canonical; @@ -62,7 +62,6 @@ pub mod region_constraints; pub mod resolve; mod sub; pub mod type_variable; -pub mod const_variable; pub mod unify_key; #[must_use] @@ -126,7 +125,7 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { pub type_variables: RefCell>, /// Map from const parameter variable to the kind of const it represents. - const_unification_table: RefCell>, + const_unification_table: RefCell>>>, /// Map from integral variable to the kind of integer it represents. int_unification_table: RefCell>>, @@ -532,7 +531,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { in_progress_tables, projection_cache: Default::default(), type_variables: RefCell::new(type_variable::TypeVariableTable::new()), - const_unification_table: RefCell::new(const_variable::ConstVariableTable::new()), + const_unification_table: RefCell::new(ut::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())), @@ -598,7 +597,7 @@ impl<'tcx> InferOk<'tcx, ()> { pub struct CombinedSnapshot<'a, 'tcx: 'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, type_snapshot: type_variable::Snapshot<'tcx>, - const_snapshot: const_variable::Snapshot<'tcx>, + const_snapshot: ut::Snapshot>>, int_snapshot: ut::Snapshot>, float_snapshot: ut::Snapshot>, region_constraints_snapshot: RegionSnapshot, @@ -1017,14 +1016,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ) -> &'tcx ty::LazyConst<'tcx> { let vid = self.const_unification_table .borrow_mut() - .new_var(universe, origin); + .new_key(ConstVarValue { + origin, + val: ConstVariableValue::Unknown { universe }, + }); self.tcx.mk_const_var(vid, ty) } pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { self.const_unification_table .borrow_mut() - .new_var(self.universe(), origin) + .new_key(ConstVarValue { + origin, + val: ConstVariableValue::Unknown { universe: self.universe() }, + }) } fn next_int_var_id(&self) -> IntVid { @@ -1120,13 +1125,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_ty_var(ty_var_id).into() } GenericParamDefKind::Const { .. } => { + let origin = ConstVariableOrigin::ConstParameterDefinition(span, param.name); let const_var_id = self.const_unification_table .borrow_mut() - .new_var( - self.universe(), - ConstVariableOrigin::ConstParameterDefinition(span, param.name), - ); + .new_key(ConstVarValue { + origin, + val: ConstVariableValue::Unknown { universe: self.universe() }, + }); self.tcx.mk_const_var(const_var_id, self.tcx.type_of(param.def_id)).into() } } @@ -1362,9 +1368,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &self, vid: ty::ConstVid<'tcx> ) -> Result<&'tcx ty::LazyConst<'tcx>, ty::UniverseIndex> { - use self::const_variable::ConstVariableValue; + use self::unify_key::ConstVariableValue; - match self.const_unification_table.borrow_mut().probe(vid) { + match self.const_unification_table.borrow_mut().probe_value(vid).val { ConstVariableValue::Known { value } => Ok(value), ConstVariableValue::Unknown { universe } => Err(universe), } @@ -1380,7 +1386,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) = ct { self.const_unification_table .borrow_mut() - .probe(*v) + .probe_value(*v) + .val .known() .map(|c| self.resolve_const_var(c)) .unwrap_or(ct) @@ -1400,7 +1407,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) => { self.const_unification_table .borrow_mut() - .probe(*vid) + .probe_value(*vid) + .val .known() .map(|c| self.shallow_resolve_const(c)) .unwrap_or(ct) diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index b285d59729110..1b34403f05339 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -6,6 +6,7 @@ use crate::ty::{self, Ty, TyCtxt, InferConst}; use crate::ty::TyVar; use crate::ty::fold::TypeFoldable; use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; +use crate::infer::unify_key::replace_if_possible; use crate::mir::interpret::ConstValue; use std::mem; @@ -143,8 +144,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> if a == b { return Ok(a); } let infcx = self.fields.infcx; - let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a); - let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b); + let a = replace_if_possible(infcx.const_unification_table.borrow_mut(), a); + let b = replace_if_possible(infcx.const_unification_table.borrow_mut(), b); // Consts can only be equal or unequal to each other: there's no subtyping // relation, so we're just going to perform equating here instead. diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index 208c553aa327f..5cd0e8e25912e 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -1,5 +1,13 @@ -use crate::ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt}; -use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue}; +use crate::ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt, InferConst}; +use crate::mir::interpret::ConstValue; +use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue, UnificationTable}; +use rustc_data_structures::unify::InPlace; +use syntax_pos::{Span, DUMMY_SP}; +use syntax::symbol::InternedString; + +use std::cmp; +use std::marker::PhantomData; +use std::cell::RefMut; pub trait ToType { fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>; @@ -68,3 +76,113 @@ impl ToType for FloatVarValue { tcx.mk_mach_float(self.0) } } + +// Generic consts. + +/// Reasons to create a const inference variable +#[derive(Copy, Clone, Debug)] +pub enum ConstVariableOrigin { + MiscVariable(Span), + ConstInference(Span), + ConstParameterDefinition(Span, InternedString), + SubstitutionPlaceholder(Span), +} + +#[derive(Copy, Clone, Debug)] +pub enum ConstVariableValue<'tcx> { + Known { value: &'tcx ty::LazyConst<'tcx> }, + Unknown { universe: ty::UniverseIndex }, +} + +impl<'tcx> ConstVariableValue<'tcx> { + /// If this value is known, returns the const it is known to be. + /// Otherwise, `None`. + pub fn known(&self) -> Option<&'tcx ty::LazyConst<'tcx>> { + match *self { + ConstVariableValue::Unknown { .. } => None, + ConstVariableValue::Known { value } => Some(value), + } + } + + pub fn is_unknown(&self) -> bool { + match *self { + ConstVariableValue::Unknown { .. } => true, + ConstVariableValue::Known { .. } => false, + } + } +} + +#[derive(Copy, Clone, Debug)] +pub struct ConstVarValue<'tcx> { + pub origin: ConstVariableOrigin, + pub val: ConstVariableValue<'tcx>, +} + +impl<'tcx> UnifyKey for ty::ConstVid<'tcx> { + type Value = ConstVarValue<'tcx>; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } } + fn tag() -> &'static str { "ConstVid" } +} + +impl<'tcx> UnifyValue for ConstVarValue<'tcx> { + type Error = (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>); + + fn unify_values(value1: &Self, value2: &Self) -> Result { + let val = match (value1.val, value2.val) { + ( + ConstVariableValue::Known { value: value1 }, + ConstVariableValue::Known { value: value2 } + ) => { + match <&'tcx ty::LazyConst<'tcx>>::unify_values(&value1, &value2) { + Ok(value) => Ok(ConstVariableValue::Known { value }), + Err(err) => Err(err), + } + } + + // If one side is known, prefer that one. + (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { + Ok(value1.val) + } + (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { + Ok(value2.val) + } + + // If both sides are *unknown*, it hardly matters, does it? + (ConstVariableValue::Unknown { universe: universe1 }, + ConstVariableValue::Unknown { universe: universe2 }) => { + // If we unify two unbound variables, ?T and ?U, then whatever + // value they wind up taking (which must be the same value) must + // be nameable by both universes. Therefore, the resulting + // universe is the minimum of the two universes, because that is + // the one which contains the fewest names in scope. + let universe = cmp::min(universe1, universe2); + Ok(ConstVariableValue::Unknown { universe }) + } + }?; + + Ok(ConstVarValue { + origin: ConstVariableOrigin::ConstInference(DUMMY_SP), + val, + }) + } +} + +impl<'tcx> EqUnifyValue for &'tcx ty::LazyConst<'tcx> {} + +pub fn replace_if_possible( + mut table: RefMut<'_, UnificationTable>>>, + c: &'tcx ty::LazyConst<'tcx> +) -> &'tcx ty::LazyConst<'tcx> { + if let ty::LazyConst::Evaluated(ty::Const { + val: ConstValue::Infer(InferConst::Var(vid)), + .. + }) = c { + match table.probe_value(*vid).val.known() { + Some(c) => c, + None => c, + } + } else { + c + } +} From fc16b0a1476bdd1aa8fafd69dc841b5f539bc94e Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 18 Mar 2019 20:55:19 +0000 Subject: [PATCH 30/47] Fix rebase from LazyConst removal --- src/librustc/infer/canonical/canonicalizer.rs | 106 +++++++++--------- src/librustc/infer/canonical/mod.rs | 16 +-- .../infer/canonical/query_response.rs | 4 +- src/librustc/infer/combine.rs | 69 ++++++------ src/librustc/infer/equate.rs | 49 ++++---- src/librustc/infer/freshen.rs | 73 ++++++------ src/librustc/infer/fudge.rs | 7 +- src/librustc/infer/glb.rs | 6 +- src/librustc/infer/higher_ranked/mod.rs | 4 +- src/librustc/infer/lub.rs | 6 +- src/librustc/infer/mod.rs | 24 ++-- src/librustc/infer/nll_relate/mod.rs | 22 ++-- src/librustc/infer/resolve.rs | 23 ++-- src/librustc/infer/sub.rs | 48 ++++---- src/librustc/infer/unify_key.rs | 19 ++-- src/librustc/ty/_match.rs | 24 ++-- src/librustc/ty/context.rs | 8 +- src/librustc/ty/error.rs | 2 +- src/librustc/ty/fold.rs | 32 +++--- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/print/pretty.rs | 4 +- src/librustc/ty/relate.rs | 106 +++++++++--------- .../chalk_context/resolvent_ops.rs | 18 +-- src/librustc_typeck/check/writeback.rs | 54 +++++---- 24 files changed, 337 insertions(+), 389 deletions(-) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 95310996c1859..1bf1163c4abcb 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -15,6 +15,7 @@ use std::sync::atomic::Ordering; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::subst::Kind; use crate::ty::{self, BoundVar, InferConst, Lift, List, Ty, TyCtxt, TypeFlags}; +use crate::ty::flags::FlagComputation; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; @@ -434,59 +435,58 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> } } - fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - if let ty::LazyConst::Evaluated(ct) = c { - match ct.val { - ConstValue::Infer(InferConst::Var(vid)) => { - debug!("canonical: const var found with vid {:?}", vid); - match self.infcx.unwrap().probe_const_var(vid) { - Ok(c) => { - debug!("(resolved to {:?})", c); - return self.fold_const(c); - } + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + match ct.val { + ConstValue::Infer(InferConst::Var(vid)) => { + debug!("canonical: const var found with vid {:?}", vid); + match self.infcx.unwrap().probe_const_var(vid) { + Ok(c) => { + debug!("(resolved to {:?})", c); + return self.fold_const(c); + } - // `ConstVar(vid)` is unresolved, track its universe index in the - // canonicalized result - Err(mut ui) => { - if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk { - // FIXME: perf problem described in #55921. - ui = ty::UniverseIndex::ROOT; - } - return self.canonicalize_const_var( - CanonicalVarInfo { - kind: CanonicalVarKind::Const(ui), - }, - c, - ); + // `ConstVar(vid)` is unresolved, track its universe index in the + // canonicalized result + Err(mut ui) => { + if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk { + // FIXME: perf problem described in #55921. + ui = ty::UniverseIndex::ROOT; } + return self.canonicalize_const_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Const(ui), + }, + ct, + ); } } - ConstValue::Infer(InferConst::Fresh(_)) => { - bug!("encountered a fresh const during canonicalization") - } - ConstValue::Infer(InferConst::Canonical(debruijn, _)) => { - if debruijn >= self.binder_index { - bug!("escaping bound type during canonicalization") - } else { - return c; - } - } - ConstValue::Placeholder(placeholder) => { - return self.canonicalize_const_var( - CanonicalVarInfo { - kind: CanonicalVarKind::PlaceholderConst(placeholder), - }, - c, - ); + } + ConstValue::Infer(InferConst::Fresh(_)) => { + bug!("encountered a fresh const during canonicalization") + } + ConstValue::Infer(InferConst::Canonical(debruijn, _)) => { + if debruijn >= self.binder_index { + bug!("escaping bound type during canonicalization") + } else { + return ct; } - _ => {} } + ConstValue::Placeholder(placeholder) => { + return self.canonicalize_const_var( + CanonicalVarInfo { + kind: CanonicalVarKind::PlaceholderConst(placeholder), + }, + ct, + ); + } + _ => {} } - if c.type_flags().intersects(self.needs_canonical_flags) { - c.super_fold_with(self) + let flags = FlagComputation::for_const(ct); + if flags.intersects(self.needs_canonical_flags) { + ct.super_fold_with(self) } else { - c + ct } } } @@ -700,25 +700,19 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { fn canonicalize_const_var( &mut self, info: CanonicalVarInfo, - const_var: &'tcx ty::LazyConst<'tcx> - ) -> &'tcx ty::LazyConst<'tcx> { + const_var: &'tcx ty::Const<'tcx> + ) -> &'tcx ty::Const<'tcx> { let infcx = self.infcx.expect("encountered const-var without infcx"); let bound_to = infcx.resolve_const_var(const_var); if bound_to != const_var { self.fold_const(bound_to) } else { - let ty = match const_var { - ty::LazyConst::Unevaluated(def_id, _) => { - self.tcx.type_of(*def_id) - } - ty::LazyConst::Evaluated(ty::Const { ty, .. }) => ty, - }; let var = self.canonical_var(info, const_var.into()); - self.tcx().mk_lazy_const( - ty::LazyConst::Evaluated(ty::Const { + self.tcx().mk_const( + ty::Const { val: ConstValue::Infer(InferConst::Canonical(self.binder_index, var.into())), - ty, - }) + ty: const_var.ty, + } ) } } diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index a5694818b9810..7c61db21e613a 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -419,12 +419,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { universe: universe_mapped, name, }; - self.tcx.mk_lazy_const(ty::LazyConst::Evaluated( + self.tcx.mk_const( ty::Const { val: ConstValue::Placeholder(placeholder_mapped), ty: self.tcx.types.err, // FIXME(const_generics) } - )).into() + ).into() } } } @@ -482,18 +482,12 @@ impl<'tcx> CanonicalVarValues<'tcx> { ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i)) ).into(), UnpackedKind::Const(ct) => { - let ty = match ct { - ty::LazyConst::Unevaluated(def_id, _) => { - tcx.type_of(*def_id) - } - ty::LazyConst::Evaluated(ty::Const { ty, .. }) => ty, - }; - tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const { - ty: ty, + tcx.mk_const(ty::Const { + ty: ct.ty, val: ConstValue::Infer( InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from_u32(i)) ), - })).into() + }).into() } }) .collect() diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 65c579aedf2f4..8225ed70c5827 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -481,10 +481,10 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { } } UnpackedKind::Const(result_value) => { - if let ty::LazyConst::Evaluated(ty::Const { + if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(debrujin, b)), .. - }) = result_value { + } = result_value { // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. // We only allow a `ty::INNERMOST` index in substitutions. diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 7ee762d94ae6c..048c0a7a8fd0a 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -33,7 +33,7 @@ use super::unify_key::{ConstVarValue, ConstVariableValue, ConstVariableOrigin}; use crate::hir::def_id::DefId; use crate::mir::interpret::ConstValue; use crate::ty::{IntType, UintType}; -use crate::ty::{self, Ty, TyCtxt, InferConst, LazyConst}; +use crate::ty::{self, Ty, TyCtxt, InferConst}; use crate::ty::error::TypeError; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::ty::subst::SubstsRef; @@ -118,41 +118,39 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { pub fn super_combine_consts( &self, relation: &mut R, - a: &'tcx LazyConst<'tcx>, - b: &'tcx LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx LazyConst<'tcx>> + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> where R: TypeRelation<'infcx, 'gcx, 'tcx>, { let a_is_expected = relation.a_is_expected(); - if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { - match (a_eval.val, b_eval.val) { - (ConstValue::Infer(InferConst::Var(a_vid)), - ConstValue::Infer(InferConst::Var(b_vid))) => { - self.const_unification_table - .borrow_mut() - .unify_var_var(a_vid, b_vid) - .map_err(|e| const_unification_error(a_is_expected, e))?; - return Ok(a); - } - - // All other cases of inference with other variables are errors. - (ConstValue::Infer(InferConst::Var(_)), ConstValue::Infer(_)) | - (ConstValue::Infer(_), ConstValue::Infer(InferConst::Var(_))) => { - bug!("tried to combine ConstValue::Infer/ConstValue::Infer(InferConst::Var)") - } + match (a.val, b.val) { + (ConstValue::Infer(InferConst::Var(a_vid)), + ConstValue::Infer(InferConst::Var(b_vid))) => { + self.const_unification_table + .borrow_mut() + .unify_var_var(a_vid, b_vid) + .map_err(|e| const_unification_error(a_is_expected, e))?; + return Ok(a); + } - (ConstValue::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(a_is_expected, vid, b); - } + // All other cases of inference with other variables are errors. + (ConstValue::Infer(InferConst::Var(_)), ConstValue::Infer(_)) | + (ConstValue::Infer(_), ConstValue::Infer(InferConst::Var(_))) => { + bug!("tried to combine ConstValue::Infer/ConstValue::Infer(InferConst::Var)") + } - (_, ConstValue::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(!a_is_expected, vid, a); - } + (ConstValue::Infer(InferConst::Var(vid)), _) => { + return self.unify_const_variable(a_is_expected, vid, b); + } - _ => {} + (_, ConstValue::Infer(InferConst::Var(vid))) => { + return self.unify_const_variable(!a_is_expected, vid, a); } + + _ => {} } ty::relate::super_relate_consts(relation, a, b) @@ -162,8 +160,8 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { &self, vid_is_expected: bool, vid: ty::ConstVid<'tcx>, - value: &'tcx LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx LazyConst<'tcx>> { + value: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { self.const_unification_table .borrow_mut() .unify_var_value(vid, ConstVarValue { @@ -582,16 +580,13 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' fn consts( &mut self, - c: &'tcx ty::LazyConst<'tcx>, - c2: &'tcx ty::LazyConst<'tcx> - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + c: &'tcx ty::Const<'tcx>, + c2: &'tcx ty::Const<'tcx> + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == match c { - LazyConst::Evaluated(ty::Const { - val: ConstValue::Infer(InferConst::Var(vid)), - .. - }) => { + ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } => { let mut variable_table = self.infcx.const_unification_table.borrow_mut(); match variable_table.probe_value(*vid).val.known() { Some(u) => { @@ -628,7 +623,7 @@ impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'t pub fn const_unification_error<'tcx>( a_is_expected: bool, - (a, b): (&'tcx LazyConst<'tcx>, &'tcx LazyConst<'tcx>), + (a, b): (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>), ) -> TypeError<'tcx> { TypeError::ConstMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 226ab8b438e3f..f61408696ecbf 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -104,9 +104,9 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { debug!("{}.consts({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); } @@ -114,29 +114,28 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let a = replace_if_possible(infcx.const_unification_table.borrow_mut(), a); let b = replace_if_possible(infcx.const_unification_table.borrow_mut(), b); let a_is_expected = self.a_is_expected(); - if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { - match (a_eval.val, b_eval.val) { - (ConstValue::Infer(InferConst::Var(a_vid)), - ConstValue::Infer(InferConst::Var(b_vid))) => { - infcx.const_unification_table - .borrow_mut() - .unify_var_var(a_vid, b_vid) - .map_err(|e| const_unification_error(a_is_expected, e))?; - return Ok(a); - } - - (ConstValue::Infer(InferConst::Var(a_id)), _) => { - self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?; - return Ok(a); - } - - (_, ConstValue::Infer(InferConst::Var(b_id))) => { - self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?; - return Ok(a); - } - - _ => {} + + match (a.val, b.val) { + (ConstValue::Infer(InferConst::Var(a_vid)), + ConstValue::Infer(InferConst::Var(b_vid))) => { + infcx.const_unification_table + .borrow_mut() + .unify_var_var(a_vid, b_vid) + .map_err(|e| const_unification_error(a_is_expected, e))?; + return Ok(a); + } + + (ConstValue::Infer(InferConst::Var(a_id)), _) => { + self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?; + return Ok(a); } + + (_, ConstValue::Infer(InferConst::Var(b_id))) => { + self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?; + return Ok(a); + } + + _ => {} } self.fields.infcx.super_combine_consts(self, a, b)?; diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index a1de088478871..679635bef13e5 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -46,7 +46,7 @@ pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ty_freshen_count: u32, const_freshen_count: u32, ty_freshen_map: FxHashMap>, - const_freshen_map: FxHashMap, &'tcx ty::LazyConst<'tcx>>, + const_freshen_map: FxHashMap, &'tcx ty::Const<'tcx>>, } impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { @@ -88,11 +88,11 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { fn freshen_const( &mut self, - opt_ct: Option<&'tcx ty::LazyConst<'tcx>>, + opt_ct: Option<&'tcx ty::Const<'tcx>>, key: ty::InferConst<'tcx>, freshener: F, ty: Ty<'tcx>, - ) -> &'tcx ty::LazyConst<'tcx> + ) -> &'tcx ty::Const<'tcx> where F: FnOnce(u32) -> ty::InferConst<'tcx>, { @@ -226,44 +226,43 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - if let ty::LazyConst::Evaluated(ty::Const{ val, ty }) = ct { - match val { - ConstValue::Infer(ty::InferConst::Var(v)) => { - let opt_ct = self.infcx.const_unification_table - .borrow_mut() - .probe_value(*v) - .val - .known(); - return self.freshen_const( - opt_ct, - ty::InferConst::Var(*v), - ty::InferConst::Fresh, - ty, + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + match ct.val { + ConstValue::Infer(ty::InferConst::Var(v)) => { + let opt_ct = self.infcx.const_unification_table + .borrow_mut() + .probe_value(v) + .val + .known(); + return self.freshen_const( + opt_ct, + ty::InferConst::Var(v), + ty::InferConst::Fresh, + ct.ty, + ); + } + ConstValue::Infer(ty::InferConst::Fresh(i)) => { + if i >= self.const_freshen_count { + bug!( + "Encountered a freshend const with id {} \ + but our counter is only at {}", + i, + self.const_freshen_count, ); } - ConstValue::Infer(ty::InferConst::Fresh(i)) => { - if *i >= self.const_freshen_count { - bug!( - "Encountered a freshend const with id {} \ - but our counter is only at {}", - i, - self.const_freshen_count, - ); - } - return ct; - } - - ConstValue::Infer(ty::InferConst::Canonical(..)) | - ConstValue::Placeholder(_) => { - bug!("unexpected const {:?}", ct) - } + return ct; + } - ConstValue::Param(_) | - ConstValue::Scalar(_) | - ConstValue::Slice(..) | - ConstValue::ByRef(..) => {} + ConstValue::Infer(ty::InferConst::Canonical(..)) | + ConstValue::Placeholder(_) => { + bug!("unexpected const {:?}", ct) } + + ConstValue::Param(_) | + ConstValue::Scalar(_) | + ConstValue::Slice(..) | + ConstValue::ByRef(..) | + ConstValue::Unevaluated(..) => {} } ct.super_fold_with(self) diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 43f4ecfb852bf..5a9ba64659edc 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -176,11 +176,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> r } - fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - if let ty::LazyConst::Evaluated(ty::Const { - val: ConstValue::Infer(ty::InferConst::Var(vid)), - ty, - }) = *ct { + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + if let ty::Const { val: ConstValue::Infer(ty::InferConst::Var(vid)), ty } = *ct { if self.const_variables.contains(&vid) { // This variable was created during the // fudging. Recreate it with a fresh variable diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index dde43d2072271..63a8f17398a04 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -62,9 +62,9 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { debug!("{}.consts({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 84ebe2d8b5292..fcec820cbb92a 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; let fld_c = |bound_var: ty::BoundVar, ty| { - self.tcx.mk_lazy_const(ty::LazyConst::Evaluated( + self.tcx.mk_const( ty::Const { val: ConstValue::Placeholder(ty::PlaceholderConst { universe: next_universe, @@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }), ty, } - )) + ) }; let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c); diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 2a06886d94b68..29b319ef8f5ff 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -62,9 +62,9 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { debug!("{}.consts({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e013b2429e318..0f603a6c77785 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1004,7 +1004,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &self, ty: Ty<'tcx>, origin: ConstVariableOrigin - ) -> &'tcx ty::LazyConst<'tcx> { + ) -> &'tcx ty::Const<'tcx> { self.tcx.mk_const_var(self.next_const_var_id(origin), ty) } @@ -1013,7 +1013,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty: Ty<'tcx>, origin: ConstVariableOrigin, universe: ty::UniverseIndex, - ) -> &'tcx ty::LazyConst<'tcx> { + ) -> &'tcx ty::Const<'tcx> { let vid = self.const_unification_table .borrow_mut() .new_key(ConstVarValue { @@ -1367,7 +1367,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn probe_const_var( &self, vid: ty::ConstVid<'tcx> - ) -> Result<&'tcx ty::LazyConst<'tcx>, ty::UniverseIndex> { + ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> { use self::unify_key::ConstVariableValue; match self.const_unification_table.borrow_mut().probe_value(vid).val { @@ -1378,12 +1378,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn resolve_const_var( &self, - ct: &'tcx ty::LazyConst<'tcx> - ) -> &'tcx ty::LazyConst<'tcx> { - if let ty::LazyConst::Evaluated(ty::Const { - val: ConstValue::Infer(InferConst::Var(v)), - .. - }) = ct { + ct: &'tcx ty::Const<'tcx> + ) -> &'tcx ty::Const<'tcx> { + if let ty::Const { val: ConstValue::Infer(InferConst::Var(v)), .. } = ct { self.const_unification_table .borrow_mut() .probe_value(*v) @@ -1398,13 +1395,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn shallow_resolve_const( &self, - ct: &'tcx ty::LazyConst<'tcx> - ) -> &'tcx ty::LazyConst<'tcx> { + ct: &'tcx ty::Const<'tcx> + ) -> &'tcx ty::Const<'tcx> { match ct { - ty::LazyConst::Evaluated(ty::Const { - val: ConstValue::Infer(InferConst::Var(vid)), - .. - }) => { + ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } => { self.const_unification_table .borrow_mut() .probe_value(*vid) diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index 91a1e0a13bc2f..8d3a86a8dc329 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -610,13 +610,10 @@ where fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { - if let ty::LazyConst::Evaluated(ty::Const { - val: ConstValue::Infer(InferConst::Canonical(_, _)), - .. - }) = a { + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(_, _)), .. } = a { // FIXME(const_generics): I'm unsure how this branch should actually be handled, // so this is probably not correct. self.infcx.super_combine_consts(self, a, b) @@ -983,15 +980,12 @@ where fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - _: &'tcx ty::LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + a: &'tcx ty::Const<'tcx>, + _: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { debug!("TypeGeneralizer::consts(a={:?})", a); - if let ty::LazyConst::Evaluated(ty::Const { - val: ConstValue::Infer(InferConst::Canonical(_, _)), - .. - }) = a { + if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(_, _)), .. } = a { bug!( "unexpected inference variable encountered in NLL generalization: {:?}", a diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 30a398de19ae7..831ed302147ed 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv } } - fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { if !ct.needs_infer() { ct // micro-optimize -- if there is nothing in this const that this fold affects... } else { @@ -210,25 +210,20 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> } } - fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { if !c.needs_infer() && !ty::keep_local(&c) { c // micro-optimize -- if there is nothing in this const that this fold affects... // ^ we need to have the `keep_local` check to un-default // defaulted tuples. } else { let c = self.infcx.shallow_resolve_const(c); - match c { - ty::LazyConst::Evaluated(ty::Const { val, .. }) => { - match val { - ConstValue::Infer(InferConst::Var(vid)) => { - self.err = Some(FixupError::UnresolvedConst(*vid)); - return self.tcx().types.ct_err; - } - ConstValue::Infer(InferConst::Fresh(_)) => { - bug!("Unexpected const in full const resolver: {:?}", c); - } - _ => {} - } + match c.val { + ConstValue::Infer(InferConst::Var(vid)) => { + self.err = Some(FixupError::UnresolvedConst(vid)); + return self.tcx().types.ct_err; + } + ConstValue::Infer(InferConst::Fresh(_)) => { + bug!("Unexpected const in full const resolver: {:?}", c); } _ => {} } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 1b34403f05339..f2f36d59cbef6 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -137,9 +137,9 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { debug!("{}.consts({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); } @@ -150,29 +150,27 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> // Consts can only be equal or unequal to each other: there's no subtyping // relation, so we're just going to perform equating here instead. let a_is_expected = self.a_is_expected(); - if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { - match (a_eval.val, b_eval.val) { - (ConstValue::Infer(InferConst::Var(a_vid)), - ConstValue::Infer(InferConst::Var(b_vid))) => { - infcx.const_unification_table - .borrow_mut() - .unify_var_var(a_vid, b_vid) - .map_err(|e| const_unification_error(a_is_expected, e))?; - return Ok(a); - } - - (ConstValue::Infer(InferConst::Var(a_id)), _) => { - self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?; - return Ok(a); - } - - (_, ConstValue::Infer(InferConst::Var(b_id))) => { - self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?; - return Ok(a); - } - - _ => {} + match (a.val, b.val) { + (ConstValue::Infer(InferConst::Var(a_vid)), + ConstValue::Infer(InferConst::Var(b_vid))) => { + infcx.const_unification_table + .borrow_mut() + .unify_var_var(a_vid, b_vid) + .map_err(|e| const_unification_error(a_is_expected, e))?; + return Ok(a); } + + (ConstValue::Infer(InferConst::Var(a_id)), _) => { + self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?; + return Ok(a); + } + + (_, ConstValue::Infer(InferConst::Var(b_id))) => { + self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?; + return Ok(a); + } + + _ => {} } self.fields.infcx.super_combine_consts(self, a, b)?; diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index 5cd0e8e25912e..9b1b423ef5059 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -90,14 +90,14 @@ pub enum ConstVariableOrigin { #[derive(Copy, Clone, Debug)] pub enum ConstVariableValue<'tcx> { - Known { value: &'tcx ty::LazyConst<'tcx> }, + Known { value: &'tcx ty::Const<'tcx> }, Unknown { universe: ty::UniverseIndex }, } impl<'tcx> ConstVariableValue<'tcx> { /// If this value is known, returns the const it is known to be. /// Otherwise, `None`. - pub fn known(&self) -> Option<&'tcx ty::LazyConst<'tcx>> { + pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> { match *self { ConstVariableValue::Unknown { .. } => None, ConstVariableValue::Known { value } => Some(value), @@ -126,7 +126,7 @@ impl<'tcx> UnifyKey for ty::ConstVid<'tcx> { } impl<'tcx> UnifyValue for ConstVarValue<'tcx> { - type Error = (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>); + type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>); fn unify_values(value1: &Self, value2: &Self) -> Result { let val = match (value1.val, value2.val) { @@ -134,7 +134,7 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { ConstVariableValue::Known { value: value1 }, ConstVariableValue::Known { value: value2 } ) => { - match <&'tcx ty::LazyConst<'tcx>>::unify_values(&value1, &value2) { + match <&'tcx ty::Const<'tcx>>::unify_values(&value1, &value2) { Ok(value) => Ok(ConstVariableValue::Known { value }), Err(err) => Err(err), } @@ -168,16 +168,13 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { } } -impl<'tcx> EqUnifyValue for &'tcx ty::LazyConst<'tcx> {} +impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {} pub fn replace_if_possible( mut table: RefMut<'_, UnificationTable>>>, - c: &'tcx ty::LazyConst<'tcx> -) -> &'tcx ty::LazyConst<'tcx> { - if let ty::LazyConst::Evaluated(ty::Const { - val: ConstValue::Infer(InferConst::Var(vid)), - .. - }) = c { + c: &'tcx ty::Const<'tcx> +) -> &'tcx ty::Const<'tcx> { + if let ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } = c { match table.probe_value(*vid).val.known() { Some(c) => c, None => c, diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index 82e802dc16407..8640216b071ae 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -81,26 +81,24 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> { fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { debug!("{}.consts({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); } - if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) { - match (a_eval.val, b_eval.val) { - (_, ConstValue::Infer(InferConst::Fresh(_))) => { - return Ok(a); - } - - (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { - return Err(TypeError::ConstMismatch(relate::expected_found(self, &a, &b))); - } + match (a.val, b.val) { + (_, ConstValue::Infer(InferConst::Fresh(_))) => { + return Ok(a); + } - _ => {} + (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { + return Err(TypeError::ConstMismatch(relate::expected_found(self, &a, &b))); } + + _ => {} } relate::super_relate_consts(self, a, b) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ef94008811afd..e7b6a0ff4f4b5 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -232,7 +232,7 @@ pub struct CommonLifetimes<'tcx> { pub re_static: Region<'tcx>, pub re_erased: Region<'tcx>, - pub ct_err: &'tcx LazyConst<'tcx>, + pub ct_err: &'tcx Const<'tcx>, } pub struct LocalTableInContext<'a, V: 'a> { @@ -2683,11 +2683,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self, ic: InferConst<'tcx>, ty: Ty<'tcx>, - ) -> &'tcx LazyConst<'tcx> { - self.mk_lazy_const(LazyConst::Evaluated(ty::Const { + ) -> &'tcx ty::Const<'tcx> { + self.mk_const(ty::Const { val: ConstValue::Infer(ic), ty, - })) + }) } #[inline] diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 6a6708df5cb2e..4e4024d5bab43 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -45,7 +45,7 @@ pub enum TypeError<'tcx> { ProjectionBoundsLength(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), - ConstMismatch(ExpectedFound<&'tcx ty::LazyConst<'tcx>>), + ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 5d3c71f3eabb9..dbf9047f775bf 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -201,7 +201,7 @@ pub trait TypeVisitor<'tcx> : Sized { pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G, H> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, - H: FnMut(&'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx>, + H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>, { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, pub ty_op: F, @@ -212,7 +212,7 @@ pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G, H> impl<'a, 'gcx, 'tcx, F, G, H> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G, H> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, - H: FnMut(&'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx>, + H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>, { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } @@ -226,7 +226,7 @@ impl<'a, 'gcx, 'tcx, F, G, H> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx (self.lt_op)(r) } - fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { let ct = ct.super_fold_with(self); (self.ct_op)(ct) } @@ -435,7 +435,7 @@ struct BoundVarReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), - fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx> + 'a), + fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a), } impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> { @@ -447,7 +447,7 @@ impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> { ) -> Self where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, - H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx>, + H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, { BoundVarReplacer { tcx, @@ -515,11 +515,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> } } - fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - if let ty::LazyConst::Evaluated(ty::Const { + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + if let ty::Const { val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)), ty, - }) = *ct { + } = *ct { if debruijn == self.current_index { let fld_c = &mut self.fld_c; let ct = fld_c(bound_const, ty); @@ -582,7 +582,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ) -> (T, BTreeMap>) where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, - H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx>, + H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { use rustc_data_structures::fx::FxHashMap; @@ -629,7 +629,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ) -> (T, BTreeMap>) where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, - H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx>, + H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx> { self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) @@ -794,11 +794,11 @@ impl TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - if let ty::LazyConst::Evaluated(ty::Const { + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + if let ty::Const { val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)), ty, - }) = *ct { + } = *ct { if self.amount == 0 || debruijn < self.current_index { ct } else { @@ -908,11 +908,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { r.bound_at_or_above_binder(self.outer_index) } - fn visit_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> bool { - if let ty::LazyConst::Evaluated(ty::Const { + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool { + if let ty::Const { val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)), .. - }) = *ct { + } = *ct { debruijn >= self.outer_index } else { false diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2cdf718c3ac57..36da21b71f536 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -96,6 +96,7 @@ mod constness; pub mod error; mod erase_regions; pub mod fast_reject; +pub mod flags; pub mod fold; pub mod inhabitedness; pub mod layout; @@ -112,7 +113,6 @@ pub mod wf; pub mod util; mod context; -mod flags; mod instance; mod structural_impls; mod sty; diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index e5803b7be4f63..d2cc251453610 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -712,7 +712,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: // in order to place the projections inside the `<...>`. if !resugared { // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx().mk_infer(ty::FreshTy(0)); + let dummy_self = self.tcx().mk_ty_infer(ty::FreshTy(0)); let principal = principal.with_self_ty(self.tcx(), dummy_self); let args = self.generic_args_to_print( @@ -1481,7 +1481,7 @@ define_print_and_forward_display! { ty::ExistentialTraitRef<'tcx> { // Use a type that can't appear in defaults of type parameters. - let dummy_self = cx.tcx().mk_infer(ty::FreshTy(0)); + let dummy_self = cx.tcx().mk_ty_infer(ty::FreshTy(0)); let trait_ref = self.with_self_ty(cx.tcx(), dummy_self); p!(print(trait_ref)) } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index e60edfeba1c27..1ba5a67f7364d 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -7,7 +7,7 @@ use crate::hir::def_id::DefId; use crate::ty::subst::{Kind, UnpackedKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; -use crate::ty::error::{ExpectedFound, TypeError, ConstError}; +use crate::ty::error::{ExpectedFound, TypeError}; use crate::mir::interpret::{GlobalId, ConstValue, Scalar}; use crate::util::common::ErrorReported; use syntax_pos::DUMMY_SP; @@ -86,9 +86,9 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx> - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>>; + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx> + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>; fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> @@ -124,7 +124,7 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> { ast::Mutability::MutMutable => ty::Invariant, }; let ty = relation.relate_with_variance(variance, &a.ty, &b.ty)?; - Ok(ty::TypeAndMut {ty: ty, mutbl: mutbl}) + Ok(ty::TypeAndMut { ty, mutbl }) } } } @@ -590,59 +590,55 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, /// it. pub fn super_relate_consts<'a, 'gcx, 'tcx, R>( relation: &mut R, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx> -) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx> +) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { + // Only consts whose types are equal should be compared. + assert_eq!(a.ty, b.ty); + let tcx = relation.tcx(); - match (a, b) { - (ty::LazyConst::Evaluated(a_eval), ty::LazyConst::Evaluated(b_eval)) => { - // Only consts whose types are equal should be compared. - assert_eq!(a_eval.ty, b_eval.ty); - - // Currently, the values that can be unified are those that - // implement both `PartialEq` and `Eq`, corresponding to - // `structural_match` types. - // FIXME(const_generics): check for `structural_match` synthetic attribute. - match (a_eval.val, b_eval.val) { - (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) - } - (ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => { - Ok(a) - } - (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => { - Ok(a) - } - (ConstValue::Scalar(Scalar::Bits { .. }), _) if a == b => { - Ok(a) - } - (ConstValue::ByRef(..), _) => { - bug!( - "non-Scalar ConstValue encountered in super_relate_consts {:?} {:?}", - a, - b, - ); - } - _ => { - Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) - } - } + // Currently, the values that can be unified are those that + // implement both `PartialEq` and `Eq`, corresponding to + // `structural_match` types. + // FIXME(const_generics): check for `structural_match` synthetic attribute. + match (a.val, b.val) { + (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { + // The caller should handle these cases! + bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) } - // FIXME(const_generics): this is probably wrong (regarding TyProjection) - ( - ty::LazyConst::Unevaluated(a_def_id, a_substs), - ty::LazyConst::Unevaluated(b_def_id, b_substs), - ) if a_def_id == b_def_id => { - let substs = - relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?; - Ok(tcx.mk_lazy_const(ty::LazyConst::Unevaluated(*a_def_id, substs))) + (ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => { + Ok(a) + } + (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => { + Ok(a) + } + (ConstValue::Scalar(Scalar::Bits { .. }), _) if a == b => { + Ok(a) } - _ => { + (ConstValue::ByRef(..), _) => { + bug!( + "non-Scalar ConstValue encountered in super_relate_consts {:?} {:?}", + a, + b, + ); + } + + // FIXME(const_generics): this is wrong, as it is a projection + (ConstValue::Unevaluated(a_def_id, a_substs), + ConstValue::Unevaluated(b_def_id, b_substs)) if a_def_id == b_def_id => { + let substs = + relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?; + Ok(tcx.mk_const(ty::Const { + val: ConstValue::Unevaluated(a_def_id, &substs), + ty: a.ty, + }) + } + + _ => { Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) } } @@ -719,11 +715,11 @@ impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { } } -impl<'tcx> Relate<'tcx> for &'tcx ty::LazyConst<'tcx> { +impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> { fn relate<'a, 'gcx, R>(relation: &mut R, - a: &&'tcx ty::LazyConst<'tcx>, - b: &&'tcx ty::LazyConst<'tcx>) - -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> + a: &&'tcx ty::Const<'tcx>, + b: &&'tcx ty::Const<'tcx>) + -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { relation.consts(*a, *b) diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs index 7fc0530875406..6bc62364b43fd 100644 --- a/src/librustc_traits/chalk_context/resolvent_ops.rs +++ b/src/librustc_traits/chalk_context/resolvent_ops.rs @@ -279,13 +279,13 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { fn consts( &mut self, - a: &'tcx ty::LazyConst<'tcx>, - b: &'tcx ty::LazyConst<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> { - if let ty::LazyConst::Evaluated(ty::Const { + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)), .. - }) = a { + } = a { if *debruijn == self.binder_index { self.unify_free_answer_var(*bound_ct, b.into())?; return Ok(b); @@ -294,14 +294,14 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { match (a, b) { ( - ty::LazyConst::Evaluated(ty::Const { + ty::Const { val: ConstValue::Infer(InferConst::Canonical(a_debruijn, a_bound)), .. - }), - ty::LazyConst::Evaluated(ty::Const { + }, + ty::Const { val: ConstValue::Infer(InferConst::Canonical(b_debruijn, b_bound)), .. - }), + }, ) => { assert_eq!(a_debruijn, b_debruijn); assert_eq!(a_bound, b_bound); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index d16d69e923326..f56ef1a0d0c4e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -11,7 +11,7 @@ use rustc::infer::InferCtxt; use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; use rustc::ty::subst::UnpackedKind; -use rustc::ty::{self, Ty, TyCtxt, Const, LazyConst}; +use rustc::ty::{self, Ty, TyCtxt, Const}; use rustc::mir::interpret::ConstValue; use rustc::util::nodemap::DefIdSet; use rustc_data_structures::sync::Lrc; @@ -567,36 +567,34 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { }, ct_op: |ct| { trace!("checking const {:?}", ct); - // find a const parameter - if let LazyConst::Evaluated(Const { ty, val }) = ct { - if let ConstValue::Param(..) = val { - // look it up in the substitution list - assert_eq!(opaque_defn.substs.len(), generics.params.len()); - for (subst, param) in opaque_defn.substs.iter() - .zip(&generics.params) { - if let UnpackedKind::Const(subst) = subst.unpack() { - if subst == ct { - // found it in the substitution list, replace with the - // parameter from the existential type - return self.tcx() - .global_tcx() - .mk_const_param(param.index, param.name, ty); - } + // Find a const parameter + if let ConstValue::Param(..) = ct.val { + // look it up in the substitution list + assert_eq!(opaque_defn.substs.len(), generics.params.len()); + for (subst, param) in opaque_defn.substs.iter() + .zip(&generics.params) { + if let UnpackedKind::Const(subst) = subst.unpack() { + if subst == ct { + // found it in the substitution list, replace with the + // parameter from the existential type + return self.tcx() + .global_tcx() + .mk_const_param(param.index, param.name, ty); } } - self.tcx() - .sess - .struct_span_err( - span, - &format!( - "const parameter `{}` is part of concrete type but not \ - used in parameter list for existential type", - ct, - ), - ) - .emit(); - return self.tcx().types.ct_err; } + self.tcx() + .sess + .struct_span_err( + span, + &format!( + "const parameter `{}` is part of concrete type but not \ + used in parameter list for existential type", + ct, + ), + ) + .emit(); + return self.tcx().types.ct_err; } ct } From d8b9387ace8331ce1a61d496c8f3251ac1de6928 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 18 Mar 2019 21:00:52 +0000 Subject: [PATCH 31/47] Take ConstValue::Placeholder into account in new locations --- src/librustc/ty/structural_impls.rs | 4 +++- src/librustc_typeck/check/writeback.rs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 3057c529ddfd4..504b939c5f2d6 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1355,6 +1355,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { // FIXME(const_generics): implement TypeFoldable for InferConst ConstValue::Infer(ic) => ConstValue::Infer(ic), ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)), + ConstValue::Placeholder(p) => ConstValue::Placeholder(p), ConstValue::Scalar(a) => ConstValue::Scalar(a), ConstValue::Slice(a, b) => ConstValue::Slice(a, b), ConstValue::Unevaluated(did, substs) @@ -1366,8 +1367,9 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { match *self { ConstValue::ByRef(..) => false, // FIXME(const_generics): implement TypeFoldable for InferConst - ConstValue::Infer(_ic) => false, + ConstValue::Infer(_) => false, ConstValue::Param(p) => p.visit_with(visitor), + ConstValue::Placeholder(_) => false, ConstValue::Scalar(_) => false, ConstValue::Slice(..) => false, ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor), diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f56ef1a0d0c4e..5d98cb568bdaf 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -11,7 +11,7 @@ use rustc::infer::InferCtxt; use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; use rustc::ty::subst::UnpackedKind; -use rustc::ty::{self, Ty, TyCtxt, Const}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::interpret::ConstValue; use rustc::util::nodemap::DefIdSet; use rustc_data_structures::sync::Lrc; @@ -579,7 +579,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // parameter from the existential type return self.tcx() .global_tcx() - .mk_const_param(param.index, param.name, ty); + .mk_const_param(param.index, param.name, ct.ty); } } } From f2416936620f86a8c520a6128aaa461fc5b88c7c Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 18 Mar 2019 21:40:45 +0000 Subject: [PATCH 32/47] Fix missing parenthesis --- src/librustc/ty/relate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 1ba5a67f7364d..d9e224b364800 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -635,7 +635,7 @@ where Ok(tcx.mk_const(ty::Const { val: ConstValue::Unevaluated(a_def_id, &substs), ty: a.ty, - }) + })) } _ => { From 972e25410651e31a9458a4a47cc739ecd446f35a Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 27 Mar 2019 17:50:49 +0000 Subject: [PATCH 33/47] Implement const generics for `InferenceFudger` --- src/librustc/infer/fudge.rs | 45 ++++++++++++++++++++-------- src/librustc/infer/nll_relate/mod.rs | 1 + 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 5a9ba64659edc..5f5a2d4a489e3 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -1,13 +1,27 @@ -use crate::ty::{self, Ty, TyCtxt, TyVid, IntVid, FloatVid, RegionVid}; +use crate::ty::{self, Ty, TyCtxt, TyVid, IntVid, FloatVid, RegionVid, ConstVid}; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::mir::interpret::ConstValue; use super::InferCtxt; -use super::RegionVariableOrigin; +use super::{RegionVariableOrigin, ConstVariableOrigin}; use super::type_variable::TypeVariableOrigin; +use rustc_data_structures::unify as ut; +use ut::UnifyKey; + +use std::cell::RefMut; use std::ops::Range; +fn const_vars_since_snapshot<'tcx>( + mut table: RefMut<'_, ut::UnificationTable>>>, + snapshot: &ut::Snapshot>>, +) -> (Range>, Vec) { + let range = table.vars_since_snapshot(snapshot); + (range.start..range.end, (range.start.index..range.end.index).map(|index| { + table.probe_value(ConstVid::from_index(index)).origin.clone() + }).collect()) +} + impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// This rather funky routine is used while processing expected /// types. What happens here is that we want to propagate a @@ -80,6 +94,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let region_vars = self.borrow_region_constraints().vars_since_snapshot( &snapshot.region_constraints_snapshot, ); + let const_vars = const_vars_since_snapshot( + self.const_unification_table.borrow_mut(), + &snapshot.const_snapshot, + ); let fudger = InferenceFudger { infcx: self, @@ -87,6 +105,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_vars, float_vars, region_vars, + const_vars, }; Ok((fudger, value)) @@ -105,7 +124,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if fudger.type_vars.0.is_empty() && fudger.int_vars.is_empty() && fudger.float_vars.is_empty() && - fudger.region_vars.0.is_empty() { + fudger.region_vars.0.is_empty() && + fudger.const_vars.0.is_empty() { Ok(value) } else { Ok(value.fold_with(&mut fudger)) @@ -119,6 +139,7 @@ pub struct InferenceFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { int_vars: Range, float_vars: Range, region_vars: (Range, Vec), + const_vars: (Range>, Vec), } impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> { @@ -166,9 +187,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReVar(vid) = r { + if let ty::ReVar(vid) = *r { if self.region_vars.0.contains(&vid) { - let idx = (vid.index() - self.region_vars.0.start.index()) as usize; + let idx = vid.index() - self.region_vars.0.start.index(); let origin = self.region_vars.1[idx]; return self.infcx.next_region_var(origin); } @@ -177,14 +198,12 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ConstValue::Infer(ty::InferConst::Var(vid)), ty } = *ct { - if self.const_variables.contains(&vid) { - // This variable was created during the - // fudging. Recreate it with a fresh variable - // here. - let origin = self.infcx.const_unification_table.borrow_mut() - .probe_value(vid) - .origin; + if let ty::Const { val: ConstValue::Infer(ty::InferConst::Var(vid)), ty } = ct { + if self.const_vars.0.contains(&vid) { + // This variable was created during the fudging. + // Recreate it with a fresh variable here. + let idx = (vid.index - self.const_vars.0.start.index) as usize; + let origin = self.const_vars.1[idx]; self.infcx.next_const_var(ty, origin) } else { ct diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index 8d3a86a8dc329..f4f5c868e2c8d 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -28,6 +28,7 @@ use crate::ty::fold::{TypeFoldable, TypeVisitor}; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::ty::subst::Kind; use crate::ty::{self, Ty, TyCtxt, InferConst}; +use crate::mir::interpret::ConstValue; use rustc_data_structures::fx::FxHashMap; use std::fmt::Debug; From 5cf45bc27abd8169ea0fd3629000028c10a7aa1a Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 17 Apr 2019 19:18:12 +0100 Subject: [PATCH 34/47] Fix rebase issue --- src/librustc/infer/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 0f603a6c77785..0d09644a3101f 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1368,8 +1368,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &self, vid: ty::ConstVid<'tcx> ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> { - use self::unify_key::ConstVariableValue; - match self.const_unification_table.borrow_mut().probe_value(vid).val { ConstVariableValue::Known { value } => Ok(value), ConstVariableValue::Unknown { universe } => Err(universe), From 67176f751b03404112cc7f9e25ea3081d834f144 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 17 Apr 2019 19:31:04 +0100 Subject: [PATCH 35/47] Add `const-types` test --- src/test/ui/const-generics/const-types.rs | 16 ++++++++++++++++ src/test/ui/const-generics/const-types.stderr | 6 ++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/const-generics/const-types.rs create mode 100644 src/test/ui/const-generics/const-types.stderr diff --git a/src/test/ui/const-generics/const-types.rs b/src/test/ui/const-generics/const-types.rs new file mode 100644 index 0000000000000..11757cd588dab --- /dev/null +++ b/src/test/ui/const-generics/const-types.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +#[allow(dead_code)] + +struct ConstArray { + array: [T; LEN], +} + +fn main() { + let arr = ConstArray:: { + array: [0; 8], + }; +} diff --git a/src/test/ui/const-generics/const-types.stderr b/src/test/ui/const-generics/const-types.stderr new file mode 100644 index 0000000000000..fbf5d53754164 --- /dev/null +++ b/src/test/ui/const-generics/const-types.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-types.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + From 97c0c6653bb3ff77e4810311b5011842ade56916 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 17 Apr 2019 22:48:57 +0100 Subject: [PATCH 36/47] Remove spurious assertion --- src/librustc/ty/relate.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index d9e224b364800..d7b1907074195 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -596,9 +596,6 @@ pub fn super_relate_consts<'a, 'gcx, 'tcx, R>( where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - // Only consts whose types are equal should be compared. - assert_eq!(a.ty, b.ty); - let tcx = relation.tcx(); // Currently, the values that can be unified are those that From b872e6358549f6627fac1fa7028a547042152806 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 17 Apr 2019 22:53:23 +0100 Subject: [PATCH 37/47] Fix known-known const unification case --- src/librustc/infer/unify_key.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index 9b1b423ef5059..d238f848d9fa9 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -134,10 +134,7 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { ConstVariableValue::Known { value: value1 }, ConstVariableValue::Known { value: value2 } ) => { - match <&'tcx ty::Const<'tcx>>::unify_values(&value1, &value2) { - Ok(value) => Ok(ConstVariableValue::Known { value }), - Err(err) => Err(err), - } + bug!("equating two const variables, both of which have known values") } // If one side is known, prefer that one. From d8b1ddba9b132c4853b4e7af8e4e906e7a0d37b2 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 17 Apr 2019 23:14:32 +0100 Subject: [PATCH 38/47] Fix unused variable warning --- src/librustc/infer/unify_key.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index d238f848d9fa9..678a45a84e9ea 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -131,8 +131,8 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { fn unify_values(value1: &Self, value2: &Self) -> Result { let val = match (value1.val, value2.val) { ( - ConstVariableValue::Known { value: value1 }, - ConstVariableValue::Known { value: value2 } + ConstVariableValue::Known { .. }, + ConstVariableValue::Known { .. } ) => { bug!("equating two const variables, both of which have known values") } From 388f823c03f539308695b06bbeb3a16bf11243e5 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 22 Apr 2019 23:07:09 +0100 Subject: [PATCH 39/47] Correct name of constrained_generic_params alias --- src/librustc_typeck/collect.rs | 6 +++--- src/librustc_typeck/impl_wf_check.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 894a1c82e876f..9c8b5ac58e337 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -15,7 +15,7 @@ //! crate as a kind of pass. This should eventually be factored away. use crate::astconv::{AstConv, Bounds}; -use crate::constrained_generic_params as ctp; +use crate::constrained_generic_params as cgp; use crate::check::intrinsic::intrisic_operation_unsafety; use crate::lint; use crate::middle::lang_items::SizedTraitLangItem; @@ -2202,11 +2202,11 @@ fn explicit_predicates_of<'a, 'tcx>( { let self_ty = tcx.type_of(def_id); let trait_ref = tcx.impl_trait_ref(def_id); - ctp::setup_constraining_predicates( + cgp::setup_constraining_predicates( tcx, &mut predicates, trait_ref, - &mut ctp::parameters_for_impl(self_ty, trait_ref), + &mut cgp::parameters_for_impl(self_ty, trait_ref), ); } diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 2b72f43d36f72..e7ec5bc81c769 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -8,7 +8,7 @@ //! specialization errors. These things can (and probably should) be //! fixed, but for the moment it's easier to do these checks early. -use crate::constrained_generic_params as ctp; +use crate::constrained_generic_params as cgp; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::def_id::DefId; @@ -102,8 +102,8 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref); - ctp::identify_constrained_generic_params( + let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref); + cgp::identify_constrained_generic_params( tcx, &impl_predicates, impl_trait_ref, &mut input_parameters); // Disallow unconstrained lifetimes, but only if they appear in assoc types. @@ -114,7 +114,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item.kind == ty::AssociatedKind::Type && item.defaultness.has_value() }) .flat_map(|def_id| { - ctp::parameters_for(&tcx.type_of(def_id), true) + cgp::parameters_for(&tcx.type_of(def_id), true) }).collect(); for param in &impl_generics.params { @@ -122,7 +122,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Disallow ANY unconstrained type parameters. ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); - if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { + if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { report_unused_parameter(tcx, tcx.def_span(param.def_id), "type", @@ -130,7 +130,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } ty::GenericParamDefKind::Lifetime => { - let param_lt = ctp::Parameter::from(param.to_early_bound_region_data()); + let param_lt = cgp::Parameter::from(param.to_early_bound_region_data()); if lifetimes_in_associated_types.contains(¶m_lt) && // (*) !input_parameters.contains(¶m_lt) { report_unused_parameter(tcx, @@ -141,7 +141,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } ty::GenericParamDefKind::Const => { let param_ct = ty::ParamConst::for_def(param); - if !input_parameters.contains(&ctp::Parameter::from(param_ct)) { + if !input_parameters.contains(&cgp::Parameter::from(param_ct)) { report_unused_parameter(tcx, tcx.def_span(param.def_id), "const", From beb2f84b31efc5cb852f485672d3059acb706a88 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 22 Apr 2019 23:15:52 +0100 Subject: [PATCH 40/47] Resolve FIXME in probe.rs --- src/librustc_typeck/check/method/probe.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 5a420c3661594..a35777873abdf 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -21,6 +21,7 @@ use rustc::traits::query::method_autoderef::{MethodAutoderefBadTy}; use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; use rustc::ty::GenericParamDefKind; use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::infer::unify_key::ConstVariableOrigin; use rustc::util::nodemap::FxHashSet; use rustc::infer::{self, InferOk}; use rustc::infer::canonical::{Canonical, QueryResponse}; @@ -1572,7 +1573,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.tcx.def_span(def_id))).into() } GenericParamDefKind::Const { .. } => { - unimplemented!() // FIXME(const_generics) + let span = self.tcx.def_span(def_id); + let origin = ConstVariableOrigin::SubstitutionPlaceholder(span); + self.next_const_var(self.tcx.type_of(param.def_id), origin).into() } } }) From a29eca5d82d36bdbda5cccf317b9c0b3e33ed23d Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 23 Apr 2019 00:03:00 +0100 Subject: [PATCH 41/47] Fix issue with const params in operand.rs --- src/librustc_mir/interpret/operand.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index df6d4568ab3e2..ed7c316e3da75 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -524,7 +524,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> layout: Option>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { let op = match val.val { - ConstValue::Param(_) | ConstValue::Infer(_) | ConstValue::Placeholder(_) => bug!(), + ConstValue::Param(_) => return err!(TooGeneric), + ConstValue::Infer(_) | ConstValue::Placeholder(_) => bug!(), ConstValue::ByRef(ptr, alloc) => { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen -- and for `static mut`, we copy on demand anyway. From c7deb5bdc2dead50d728c71a18095f088398b7db Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 23 Apr 2019 00:03:14 +0100 Subject: [PATCH 42/47] Add a test for const arguments --- src/test/ui/const-generics/const-arg-in-fn.rs | 13 +++++++++++++ src/test/ui/const-generics/const-arg-in-fn.stderr | 6 ++++++ 2 files changed, 19 insertions(+) create mode 100644 src/test/ui/const-generics/const-arg-in-fn.rs create mode 100644 src/test/ui/const-generics/const-arg-in-fn.stderr diff --git a/src/test/ui/const-generics/const-arg-in-fn.rs b/src/test/ui/const-generics/const-arg-in-fn.rs new file mode 100644 index 0000000000000..3f86782838ca1 --- /dev/null +++ b/src/test/ui/const-generics/const-arg-in-fn.rs @@ -0,0 +1,13 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn const_u32_identity() -> u32 { + X +} + + fn main() { + let val = const_u32_identity::<18>(); + assert_eq!(val, 18); +} diff --git a/src/test/ui/const-generics/const-arg-in-fn.stderr b/src/test/ui/const-generics/const-arg-in-fn.stderr new file mode 100644 index 0000000000000..e32b714b25d36 --- /dev/null +++ b/src/test/ui/const-generics/const-arg-in-fn.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-arg-in-fn.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + From 16d6ee39523bbaa1fd38808cab30f284ce3f30f8 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 23 Apr 2019 13:18:11 +0100 Subject: [PATCH 43/47] Fold const in writeback --- src/librustc_typeck/check/writeback.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 5d98cb568bdaf..e13651d253d89 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -853,6 +853,21 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { self.infcx.fully_resolve(&r).unwrap_or(self.tcx.lifetimes.re_static) } + + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + match self.infcx.fully_resolve(&ct) { + Ok(ct) => ct, + Err(_) => { + debug!( + "Resolver::fold_const: input const `{:?}` not fully resolvable", + ct + ); + // FIXME: we'd like to use `self.report_error`, but it doesn't yet + // accept a &'tcx ty::Const. + self.tcx().types.ct_err + } + } + } } /////////////////////////////////////////////////////////////////////////// From a188850dedeab85df9b11222f25afc59aeb3bb94 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 23 Apr 2019 13:20:04 +0100 Subject: [PATCH 44/47] Add a test for incorrect numbers of const args --- .../incorrect-number-of-const-args.rs | 11 ++++++++++ .../incorrect-number-of-const-args.stderr | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/ui/const-generics/incorrect-number-of-const-args.rs create mode 100644 src/test/ui/const-generics/incorrect-number-of-const-args.stderr diff --git a/src/test/ui/const-generics/incorrect-number-of-const-args.rs b/src/test/ui/const-generics/incorrect-number-of-const-args.rs new file mode 100644 index 0000000000000..7059e9d8348e3 --- /dev/null +++ b/src/test/ui/const-generics/incorrect-number-of-const-args.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn foo() -> usize { + 0 +} + +fn main() { + foo::<0>(); //~ ERROR wrong number of const arguments: expected 2, found 1 + foo::<0, 0, 0>(); //~ ERROR wrong number of const arguments: expected 2, found 3 +} diff --git a/src/test/ui/const-generics/incorrect-number-of-const-args.stderr b/src/test/ui/const-generics/incorrect-number-of-const-args.stderr new file mode 100644 index 0000000000000..11727733eb533 --- /dev/null +++ b/src/test/ui/const-generics/incorrect-number-of-const-args.stderr @@ -0,0 +1,21 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/incorrect-number-of-const-args.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0107]: wrong number of const arguments: expected 2, found 1 + --> $DIR/incorrect-number-of-const-args.rs:9:5 + | +LL | foo::<0>(); + | ^^^^^^^^ expected 2 const arguments + +error[E0107]: wrong number of const arguments: expected 2, found 3 + --> $DIR/incorrect-number-of-const-args.rs:10:17 + | +LL | foo::<0, 0, 0>(); + | ^ unexpected const argument + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. From 1369132afae1e9721828370b37de7baca221a6b6 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 23 Apr 2019 13:20:22 +0100 Subject: [PATCH 45/47] Add a test for const args that cannot be inferred Co-Authored-By: Gabriel Smith --- .../ui/const-generics/cannot-infer-const-args.rs | 10 ++++++++++ .../const-generics/cannot-infer-const-args.stderr | 15 +++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/ui/const-generics/cannot-infer-const-args.rs create mode 100644 src/test/ui/const-generics/cannot-infer-const-args.stderr diff --git a/src/test/ui/const-generics/cannot-infer-const-args.rs b/src/test/ui/const-generics/cannot-infer-const-args.rs new file mode 100644 index 0000000000000..e1061c6d1a33d --- /dev/null +++ b/src/test/ui/const-generics/cannot-infer-const-args.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn foo() -> usize { + 0 +} + +fn main() { + foo(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr new file mode 100644 index 0000000000000..5528c2fca6a3b --- /dev/null +++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr @@ -0,0 +1,15 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/cannot-infer-const-args.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0282]: type annotations needed + --> $DIR/cannot-infer-const-args.rs:9:5 + | +LL | foo(); + | ^^^ cannot infer type for `fn() -> usize {foo::<_>}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. From 541de81f8e44053ab76ff5f03e3d36bde4b2457c Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 30 Apr 2019 22:27:33 +0100 Subject: [PATCH 46/47] Create ShallowResolver Co-Authored-By: Gabriel Smith --- src/librustc/infer/canonical/canonicalizer.rs | 2 +- src/librustc/infer/mod.rs | 156 ++++++++++-------- src/librustc/infer/nll_relate/mod.rs | 4 +- src/librustc/infer/resolve.rs | 14 +- src/librustc/traits/fulfill.rs | 8 +- src/librustc/traits/project.rs | 6 +- src/librustc/traits/select.rs | 20 +-- src/librustc/ty/wf.rs | 2 +- .../chalk_context/resolvent_ops.rs | 2 +- src/librustc_typeck/check/_match.rs | 4 +- src/librustc_typeck/check/coercion.rs | 14 +- src/librustc_typeck/check/mod.rs | 4 +- 12 files changed, 128 insertions(+), 108 deletions(-) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 1bf1163c4abcb..0e9dbcac5cd64 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -684,7 +684,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { /// `ty_var`. fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.infcx.expect("encountered ty-var without infcx"); - let bound_to = infcx.shallow_resolve_type(ty_var); + let bound_to = infcx.shallow_resolve(ty_var); if bound_to != ty_var { self.fold_ty(bound_to) } else { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 0d09644a3101f..65bc2b3e945ce 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -18,7 +18,7 @@ use crate::mir::interpret::ConstValue; use crate::session::config::BorrowckMode; use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use crate::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use crate::ty::fold::TypeFoldable; +use crate::ty::fold::{TypeFolder, TypeFoldable}; use crate::ty::relate::RelateResult; use crate::ty::subst::{Kind, InternalSubsts, SubstsRef}; use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, CtxtInterners, InferConst}; @@ -919,17 +919,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { predicate: &ty::PolySubtypePredicate<'tcx>, ) -> Option> { // Subtle: it's ok to skip the binder here and resolve because - // `shallow_resolve_type` just ignores anything that is not a type + // `shallow_resolve` just ignores anything that is not a type // variable, and because type variable's can't (at present, at // least) capture any of the things bound by this binder. // // Really, there is no *particular* reason to do this - // `shallow_resolve_type` here except as a + // `shallow_resolve` here except as a // micro-optimization. Naturally I could not // resist. -nmatsakis let two_unbound_type_vars = { - let a = self.shallow_resolve_type(predicate.skip_binder().a); - let b = self.shallow_resolve_type(predicate.skip_binder().b); + let a = self.shallow_resolve(predicate.skip_binder().a); + let b = self.shallow_resolve(predicate.skip_binder().b); a.is_ty_var() && b.is_ty_var() }; @@ -1274,46 +1274,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.resolve_type_vars_if_possible(t).to_string() } - // We have this force-inlined variant of `shallow_resolve_type` for the one - // callsite that is extremely hot. All other callsites use the normal - // variant. - #[inline(always)] - pub fn inlined_shallow_resolve_type(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match typ.sty { - ty::Infer(ty::TyVar(v)) => { - // Not entirely obvious: if `typ` is a type variable, - // it can be resolved to an int/float variable, which - // can then be recursively resolved, hence the - // recursion. Note though that we prevent type - // variables from unifyxing to other type variables - // directly (though they may be embedded - // structurally), and we prevent cycles in any case, - // so this recursion should always be of very limited - // depth. - self.type_variables - .borrow_mut() - .probe(v) - .known() - .map(|t| self.shallow_resolve_type(t)) - .unwrap_or(typ) - } - - ty::Infer(ty::IntVar(v)) => self.int_unification_table - .borrow_mut() - .probe_value(v) - .map(|v| v.to_type(self.tcx)) - .unwrap_or(typ), - - ty::Infer(ty::FloatVar(v)) => self.float_unification_table - .borrow_mut() - .probe_value(v) - .map(|v| v.to_type(self.tcx)) - .unwrap_or(typ), - - _ => typ, - } - } - /// If `TyVar(vid)` resolves to a type, return that type. Else, return the /// universe index of `TyVar(vid)`. pub fn probe_ty_var(&self, vid: TyVid) -> Result, ty::UniverseIndex> { @@ -1325,8 +1285,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn shallow_resolve_type(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - self.inlined_shallow_resolve_type(typ) + pub fn shallow_resolve(&self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + let mut r = ShallowResolver::new(self); + value.fold_with(&mut r) } pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { @@ -1391,24 +1355,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn shallow_resolve_const( - &self, - ct: &'tcx ty::Const<'tcx> - ) -> &'tcx ty::Const<'tcx> { - match ct { - ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } => { - self.const_unification_table - .borrow_mut() - .probe_value(*vid) - .val - .known() - .map(|c| self.shallow_resolve_const(c)) - .unwrap_or(ct) - } - _ => ct, - } - } - pub fn fully_resolve>(&self, value: &T) -> FixupResult<'tcx, T> { /*! * Attempts to resolve all type/region/const variables in @@ -1528,7 +1474,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { closure_substs: ty::ClosureSubsts<'tcx>, ) -> Option { let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx); - let closure_kind_ty = self.shallow_resolve_type(&closure_kind_ty); + let closure_kind_ty = self.shallow_resolve(closure_kind_ty); closure_kind_ty.to_opt_closure_kind() } @@ -1542,7 +1488,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { substs: ty::ClosureSubsts<'tcx>, ) -> ty::PolyFnSig<'tcx> { let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx); - let closure_sig_ty = self.shallow_resolve_type(&closure_sig_ty); + let closure_sig_ty = self.shallow_resolve(closure_sig_ty); closure_sig_ty.fn_sig(self.tcx) } @@ -1598,6 +1544,82 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } +pub struct ShallowResolver<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, +} + +impl<'a, 'gcx, 'tcx> ShallowResolver<'a, 'gcx, 'tcx> { + #[inline(always)] + pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { + ShallowResolver { infcx } + } + + // We have this force-inlined variant of `shallow_resolve` for the one + // callsite that is extremely hot. All other callsites use the normal + // variant. + #[inline(always)] + pub fn inlined_shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { + match typ.sty { + ty::Infer(ty::TyVar(v)) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifyxing to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. + self.infcx.type_variables + .borrow_mut() + .probe(v) + .known() + .map(|t| self.fold_ty(t)) + .unwrap_or(typ) + } + + ty::Infer(ty::IntVar(v)) => self.infcx.int_unification_table + .borrow_mut() + .probe_value(v) + .map(|v| v.to_type(self.infcx.tcx)) + .unwrap_or(typ), + + ty::Infer(ty::FloatVar(v)) => self.infcx.float_unification_table + .borrow_mut() + .probe_value(v) + .map(|v| v.to_type(self.infcx.tcx)) + .unwrap_or(typ), + + _ => typ, + } + } +} + +impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ShallowResolver<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.inlined_shallow_resolve(ty) + } + + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + match ct { + ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } => { + self.infcx.const_unification_table + .borrow_mut() + .probe_value(*vid) + .val + .known() + .map(|c| self.fold_const(c)) + .unwrap_or(ct) + } + _ => ct, + } + } +} + impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { pub fn span(&self) -> Span { self.cause.span diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index f4f5c868e2c8d..a3800d8f0754e 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -538,10 +538,10 @@ where } fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let a = self.infcx.shallow_resolve_type(a); + let a = self.infcx.shallow_resolve(a); if !D::forbid_inference_vars() { - b = self.infcx.shallow_resolve_type(b); + b = self.infcx.shallow_resolve(b); } match (&a.sty, &b.sty) { diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 831ed302147ed..61563a8ba269d 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -8,7 +8,7 @@ use crate::ty::fold::{TypeFolder, TypeVisitor}; /// The opportunistic type resolver can be used at any time. It simply replaces /// type variables that have been unified with the things they have -/// been unified with (similar to `shallow_resolve_type`, but deep). This is +/// been unified with (similar to `shallow_resolve`, but deep). This is /// useful for printing messages etc but also required at various /// points for correctness. pub struct OpportunisticTypeResolver<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { @@ -31,7 +31,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeResolver<'a, 'g if !t.has_infer_types() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { - let t0 = self.infcx.shallow_resolve_type(t); + let t0 = self.infcx.shallow_resolve(t); t0.super_fold_with(self) } } @@ -59,7 +59,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv if !t.needs_infer() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { - let t0 = self.infcx.shallow_resolve_type(t); + let t0 = self.infcx.shallow_resolve(t); t0.super_fold_with(self) } } @@ -78,7 +78,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv if !ct.needs_infer() { ct // micro-optimize -- if there is nothing in this const that this fold affects... } else { - let c0 = self.infcx.shallow_resolve_const(ct); + let c0 = self.infcx.shallow_resolve(ct); c0.super_fold_with(self) } } @@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> UnresolvedTypeFinder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'gcx, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - let t = self.infcx.shallow_resolve_type(t); + let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { if let ty::Infer(infer_ty) = t.sty { // Since we called `shallow_resolve` above, this must @@ -175,7 +175,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> // ^ we need to have the `keep_local` check to un-default // defaulted tuples. } else { - let t = self.infcx.shallow_resolve_type(t); + let t = self.infcx.shallow_resolve(t); match t.sty { ty::Infer(ty::TyVar(vid)) => { self.err = Some(FixupError::UnresolvedTy(vid)); @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> // ^ we need to have the `keep_local` check to un-default // defaulted tuples. } else { - let c = self.infcx.shallow_resolve_const(c); + let c = self.infcx.shallow_resolve(c); match c.val { ConstValue::Infer(InferConst::Var(vid)) => { self.err = Some(FixupError::UnresolvedConst(vid)); diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 59a9fd11e1d57..96212d829d448 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -1,4 +1,4 @@ -use crate::infer::InferCtxt; +use crate::infer::{InferCtxt, ShallowResolver}; use crate::mir::interpret::{GlobalId, ErrorHandled}; use crate::ty::{self, Ty, TypeFoldable, ToPolyTraitRef}; use crate::ty::error::ExpectedFound; @@ -255,9 +255,9 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, // doing more work yet if !pending_obligation.stalled_on.is_empty() { if pending_obligation.stalled_on.iter().all(|&ty| { - // Use the force-inlined variant of shallow_resolve_type() because this code is hot. - let resolved_ty = self.selcx.infcx().inlined_shallow_resolve_type(&ty); - resolved_ty == ty // nothing changed here + // Use the force-inlined variant of shallow_resolve() because this code is hot. + let resolved = ShallowResolver::new(self.selcx.infcx()).inlined_shallow_resolve(ty); + resolved == ty // nothing changed here }) { debug!("process_predicate: pending obligation {:?} still stalled on {:?}", self.selcx.infcx() diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 763fa40d8f3bb..dabb8a728901c 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1229,7 +1229,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( -> Progress<'tcx> { let self_ty = obligation_trait_ref.self_ty(); - let object_ty = selcx.infcx().shallow_resolve_type(self_ty); + let object_ty = selcx.infcx().shallow_resolve(self_ty); debug!("confirm_object_candidate(object_ty={:?})", object_ty); let data = match object_ty.sty { @@ -1346,7 +1346,7 @@ fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>) -> Progress<'tcx> { - let fn_type = selcx.infcx().shallow_resolve_type(fn_pointer_vtable.fn_ty); + let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); let sig = fn_type.fn_sig(selcx.tcx()); let Normalized { value: sig, @@ -1371,7 +1371,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>( let tcx = selcx.tcx(); let infcx = selcx.infcx(); let closure_sig_ty = vtable.substs.closure_sig_ty(vtable.closure_def_id, tcx); - let closure_sig = infcx.shallow_resolve_type(&closure_sig_ty).fn_sig(tcx); + let closure_sig = infcx.shallow_resolve(closure_sig_ty).fn_sig(tcx); let Normalized { value: closure_sig, obligations diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 18ac30b7f1eb2..f0c402789c4cd 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2403,7 +2403,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // NOTE: binder moved to (*) let self_ty = self.infcx - .shallow_resolve_type(obligation.predicate.skip_binder().self_ty()); + .shallow_resolve(obligation.predicate.skip_binder().self_ty()); match self_ty.sty { ty::Infer(ty::IntVar(_)) @@ -2467,7 +2467,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ) -> BuiltinImplConditions<'tcx> { // NOTE: binder moved to (*) let self_ty = self.infcx - .shallow_resolve_type(obligation.predicate.skip_binder().self_ty()); + .shallow_resolve(obligation.predicate.skip_binder().self_ty()); use self::BuiltinImplConditions::{Ambiguous, None, Where}; @@ -2866,7 +2866,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ); let types = obligation.predicate.map_bound(|inner| { - let self_ty = self.infcx.shallow_resolve_type(inner.self_ty()); + let self_ty = self.infcx.shallow_resolve(inner.self_ty()); self.constituent_types_for_ty(self_ty) }); self.vtable_auto_impl(obligation, trait_def_id, types) @@ -2990,7 +2990,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // from the object. Have to try to make a broken test case that // results. let self_ty = self.infcx - .shallow_resolve_type(*obligation.self_ty().skip_binder()); + .shallow_resolve(*obligation.self_ty().skip_binder()); let poly_trait_ref = match self_ty.sty { ty::Dynamic(ref data, ..) => data.principal().unwrap_or_else(|| { @@ -3045,7 +3045,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // OK to skip binder; it is reintroduced below let self_ty = self.infcx - .shallow_resolve_type(*obligation.self_ty().skip_binder()); + .shallow_resolve(*obligation.self_ty().skip_binder()); let sig = self_ty.fn_sig(self.tcx()); let trait_ref = self.tcx() .closure_trait_ref_and_return_type( @@ -3124,8 +3124,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // OK to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters - let self_ty = self.infcx - .shallow_resolve_type(obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let (generator_def_id, substs) = match self_ty.sty { ty::Generator(id, substs, _) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), @@ -3182,8 +3181,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // OK to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope // type/region parameters - let self_ty = self.infcx - .shallow_resolve_type(obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let (closure_def_id, substs) = match self_ty.sty { ty::Closure(id, substs) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), @@ -3278,14 +3276,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // assemble_candidates_for_unsizing should ensure there are no late bound // regions here. See the comment there for more details. let source = self.infcx - .shallow_resolve_type(obligation.self_ty().no_bound_vars().unwrap()); + .shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); let target = obligation .predicate .skip_binder() .trait_ref .substs .type_at(1); - let target = self.infcx.shallow_resolve_type(target); + let target = self.infcx.shallow_resolve(target); debug!( "confirm_builtin_unsize_candidate(source={:?}, target={:?})", diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index fc8fcff7475c4..c474baac3d129 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -406,7 +406,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // moving. (Goal is that an "inductive hypothesis" // is satisfied to ensure termination.) ty::Infer(_) => { - let ty = self.infcx.shallow_resolve_type(ty); + let ty = self.infcx.shallow_resolve(ty); if let ty::Infer(_) = ty.sty { // not yet resolved... if ty == ty0 { // ...this is the type we started from! no progress. return false; diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs index 6bc62364b43fd..9d234e93b837b 100644 --- a/src/librustc_traits/chalk_context/resolvent_ops.rs +++ b/src/librustc_traits/chalk_context/resolvent_ops.rs @@ -204,7 +204,7 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { } fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let b = self.infcx.shallow_resolve_type(b); + let b = self.infcx.shallow_resolve(b); debug!("AnswerSubstitutor::tys(a = {:?}, b = {:?})", a, b); if let &ty::Bound(debruijn, bound_ty) = &a.sty { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index f03a3bde84e4c..8cdfbf5f55ca0 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -350,7 +350,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } PatKind::Ref(ref inner, mutbl) => { - let expected = self.shallow_resolve_type(expected); + let expected = self.shallow_resolve(expected); if self.check_dereferencable(pat.span, expected, &inner) { // `demand::subtype` would be good enough, but using // `eqtype` turns out to be equally general. See (*) @@ -519,7 +519,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { if let PatKind::Binding(..) = inner.node { - if let Some(mt) = self.shallow_resolve_type(expected).builtin_deref(true) { + if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { if let ty::Dynamic(..) = mt.ty.sty { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box", an error. diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 1c6601536eea1..85eb0f9d49966 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -154,7 +154,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - let a = self.shallow_resolve_type(a); + let a = self.shallow_resolve(a); debug!("Coerce.tys({:?} => {:?})", a, b); // Just ignore error types. @@ -170,8 +170,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // let _: Option = Some({ return; }); // // here, we would coerce from `!` to `?T`. - let b = self.shallow_resolve_type(b); - return if self.shallow_resolve_type(b).is_ty_var() { + let b = self.shallow_resolve(b); + return if self.shallow_resolve(b).is_ty_var() { // micro-optimization: no need for this if `b` is // already resolved in some way. let diverging_ty = self.next_diverging_ty_var( @@ -659,7 +659,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { //! into a closure or a `proc`. //! - let b = self.shallow_resolve_type(b); + let b = self.shallow_resolve(b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); self.coerce_from_safe_fn(a, fn_ty_a, b, @@ -673,7 +673,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { //! Attempts to coerce from the type of a Rust function item //! into a closure or a `proc`. - let b = self.shallow_resolve_type(b); + let b = self.shallow_resolve(b); debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); match b.sty { @@ -719,7 +719,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { //! into a function pointer. //! - let b = self.shallow_resolve_type(b); + let b = self.shallow_resolve(b); let hir_id_a = self.tcx.hir().as_local_hir_id(def_id_a).unwrap(); match b.sty { @@ -1128,7 +1128,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> // compatibility (hopefully that is true) by helping us // uncover never types better. if expression_ty.is_ty_var() { - expression_ty = fcx.infcx.shallow_resolve_type(expression_ty); + expression_ty = fcx.infcx.shallow_resolve(expression_ty); } // If we see any error types, just propagate that error diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4b772abc5f09e..d2d486b52b3f8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -281,7 +281,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Expectation<'tcx> { match *self { ExpectHasType(ety) => { - let ety = fcx.shallow_resolve_type(ety); + let ety = fcx.shallow_resolve(ety); if !ety.is_ty_var() { ExpectHasType(ety) } else { @@ -2792,7 +2792,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, expected_vid: ty::TyVid, ) -> bool { - let self_ty = self.shallow_resolve_type(trait_ref.self_ty()); + let self_ty = self.shallow_resolve(trait_ref.self_ty()); debug!( "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", trait_ref, self_ty, expected_vid From a68ed060bdab2d4c5d36062cda24f89d22488271 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 1 May 2019 23:09:53 +0100 Subject: [PATCH 47/47] Split `ct_err` out into `CommonConsts` Co-Authored-By: Gabriel Smith --- src/librustc/infer/resolve.rs | 2 +- src/librustc/ty/context.rs | 25 +++++++++++++++++++++++-- src/librustc_typeck/check/writeback.rs | 4 ++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 61563a8ba269d..079385368f883 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -220,7 +220,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> match c.val { ConstValue::Infer(InferConst::Var(vid)) => { self.err = Some(FixupError::UnresolvedConst(vid)); - return self.tcx().types.ct_err; + return self.tcx().consts.err; } ConstValue::Infer(InferConst::Fresh(_)) => { bug!("Unexpected const in full const resolver: {:?}", c); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e7b6a0ff4f4b5..c07175d9451e6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -231,8 +231,10 @@ pub struct CommonLifetimes<'tcx> { pub re_empty: Region<'tcx>, pub re_static: Region<'tcx>, pub re_erased: Region<'tcx>, +} - pub ct_err: &'tcx Const<'tcx>, +pub struct CommonConsts<'tcx> { + pub err: &'tcx Const<'tcx>, } pub struct LocalTableInContext<'a, V: 'a> { @@ -945,7 +947,7 @@ impl<'tcx> CommonTypes<'tcx> { bool: mk(Bool), char: mk(Char), never: mk(Never), - err, + err: mk(Error), isize: mk(Int(ast::IntTy::Isize)), i8: mk(Int(ast::IntTy::I8)), i16: mk(Int(ast::IntTy::I16)), @@ -982,6 +984,20 @@ impl<'tcx> CommonLifetimes<'tcx> { } } +impl<'tcx> CommonConsts<'tcx> { + fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> { + let mk_const = |c| { + interners.const_.borrow_mut().intern(c, |c| { + Interned(interners.arena.alloc(c)) + }).0 + }; + + CommonConsts { + err: mk_const(ty::Const::zero_sized(types.err)), + } + } +} + // This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime // conflict. #[derive(Debug)] @@ -1032,6 +1048,9 @@ pub struct GlobalCtxt<'tcx> { /// Common lifetimes, pre-interned for your convenience. pub lifetimes: CommonLifetimes<'tcx>, + /// Common consts, pre-interned for your convenience. + pub consts: CommonConsts<'tcx>, + /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. trait_map: FxHashMap TyCtxt<'a, 'gcx, 'tcx> { let interners = CtxtInterners::new(&arenas.interner); let common_types = CommonTypes::new(&interners); let common_lifetimes = CommonLifetimes::new(&interners); + let common_consts = CommonConsts::new(&interners, &common_types); let dep_graph = hir.dep_graph.clone(); let max_cnum = cstore.crates_untracked().iter().map(|c| c.as_usize()).max().unwrap_or(0); let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1); @@ -1286,6 +1306,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { dep_graph, types: common_types, lifetimes: common_lifetimes, + consts: common_consts, trait_map, export_map: resolutions.export_map.into_iter().map(|(k, v)| { let exports: Vec<_> = v.into_iter().map(|e| { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index e13651d253d89..f9d83146e30c3 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -594,7 +594,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ), ) .emit(); - return self.tcx().types.ct_err; + return self.tcx().consts.err; } ct } @@ -864,7 +864,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { ); // FIXME: we'd like to use `self.report_error`, but it doesn't yet // accept a &'tcx ty::Const. - self.tcx().types.ct_err + self.tcx().consts.err } } }