]> git.lizzy.rs Git - rust.git/commitdiff
Replace ConstVariableTable with UnificationTable
authorvarkor <github@varkor.com>
Wed, 13 Mar 2019 15:19:35 +0000 (15:19 +0000)
committervarkor <github@varkor.com>
Wed, 1 May 2019 22:10:58 +0000 (23:10 +0100)
src/librustc/infer/combine.rs
src/librustc/infer/const_variable.rs [deleted file]
src/librustc/infer/equate.rs
src/librustc/infer/freshen.rs
src/librustc/infer/fudge.rs
src/librustc/infer/higher_ranked/mod.rs
src/librustc/infer/mod.rs
src/librustc/infer/sub.rs
src/librustc/infer/unify_key.rs

index 670c44bef3dbf89c51b40a317b1e41613292ba77..7ee762d94ae6c8b6b20caddf5ddba7819e6eba86 100644 (file)
@@ -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 (file)
index ac758ad..0000000
+++ /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<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.
-    }
-}
index e94996a0b99a3cd0976527f0d00d7eefc1efc588..226ab8b438e3fff96f88c91be9b1791f477be154 100644 (file)
@@ -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) {
index aa1a86361965a1a74f85874c66e0c1ce6b9ec849..a1de08847887176a7813ad310a2bc19f85a9faa9 100644 (file)
@@ -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,
index 5bb007dbb0081a111870a580cc83a303ded51163..43f4ecfb852bf321f230e1ffad9caeae7e1d8ce3 100644 (file)
@@ -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)
index ec77bb39e7d2afd6a22a75c5aaf173e156c3a955..84ebe2d8b52928a5fcfb57ac82aecaa0e348520b 100644 (file)
@@ -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 @@ pub fn replace_bound_vars_with_placeholders<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 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);
index 80816100faed7885d962672bbdb30293229d64c1..e013b2429e31815864de90248fc8bf3f4950cf6c 100644 (file)
@@ -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;
 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<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 @@ pub fn enter<R>(&'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<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 @@ 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)
index b285d59729110706964e151360e6e126a67a1a3b..1b34403f0533997d3466b886ac9df33d6cb74e01 100644 (file)
@@ -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.
index 208c553aa327f82b82b60863c9daa15eadb9aece..5cd0e8e25912e46e9bfa3b05e85e46990d19d4ca 100644 (file)
@@ -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<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
+    }
+}