rustc_infer/infer/
unify_key.rs

1use std::cmp;
2use std::marker::PhantomData;
3
4use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
5use rustc_middle::{bug, ty};
6use rustc_span::Span;
7use rustc_span::def_id::DefId;
8
9#[derive(Copy, Clone, Debug)]
10pub(crate) enum RegionVariableValue<'tcx> {
11    Known { value: ty::Region<'tcx> },
12    Unknown { universe: ty::UniverseIndex },
13}
14
15#[derive(PartialEq, Copy, Clone, Debug)]
16pub(crate) struct RegionVidKey<'tcx> {
17    pub vid: ty::RegionVid,
18    pub phantom: PhantomData<RegionVariableValue<'tcx>>,
19}
20
21impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
22    fn from(vid: ty::RegionVid) -> Self {
23        RegionVidKey { vid, phantom: PhantomData }
24    }
25}
26
27impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
28    type Value = RegionVariableValue<'tcx>;
29    #[inline]
30    fn index(&self) -> u32 {
31        self.vid.as_u32()
32    }
33    #[inline]
34    fn from_index(i: u32) -> Self {
35        RegionVidKey::from(ty::RegionVid::from_u32(i))
36    }
37    fn tag() -> &'static str {
38        "RegionVidKey"
39    }
40}
41
42pub(crate) struct RegionUnificationError;
43
44impl<'tcx> UnifyValue for RegionVariableValue<'tcx> {
45    type Error = RegionUnificationError;
46
47    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
48        match (*value1, *value2) {
49            (RegionVariableValue::Known { .. }, RegionVariableValue::Known { .. }) => {
50                Err(RegionUnificationError)
51            }
52
53            (RegionVariableValue::Known { value }, RegionVariableValue::Unknown { universe })
54            | (RegionVariableValue::Unknown { universe }, RegionVariableValue::Known { value }) => {
55                let universe_of_value = match value.kind() {
56                    ty::ReStatic
57                    | ty::ReErased
58                    | ty::ReLateParam(..)
59                    | ty::ReEarlyParam(..)
60                    | ty::ReError(_) => ty::UniverseIndex::ROOT,
61                    ty::RePlaceholder(placeholder) => placeholder.universe,
62                    ty::ReVar(..) | ty::ReBound(..) => bug!("not a universal region"),
63                };
64
65                if universe.can_name(universe_of_value) {
66                    Ok(RegionVariableValue::Known { value })
67                } else {
68                    Err(RegionUnificationError)
69                }
70            }
71
72            (
73                RegionVariableValue::Unknown { universe: a },
74                RegionVariableValue::Unknown { universe: b },
75            ) => {
76                // If we unify two unconstrained regions then whatever
77                // value they wind up taking (which must be the same value) must
78                // be nameable by both universes. Therefore, the resulting
79                // universe is the minimum of the two universes, because that is
80                // the one which contains the fewest names in scope.
81                Ok(RegionVariableValue::Unknown { universe: a.min(b) })
82            }
83        }
84    }
85}
86
87// Generic consts.
88
89#[derive(Copy, Clone, Debug)]
90pub struct ConstVariableOrigin {
91    pub span: Span,
92    /// `DefId` of the const parameter this was instantiated for, if any.
93    ///
94    /// This should only be used for diagnostics.
95    pub param_def_id: Option<DefId>,
96}
97
98#[derive(Copy, Clone, Debug)]
99pub(crate) enum ConstVariableValue<'tcx> {
100    Known { value: ty::Const<'tcx> },
101    Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
102}
103
104impl<'tcx> ConstVariableValue<'tcx> {
105    /// If this value is known, returns the const it is known to be.
106    /// Otherwise, `None`.
107    pub(crate) fn known(&self) -> Option<ty::Const<'tcx>> {
108        match *self {
109            ConstVariableValue::Unknown { .. } => None,
110            ConstVariableValue::Known { value } => Some(value),
111        }
112    }
113}
114
115#[derive(PartialEq, Copy, Clone, Debug)]
116pub(crate) struct ConstVidKey<'tcx> {
117    pub vid: ty::ConstVid,
118    pub phantom: PhantomData<ty::Const<'tcx>>,
119}
120
121impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> {
122    fn from(vid: ty::ConstVid) -> Self {
123        ConstVidKey { vid, phantom: PhantomData }
124    }
125}
126
127impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
128    type Value = ConstVariableValue<'tcx>;
129    #[inline]
130    fn index(&self) -> u32 {
131        self.vid.as_u32()
132    }
133    #[inline]
134    fn from_index(i: u32) -> Self {
135        ConstVidKey::from(ty::ConstVid::from_u32(i))
136    }
137    fn tag() -> &'static str {
138        "ConstVidKey"
139    }
140}
141
142impl<'tcx> UnifyValue for ConstVariableValue<'tcx> {
143    type Error = NoError;
144
145    fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
146        match (value1, value2) {
147            (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
148                bug!("equating two const variables, both of which have known values")
149            }
150
151            // If one side is known, prefer that one.
152            (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(value1),
153            (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(value2),
154
155            // If both sides are *unknown*, it hardly matters, does it?
156            (
157                ConstVariableValue::Unknown { origin, universe: universe1 },
158                ConstVariableValue::Unknown { origin: _, universe: universe2 },
159            ) => {
160                // If we unify two unbound variables, ?T and ?U, then whatever
161                // value they wind up taking (which must be the same value) must
162                // be nameable by both universes. Therefore, the resulting
163                // universe is the minimum of the two universes, because that is
164                // the one which contains the fewest names in scope.
165                let universe = cmp::min(universe1, universe2);
166                Ok(ConstVariableValue::Unknown { origin, universe })
167            }
168        }
169    }
170}