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