Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/infer/unify_key.rs')
-rw-r--r--crates/hir-ty/src/next_solver/infer/unify_key.rs179
1 files changed, 179 insertions, 0 deletions
diff --git a/crates/hir-ty/src/next_solver/infer/unify_key.rs b/crates/hir-ty/src/next_solver/infer/unify_key.rs
new file mode 100644
index 0000000000..dc913b262a
--- /dev/null
+++ b/crates/hir-ty/src/next_solver/infer/unify_key.rs
@@ -0,0 +1,179 @@
+//! Unification keyes for the infer context the next-trait-solver.
+
+use std::cmp;
+use std::marker::PhantomData;
+
+use ena::unify::{NoError, UnifyKey, UnifyValue};
+use rustc_type_ir::{ConstVid, RegionKind, RegionVid, UniverseIndex, inherent::IntoKind};
+
+use crate::next_solver::{Const, Region, SolverDefId, Ty};
+
+#[derive(Clone, Debug)]
+pub enum RegionVariableValue<'db> {
+ Known { value: Region<'db> },
+ Unknown { universe: UniverseIndex },
+}
+
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct RegionVidKey<'db> {
+ pub vid: RegionVid,
+ pub phantom: PhantomData<RegionVariableValue<'db>>,
+}
+
+impl<'db> From<RegionVid> for RegionVidKey<'db> {
+ fn from(vid: RegionVid) -> Self {
+ RegionVidKey { vid, phantom: PhantomData }
+ }
+}
+
+impl<'db> UnifyKey for RegionVidKey<'db> {
+ type Value = RegionVariableValue<'db>;
+ #[inline]
+ fn index(&self) -> u32 {
+ self.vid.as_u32()
+ }
+ #[inline]
+ fn from_index(i: u32) -> Self {
+ RegionVidKey::from(RegionVid::from_u32(i))
+ }
+ fn tag() -> &'static str {
+ "RegionVidKey"
+ }
+}
+
+pub struct RegionUnificationError;
+impl<'db> UnifyValue for RegionVariableValue<'db> {
+ type Error = RegionUnificationError;
+
+ fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
+ match (value1, value2) {
+ (RegionVariableValue::Known { .. }, RegionVariableValue::Known { .. }) => {
+ Err(RegionUnificationError)
+ }
+
+ (RegionVariableValue::Known { value }, RegionVariableValue::Unknown { universe })
+ | (RegionVariableValue::Unknown { universe }, RegionVariableValue::Known { value }) => {
+ let universe_of_value = match (*value).kind() {
+ RegionKind::ReStatic
+ | RegionKind::ReErased
+ | RegionKind::ReLateParam(..)
+ | RegionKind::ReEarlyParam(..)
+ | RegionKind::ReError(_) => UniverseIndex::ROOT,
+ RegionKind::RePlaceholder(placeholder) => placeholder.universe,
+ RegionKind::ReVar(..) | RegionKind::ReBound(..) => {
+ panic!("not a universal region")
+ }
+ };
+
+ if universe.can_name(universe_of_value) {
+ Ok(RegionVariableValue::Known { value: *value })
+ } else {
+ Err(RegionUnificationError)
+ }
+ }
+
+ (
+ RegionVariableValue::Unknown { universe: a },
+ RegionVariableValue::Unknown { universe: b },
+ ) => {
+ // If we unify two unconstrained regions 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.
+ Ok(RegionVariableValue::Unknown { universe: (*a).min(*b) })
+ }
+ }
+ }
+}
+
+// Generic consts.
+
+#[derive(Copy, Clone, Debug)]
+pub struct ConstVariableOrigin {
+ /// `DefId` of the const parameter this was instantiated for, if any.
+ ///
+ /// This should only be used for diagnostics.
+ pub param_def_id: Option<SolverDefId>,
+}
+
+#[derive(Clone, Debug)]
+pub enum ConstVariableValue<'db> {
+ Known { value: Const<'db> },
+ Unknown { origin: ConstVariableOrigin, universe: UniverseIndex },
+}
+
+impl<'db> ConstVariableValue<'db> {
+ /// If this value is known, returns the const it is known to be.
+ /// Otherwise, `None`.
+ pub fn known(&self) -> Option<Const<'db>> {
+ match self {
+ ConstVariableValue::Unknown { .. } => None,
+ ConstVariableValue::Known { value } => Some(*value),
+ }
+ }
+}
+
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct ConstVidKey<'db> {
+ pub vid: ConstVid,
+ pub phantom: PhantomData<Const<'db>>,
+}
+
+impl<'db> From<ConstVid> for ConstVidKey<'db> {
+ fn from(vid: ConstVid) -> Self {
+ ConstVidKey { vid, phantom: PhantomData }
+ }
+}
+
+impl<'db> UnifyKey for ConstVidKey<'db> {
+ type Value = ConstVariableValue<'db>;
+ #[inline]
+ fn index(&self) -> u32 {
+ self.vid.as_u32()
+ }
+ #[inline]
+ fn from_index(i: u32) -> Self {
+ ConstVidKey::from(ConstVid::from_u32(i))
+ }
+ fn tag() -> &'static str {
+ "ConstVidKey"
+ }
+ fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> {
+ if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) }
+ }
+}
+
+impl<'db> UnifyValue for ConstVariableValue<'db> {
+ type Error = NoError;
+
+ fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
+ match (value1, value2) {
+ (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
+ panic!("equating two const variables, both of which have known values")
+ }
+
+ // If one side is known, prefer that one.
+ (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
+ Ok(value1.clone())
+ }
+ (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
+ Ok(value2.clone())
+ }
+
+ // If both sides are *unknown*, it hardly matters, does it?
+ (
+ ConstVariableValue::Unknown { origin, universe: universe1 },
+ ConstVariableValue::Unknown { origin: _, 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 { origin: *origin, universe })
+ }
+ }
+ }
+}