• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::ty::{self, Region, Ty, TyCtxt};
2 use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
3 use rustc_span::def_id::DefId;
4 use rustc_span::symbol::Symbol;
5 use rustc_span::Span;
6 use std::cmp;
7 use std::marker::PhantomData;
8 
9 pub trait ToType {
to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>10     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
11 }
12 
13 #[derive(PartialEq, Copy, Clone, Debug)]
14 pub struct UnifiedRegion<'tcx> {
15     value: Option<ty::Region<'tcx>>,
16 }
17 
18 impl<'tcx> UnifiedRegion<'tcx> {
new(value: Option<Region<'tcx>>) -> Self19     pub fn new(value: Option<Region<'tcx>>) -> Self {
20         Self { value }
21     }
22 
23     /// The caller is responsible for checking universe compatibility before using this value.
get_value_ignoring_universes(self) -> Option<Region<'tcx>>24     pub fn get_value_ignoring_universes(self) -> Option<Region<'tcx>> {
25         self.value
26     }
27 }
28 
29 #[derive(PartialEq, Copy, Clone, Debug)]
30 pub struct RegionVidKey<'tcx> {
31     pub vid: ty::RegionVid,
32     pub phantom: PhantomData<UnifiedRegion<'tcx>>,
33 }
34 
35 impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
from(vid: ty::RegionVid) -> Self36     fn from(vid: ty::RegionVid) -> Self {
37         RegionVidKey { vid, phantom: PhantomData }
38     }
39 }
40 
41 impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
42     type Value = UnifiedRegion<'tcx>;
43     #[inline]
index(&self) -> u3244     fn index(&self) -> u32 {
45         self.vid.as_u32()
46     }
47     #[inline]
from_index(i: u32) -> Self48     fn from_index(i: u32) -> Self {
49         RegionVidKey::from(ty::RegionVid::from_u32(i))
50     }
tag() -> &'static str51     fn tag() -> &'static str {
52         "RegionVidKey"
53     }
54 }
55 
56 impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
57     type Error = NoError;
58 
unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError>59     fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
60         // We pick the value of the least universe because it is compatible with more variables.
61         // This is *not* necessary for soundness, but it allows more region variables to be
62         // resolved to the said value.
63         #[cold]
64         fn min_universe<'tcx>(r1: Region<'tcx>, r2: Region<'tcx>) -> Region<'tcx> {
65             cmp::min_by_key(r1, r2, |r| match r.kind() {
66                 ty::ReStatic
67                 | ty::ReErased
68                 | ty::ReFree(..)
69                 | ty::ReEarlyBound(..)
70                 | ty::ReError(_) => ty::UniverseIndex::ROOT,
71                 ty::RePlaceholder(placeholder) => placeholder.universe,
72                 ty::ReVar(..) | ty::ReLateBound(..) => bug!("not a universal region"),
73             })
74         }
75 
76         Ok(match (value1.value, value2.value) {
77             // Here we can just pick one value, because the full constraints graph
78             // will be handled later. Ideally, we might want a `MultipleValues`
79             // variant or something. For now though, this is fine.
80             (Some(val1), Some(val2)) => Self { value: Some(min_universe(val1, val2)) },
81 
82             (Some(_), _) => *value1,
83             (_, Some(_)) => *value2,
84 
85             (None, None) => *value1,
86         })
87     }
88 }
89 
90 impl ToType for ty::IntVarValue {
to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>91     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
92         match *self {
93             ty::IntType(i) => Ty::new_int(tcx, i),
94             ty::UintType(i) => Ty::new_uint(tcx, i),
95         }
96     }
97 }
98 
99 impl ToType for ty::FloatVarValue {
to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>100     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
101         Ty::new_float(tcx, self.0)
102     }
103 }
104 
105 // Generic consts.
106 
107 #[derive(Copy, Clone, Debug)]
108 pub struct ConstVariableOrigin {
109     pub kind: ConstVariableOriginKind,
110     pub span: Span,
111 }
112 
113 /// Reasons to create a const inference variable
114 #[derive(Copy, Clone, Debug)]
115 pub enum ConstVariableOriginKind {
116     MiscVariable,
117     ConstInference,
118     ConstParameterDefinition(Symbol, DefId),
119 }
120 
121 #[derive(Copy, Clone, Debug)]
122 pub enum ConstVariableValue<'tcx> {
123     Known { value: ty::Const<'tcx> },
124     Unknown { universe: ty::UniverseIndex },
125 }
126 
127 impl<'tcx> ConstVariableValue<'tcx> {
128     /// If this value is known, returns the const it is known to be.
129     /// Otherwise, `None`.
known(&self) -> Option<ty::Const<'tcx>>130     pub fn known(&self) -> Option<ty::Const<'tcx>> {
131         match *self {
132             ConstVariableValue::Unknown { .. } => None,
133             ConstVariableValue::Known { value } => Some(value),
134         }
135     }
136 }
137 
138 #[derive(Copy, Clone, Debug)]
139 pub struct ConstVarValue<'tcx> {
140     pub origin: ConstVariableOrigin,
141     pub val: ConstVariableValue<'tcx>,
142 }
143 
144 impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
145     type Value = ConstVarValue<'tcx>;
146     #[inline]
index(&self) -> u32147     fn index(&self) -> u32 {
148         self.index
149     }
150     #[inline]
from_index(i: u32) -> Self151     fn from_index(i: u32) -> Self {
152         ty::ConstVid { index: i, phantom: PhantomData }
153     }
tag() -> &'static str154     fn tag() -> &'static str {
155         "ConstVid"
156     }
157 }
158 
159 impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
160     type Error = NoError;
161 
unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error>162     fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
163         Ok(match (value1.val, value2.val) {
164             (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
165                 bug!("equating two const variables, both of which have known values")
166             }
167 
168             // If one side is known, prefer that one.
169             (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => value1,
170             (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2,
171 
172             // If both sides are *unknown*, it hardly matters, does it?
173             (
174                 ConstVariableValue::Unknown { universe: universe1 },
175                 ConstVariableValue::Unknown { universe: universe2 },
176             ) => {
177                 // If we unify two unbound variables, ?T and ?U, then whatever
178                 // value they wind up taking (which must be the same value) must
179                 // be nameable by both universes. Therefore, the resulting
180                 // universe is the minimum of the two universes, because that is
181                 // the one which contains the fewest names in scope.
182                 let universe = cmp::min(universe1, universe2);
183                 ConstVarValue {
184                     val: ConstVariableValue::Unknown { universe },
185                     origin: value1.origin,
186                 }
187             }
188         })
189     }
190 }
191