1 use crate::ty::{self, InferConst, Ty, TyCtxt};
2 use rustc_data_structures::snapshot_vec;
3 use rustc_data_structures::undo_log::UndoLogs;
4 use rustc_data_structures::unify::{
5 self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue,
7 use rustc_span::def_id::DefId;
8 use rustc_span::symbol::Symbol;
12 use std::marker::PhantomData;
15 fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
18 #[derive(PartialEq, Copy, Clone, Debug)]
19 pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>);
21 #[derive(PartialEq, Copy, Clone, Debug)]
22 pub struct RegionVidKey<'tcx> {
23 pub vid: ty::RegionVid,
24 pub phantom: PhantomData<UnifiedRegion<'tcx>>,
27 impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
28 fn from(vid: ty::RegionVid) -> Self {
29 RegionVidKey { vid, phantom: PhantomData }
33 impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
34 type Value = UnifiedRegion<'tcx>;
35 fn index(&self) -> u32 {
38 fn from_index(i: u32) -> Self {
39 RegionVidKey::from(ty::RegionVid::from_u32(i))
41 fn tag() -> &'static str {
46 impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
49 fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
50 Ok(match (value1.0, value2.0) {
51 // Here we can just pick one value, because the full constraints graph
52 // will be handled later. Ideally, we might want a `MultipleValues`
53 // variant or something. For now though, this is fine.
54 (Some(_), Some(_)) => *value1,
56 (Some(_), _) => *value1,
57 (_, Some(_)) => *value2,
59 (None, None) => *value1,
64 impl ToType for ty::IntVarValue {
65 fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
67 ty::IntType(i) => tcx.mk_mach_int(i),
68 ty::UintType(i) => tcx.mk_mach_uint(i),
73 impl ToType for ty::FloatVarValue {
74 fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
75 tcx.mk_mach_float(self.0)
81 #[derive(Copy, Clone, Debug)]
82 pub struct ConstVariableOrigin {
83 pub kind: ConstVariableOriginKind,
87 /// Reasons to create a const inference variable
88 #[derive(Copy, Clone, Debug)]
89 pub enum ConstVariableOriginKind {
92 ConstParameterDefinition(Symbol, DefId),
93 SubstitutionPlaceholder,
96 #[derive(Copy, Clone, Debug)]
97 pub enum ConstVariableValue<'tcx> {
98 Known { value: &'tcx ty::Const<'tcx> },
99 Unknown { universe: ty::UniverseIndex },
102 impl<'tcx> ConstVariableValue<'tcx> {
103 /// If this value is known, returns the const it is known to be.
104 /// Otherwise, `None`.
105 pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> {
107 ConstVariableValue::Unknown { .. } => None,
108 ConstVariableValue::Known { value } => Some(value),
113 #[derive(Copy, Clone, Debug)]
114 pub struct ConstVarValue<'tcx> {
115 pub origin: ConstVariableOrigin,
116 pub val: ConstVariableValue<'tcx>,
119 impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
120 type Value = ConstVarValue<'tcx>;
121 fn index(&self) -> u32 {
124 fn from_index(i: u32) -> Self {
125 ty::ConstVid { index: i, phantom: PhantomData }
127 fn tag() -> &'static str {
132 impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
133 type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);
135 fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
136 Ok(match (value1.val, value2.val) {
137 (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
138 bug!("equating two const variables, both of which have known values")
141 // If one side is known, prefer that one.
142 (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => value1,
143 (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2,
145 // If both sides are *unknown*, it hardly matters, does it?
147 ConstVariableValue::Unknown { universe: universe1 },
148 ConstVariableValue::Unknown { universe: universe2 },
150 // If we unify two unbound variables, ?T and ?U, then whatever
151 // value they wind up taking (which must be the same value) must
152 // be nameable by both universes. Therefore, the resulting
153 // universe is the minimum of the two universes, because that is
154 // the one which contains the fewest names in scope.
155 let universe = cmp::min(universe1, universe2);
157 val: ConstVariableValue::Unknown { universe },
158 origin: value1.origin,
165 impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}
167 pub fn replace_if_possible<'tcx, V, L>(
168 table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>, V, L>>,
169 c: &'tcx ty::Const<'tcx>,
170 ) -> &'tcx ty::Const<'tcx>
172 V: snapshot_vec::VecLike<unify::Delegate<ty::ConstVid<'tcx>>>,
173 L: UndoLogs<snapshot_vec::UndoLog<unify::Delegate<ty::ConstVid<'tcx>>>>,
175 if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c {
176 match table.probe_value(*vid).val.known() {