Replace ConstVariableTable with UnificationTable
This commit is contained in:
parent
2308d2d68a
commit
c888af52be
9 changed files with 181 additions and 328 deletions
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Delegate<'tcx>>,
|
||||
|
||||
relations: ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>,
|
||||
}
|
||||
|
||||
/// 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<ty::ConstVid<'tcx>, 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<ut::InPlace<ty::ConstVid<'tcx>>>,
|
||||
}
|
||||
|
||||
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<Self, Self::Error> {
|
||||
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<ConstVariableData>, _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.
|
||||
}
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<T>(
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<type_variable::TypeVariableTable<'tcx>>,
|
||||
|
||||
/// Map from const parameter variable to the kind of const it represents.
|
||||
const_unification_table: RefCell<const_variable::ConstVariableTable<'tcx>>,
|
||||
const_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>>,
|
||||
|
||||
/// Map from integral variable to the kind of integer it represents.
|
||||
int_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::IntVid>>>,
|
||||
|
|
@ -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<ut::InPlace<ty::ConstVid<'tcx>>>,
|
||||
int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
|
||||
float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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<Self, Self::Error> {
|
||||
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<InPlace<ty::ConstVid<'tcx>>>>,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue