]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/unify_key.rs
5cd0e8e25912e46e9bfa3b05e85e46990d19d4ca
[rust.git] / src / librustc / infer / unify_key.rs
1 use crate::ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt, InferConst};
2 use crate::mir::interpret::ConstValue;
3 use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue, UnificationTable};
4 use rustc_data_structures::unify::InPlace;
5 use syntax_pos::{Span, DUMMY_SP};
6 use syntax::symbol::InternedString;
7
8 use std::cmp;
9 use std::marker::PhantomData;
10 use std::cell::RefMut;
11
12 pub trait ToType {
13     fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
14 }
15
16 impl UnifyKey for ty::IntVid {
17     type Value = Option<IntVarValue>;
18     fn index(&self) -> u32 { self.index }
19     fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
20     fn tag() -> &'static str { "IntVid" }
21 }
22
23 impl EqUnifyValue for IntVarValue {}
24
25 #[derive(PartialEq, Copy, Clone, Debug)]
26 pub struct RegionVidKey {
27     /// The minimum region vid in the unification set. This is needed
28     /// to have a canonical name for a type to prevent infinite
29     /// recursion.
30     pub min_vid: ty::RegionVid
31 }
32
33 impl UnifyValue for RegionVidKey {
34     type Error = NoError;
35
36     fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
37         let min_vid = if value1.min_vid.index() < value2.min_vid.index() {
38             value1.min_vid
39         } else {
40             value2.min_vid
41         };
42
43         Ok(RegionVidKey { min_vid })
44     }
45 }
46
47 impl UnifyKey for ty::RegionVid {
48     type Value = RegionVidKey;
49     fn index(&self) -> u32 { u32::from(*self) }
50     fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid::from(i) }
51     fn tag() -> &'static str { "RegionVid" }
52 }
53
54 impl ToType for IntVarValue {
55     fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
56         match *self {
57             ty::IntType(i) => tcx.mk_mach_int(i),
58             ty::UintType(i) => tcx.mk_mach_uint(i),
59         }
60     }
61 }
62
63 // Floating point type keys
64
65 impl UnifyKey for ty::FloatVid {
66     type Value = Option<FloatVarValue>;
67     fn index(&self) -> u32 { self.index }
68     fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
69     fn tag() -> &'static str { "FloatVid" }
70 }
71
72 impl EqUnifyValue for FloatVarValue {}
73
74 impl ToType for FloatVarValue {
75     fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
76         tcx.mk_mach_float(self.0)
77     }
78 }
79
80 // Generic consts.
81
82 /// Reasons to create a const inference variable
83 #[derive(Copy, Clone, Debug)]
84 pub enum ConstVariableOrigin {
85     MiscVariable(Span),
86     ConstInference(Span),
87     ConstParameterDefinition(Span, InternedString),
88     SubstitutionPlaceholder(Span),
89 }
90
91 #[derive(Copy, Clone, Debug)]
92 pub enum ConstVariableValue<'tcx> {
93     Known { value: &'tcx ty::LazyConst<'tcx> },
94     Unknown { universe: ty::UniverseIndex },
95 }
96
97 impl<'tcx> ConstVariableValue<'tcx> {
98     /// If this value is known, returns the const it is known to be.
99     /// Otherwise, `None`.
100     pub fn known(&self) -> Option<&'tcx ty::LazyConst<'tcx>> {
101         match *self {
102             ConstVariableValue::Unknown { .. } => None,
103             ConstVariableValue::Known { value } => Some(value),
104         }
105     }
106
107     pub fn is_unknown(&self) -> bool {
108         match *self {
109             ConstVariableValue::Unknown { .. } => true,
110             ConstVariableValue::Known { .. } => false,
111         }
112     }
113 }
114
115 #[derive(Copy, Clone, Debug)]
116 pub struct ConstVarValue<'tcx> {
117     pub origin: ConstVariableOrigin,
118     pub val: ConstVariableValue<'tcx>,
119 }
120
121 impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
122     type Value = ConstVarValue<'tcx>;
123     fn index(&self) -> u32 { self.index }
124     fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } }
125     fn tag() -> &'static str { "ConstVid" }
126 }
127
128 impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
129     type Error = (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>);
130
131     fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
132         let val = match (value1.val, value2.val) {
133             (
134                 ConstVariableValue::Known { value: value1 },
135                 ConstVariableValue::Known { value: value2 }
136             ) => {
137                 match <&'tcx ty::LazyConst<'tcx>>::unify_values(&value1, &value2) {
138                     Ok(value) => Ok(ConstVariableValue::Known { value }),
139                     Err(err) => Err(err),
140                 }
141             }
142
143             // If one side is known, prefer that one.
144             (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
145                 Ok(value1.val)
146             }
147             (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
148                 Ok(value2.val)
149             }
150
151             // If both sides are *unknown*, it hardly matters, does it?
152             (ConstVariableValue::Unknown { universe: universe1 },
153              ConstVariableValue::Unknown { universe: universe2 }) =>  {
154                 // If we unify two unbound variables, ?T and ?U, then whatever
155                 // value they wind up taking (which must be the same value) must
156                 // be nameable by both universes. Therefore, the resulting
157                 // universe is the minimum of the two universes, because that is
158                 // the one which contains the fewest names in scope.
159                 let universe = cmp::min(universe1, universe2);
160                 Ok(ConstVariableValue::Unknown { universe })
161             }
162         }?;
163
164         Ok(ConstVarValue {
165             origin: ConstVariableOrigin::ConstInference(DUMMY_SP),
166             val,
167         })
168     }
169 }
170
171 impl<'tcx> EqUnifyValue for &'tcx ty::LazyConst<'tcx> {}
172
173 pub fn replace_if_possible(
174     mut table: RefMut<'_, UnificationTable<InPlace<ty::ConstVid<'tcx>>>>,
175     c: &'tcx ty::LazyConst<'tcx>
176 ) -> &'tcx ty::LazyConst<'tcx> {
177     if let ty::LazyConst::Evaluated(ty::Const {
178         val: ConstValue::Infer(InferConst::Var(vid)),
179         ..
180     }) = c {
181         match table.probe_value(*vid).val.known() {
182             Some(c) => c,
183             None => c,
184         }
185     } else {
186         c
187     }
188 }