From c888af52be46ed87bb14043da02df486288701c6 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 13 Mar 2019 15:19:35 +0000 Subject: [PATCH] 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 670c44bef3d..7ee762d94ae 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -28,7 +28,7 @@ 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::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 @@ pub fn unify_const_variable( ) -> 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 @@ fn consts( .. }) => { 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 ac758add872..00000000000 --- 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 e94996a0b99..226ab8b438e 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -8,6 +8,7 @@ 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 @@ fn consts( 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 aa1a8636196..a1de0884788 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -232,7 +232,8 @@ fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<' 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 5bb007dbb00..43f4ecfb852 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -181,26 +181,16 @@ fn fold_const(&mut self, ct: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<' 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 ec77bb39e7d..84ebe2d8b52 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 @@ pub fn replace_bound_vars_with_placeholders( })) }; - 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 80816100fae..e013b2429e3 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -10,6 +10,7 @@ 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::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 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 @@ pub fn enter(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, '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 @@ pub fn into_obligations(self) -> PredicateObligations<'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 @@ pub fn next_const_var_in_universe( ) -> &'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 @@ pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> Kind<'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 @@ pub fn probe_const_var( &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 @@ pub fn resolve_const_var( }) = 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 @@ pub fn shallow_resolve_const( }) => { 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 b285d597291..1b34403f053 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -6,6 +6,7 @@ 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 @@ fn consts( 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 208c553aa32..5cd0e8e2591 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 @@ fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { 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 + } +} -- 2.44.0