//! 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}; #[derive(Clone, Debug)] pub(crate) enum RegionVariableValue<'db> { Known { value: Region<'db> }, Unknown { universe: UniverseIndex }, } #[derive(PartialEq, Copy, Clone, Debug)] pub(crate) struct RegionVidKey<'db> { pub(crate) vid: RegionVid, pub(crate) phantom: PhantomData>, } impl<'db> From 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(crate) struct RegionUnificationError; impl<'db> UnifyValue for RegionVariableValue<'db> { type Error = RegionUnificationError; fn unify_values(value1: &Self, value2: &Self) -> Result { 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 {} #[derive(Clone, Debug)] pub(crate) 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(crate) fn known(&self) -> Option> { match self { ConstVariableValue::Unknown { .. } => None, ConstVariableValue::Known { value } => Some(*value), } } } #[derive(PartialEq, Copy, Clone, Debug)] pub(crate) struct ConstVidKey<'db> { pub(crate) vid: ConstVid, pub(crate) phantom: PhantomData>, } impl<'db> From 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 { 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 }) } } } }