diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e9b80c56e0c..12321f2e355 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) }