]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/infer/unify_key.rs
Move `{core,std}::stream::Stream` to `{core,std}::async_iter::AsyncIterator`.
[rust.git] / compiler / rustc_middle / src / infer / unify_key.rs
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,
6 };
7 use rustc_span::def_id::DefId;
8 use rustc_span::symbol::Symbol;
9 use rustc_span::Span;
10
11 use std::cmp;
12 use std::marker::PhantomData;
13
14 pub trait ToType {
15     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
16 }
17
18 #[derive(PartialEq, Copy, Clone, Debug)]
19 pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>);
20
21 #[derive(PartialEq, Copy, Clone, Debug)]
22 pub struct RegionVidKey<'tcx> {
23     pub vid: ty::RegionVid,
24     pub phantom: PhantomData<UnifiedRegion<'tcx>>,
25 }
26
27 impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
28     fn from(vid: ty::RegionVid) -> Self {
29         RegionVidKey { vid, phantom: PhantomData }
30     }
31 }
32
33 impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
34     type Value = UnifiedRegion<'tcx>;
35     fn index(&self) -> u32 {
36         self.vid.as_u32()
37     }
38     fn from_index(i: u32) -> Self {
39         RegionVidKey::from(ty::RegionVid::from_u32(i))
40     }
41     fn tag() -> &'static str {
42         "RegionVidKey"
43     }
44 }
45
46 impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
47     type Error = NoError;
48
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,
55
56             (Some(_), _) => *value1,
57             (_, Some(_)) => *value2,
58
59             (None, None) => *value1,
60         })
61     }
62 }
63
64 impl ToType for ty::IntVarValue {
65     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
66         match *self {
67             ty::IntType(i) => tcx.mk_mach_int(i),
68             ty::UintType(i) => tcx.mk_mach_uint(i),
69         }
70     }
71 }
72
73 impl ToType for ty::FloatVarValue {
74     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
75         tcx.mk_mach_float(self.0)
76     }
77 }
78
79 // Generic consts.
80
81 #[derive(Copy, Clone, Debug)]
82 pub struct ConstVariableOrigin {
83     pub kind: ConstVariableOriginKind,
84     pub span: Span,
85 }
86
87 /// Reasons to create a const inference variable
88 #[derive(Copy, Clone, Debug)]
89 pub enum ConstVariableOriginKind {
90     MiscVariable,
91     ConstInference,
92     ConstParameterDefinition(Symbol, DefId),
93     SubstitutionPlaceholder,
94 }
95
96 #[derive(Copy, Clone, Debug)]
97 pub enum ConstVariableValue<'tcx> {
98     Known { value: &'tcx ty::Const<'tcx> },
99     Unknown { universe: ty::UniverseIndex },
100 }
101
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>> {
106         match *self {
107             ConstVariableValue::Unknown { .. } => None,
108             ConstVariableValue::Known { value } => Some(value),
109         }
110     }
111 }
112
113 #[derive(Copy, Clone, Debug)]
114 pub struct ConstVarValue<'tcx> {
115     pub origin: ConstVariableOrigin,
116     pub val: ConstVariableValue<'tcx>,
117 }
118
119 impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
120     type Value = ConstVarValue<'tcx>;
121     fn index(&self) -> u32 {
122         self.index
123     }
124     fn from_index(i: u32) -> Self {
125         ty::ConstVid { index: i, phantom: PhantomData }
126     }
127     fn tag() -> &'static str {
128         "ConstVid"
129     }
130 }
131
132 impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
133     type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);
134
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")
139             }
140
141             // If one side is known, prefer that one.
142             (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => value1,
143             (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2,
144
145             // If both sides are *unknown*, it hardly matters, does it?
146             (
147                 ConstVariableValue::Unknown { universe: universe1 },
148                 ConstVariableValue::Unknown { universe: universe2 },
149             ) => {
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);
156                 ConstVarValue {
157                     val: ConstVariableValue::Unknown { universe },
158                     origin: value1.origin,
159                 }
160             }
161         })
162     }
163 }
164
165 impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}
166
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>
171 where
172     V: snapshot_vec::VecLike<unify::Delegate<ty::ConstVid<'tcx>>>,
173     L: UndoLogs<snapshot_vec::UndoLog<unify::Delegate<ty::ConstVid<'tcx>>>>,
174 {
175     if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c {
176         match table.probe_value(*vid).val.known() {
177             Some(c) => c,
178             None => c,
179         }
180     } else {
181         c
182     }
183 }