]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use rustc_hir::def_id::DefId; |
ba9703b0 | 2 | use rustc_middle::ty::{self, Ty, TyVid}; |
dfeec247 XL |
3 | use rustc_span::symbol::Symbol; |
4 | use rustc_span::Span; | |
c1a9b12d | 5 | |
f9f354fc XL |
6 | use crate::infer::InferCtxtUndoLogs; |
7 | ||
dfeec247 XL |
8 | use rustc_data_structures::snapshot_vec as sv; |
9 | use rustc_data_structures::unify as ut; | |
0531ce1d | 10 | use std::cmp; |
85aaf69f | 11 | use std::marker::PhantomData; |
532ac7d7 | 12 | use std::ops::Range; |
1a4d82fc | 13 | |
f9f354fc XL |
14 | use rustc_data_structures::undo_log::{Rollback, UndoLogs}; |
15 | ||
16 | /// Represents a single undo-able action that affects a type inference variable. | |
17 | pub(crate) enum UndoLog<'tcx> { | |
18 | EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>), | |
19 | SubRelation(sv::UndoLog<ut::Delegate<ty::TyVid>>), | |
20 | Values(sv::UndoLog<Delegate>), | |
21 | } | |
22 | ||
23 | /// Convert from a specific kind of undo to the more general UndoLog | |
24 | impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for UndoLog<'tcx> { | |
25 | fn from(l: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) -> Self { | |
26 | UndoLog::EqRelation(l) | |
27 | } | |
28 | } | |
29 | ||
30 | /// Convert from a specific kind of undo to the more general UndoLog | |
31 | impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::TyVid>>> for UndoLog<'tcx> { | |
32 | fn from(l: sv::UndoLog<ut::Delegate<ty::TyVid>>) -> Self { | |
33 | UndoLog::SubRelation(l) | |
34 | } | |
35 | } | |
36 | ||
37 | /// Convert from a specific kind of undo to the more general UndoLog | |
38 | impl<'tcx> From<sv::UndoLog<Delegate>> for UndoLog<'tcx> { | |
39 | fn from(l: sv::UndoLog<Delegate>) -> Self { | |
40 | UndoLog::Values(l) | |
41 | } | |
42 | } | |
43 | ||
44 | /// Convert from a specific kind of undo to the more general UndoLog | |
45 | impl<'tcx> From<Instantiate> for UndoLog<'tcx> { | |
46 | fn from(l: Instantiate) -> Self { | |
47 | UndoLog::Values(sv::UndoLog::Other(l)) | |
48 | } | |
49 | } | |
50 | ||
51 | impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> { | |
52 | fn reverse(&mut self, undo: UndoLog<'tcx>) { | |
53 | match undo { | |
54 | UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo), | |
55 | UndoLog::SubRelation(undo) => self.sub_relations.reverse(undo), | |
56 | UndoLog::Values(undo) => self.values.reverse(undo), | |
57 | } | |
58 | } | |
59 | } | |
60 | ||
61 | pub struct TypeVariableStorage<'tcx> { | |
62 | values: sv::SnapshotVecStorage<Delegate>, | |
cc61c64b XL |
63 | |
64 | /// Two variables are unified in `eq_relations` when we have a | |
0531ce1d XL |
65 | /// constraint `?X == ?Y`. This table also stores, for each key, |
66 | /// the known value. | |
f9f354fc | 67 | eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>, |
cc61c64b | 68 | |
48663c56 | 69 | /// Two variables are unified in `sub_relations` when we have a |
cc61c64b XL |
70 | /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second |
71 | /// table exists only to help with the occurs check. In particular, | |
72 | /// we want to report constraints like these as an occurs check | |
73 | /// violation: | |
74 | /// | |
75 | /// ?1 <: ?3 | |
76 | /// Box<?3> <: ?1 | |
77 | /// | |
78 | /// This works because `?1` and `?3` are unified in the | |
79 | /// `sub_relations` relation (not in `eq_relations`). Then when we | |
80 | /// process the `Box<?3> <: ?1` constraint, we do an occurs check | |
81 | /// on `Box<?3>` and find a potential cycle. | |
82 | /// | |
83 | /// This is reasonable because, in Rust, subtypes have the same | |
84 | /// "skeleton" and hence there is no possible type such that | |
85 | /// (e.g.) `Box<?3> <: ?3` for any `?3`. | |
f9f354fc XL |
86 | sub_relations: ut::UnificationTableStorage<ty::TyVid>, |
87 | } | |
88 | ||
89 | pub struct TypeVariableTable<'a, 'tcx> { | |
90 | storage: &'a mut TypeVariableStorage<'tcx>, | |
91 | ||
92 | undo_log: &'a mut InferCtxtUndoLogs<'tcx>, | |
1a4d82fc JJ |
93 | } |
94 | ||
dc9dc135 XL |
95 | #[derive(Copy, Clone, Debug)] |
96 | pub struct TypeVariableOrigin { | |
97 | pub kind: TypeVariableOriginKind, | |
98 | pub span: Span, | |
99 | } | |
100 | ||
476ff2be | 101 | /// Reasons to create a type inference variable |
cc61c64b | 102 | #[derive(Copy, Clone, Debug)] |
dc9dc135 XL |
103 | pub enum TypeVariableOriginKind { |
104 | MiscVariable, | |
105 | NormalizeProjectionType, | |
106 | TypeInference, | |
dfeec247 | 107 | TypeParameterDefinition(Symbol, Option<DefId>), |
ff7c6d11 | 108 | |
dc9dc135 XL |
109 | /// One of the upvars or closure kind parameters in a `ClosureSubsts` |
110 | /// (before it has been determined). | |
ba9703b0 | 111 | // FIXME(eddyb) distinguish upvar inference variables from the rest. |
dc9dc135 XL |
112 | ClosureSynthetic, |
113 | SubstitutionPlaceholder, | |
114 | AutoDeref, | |
115 | AdjustmentType, | |
116 | DivergingFn, | |
117 | LatticeVariable, | |
476ff2be SL |
118 | } |
119 | ||
f9f354fc | 120 | pub(crate) struct TypeVariableData { |
476ff2be | 121 | origin: TypeVariableOrigin, |
a1dfa0c6 | 122 | diverging: bool, |
1a4d82fc JJ |
123 | } |
124 | ||
0531ce1d XL |
125 | #[derive(Copy, Clone, Debug)] |
126 | pub enum TypeVariableValue<'tcx> { | |
127 | Known { value: Ty<'tcx> }, | |
83c7162d | 128 | Unknown { universe: ty::UniverseIndex }, |
c1a9b12d SL |
129 | } |
130 | ||
0531ce1d | 131 | impl<'tcx> TypeVariableValue<'tcx> { |
83c7162d XL |
132 | /// If this value is known, returns the type it is known to be. |
133 | /// Otherwise, `None`. | |
0531ce1d XL |
134 | pub fn known(&self) -> Option<Ty<'tcx>> { |
135 | match *self { | |
136 | TypeVariableValue::Unknown { .. } => None, | |
137 | TypeVariableValue::Known { value } => Some(value), | |
138 | } | |
139 | } | |
140 | ||
141 | pub fn is_unknown(&self) -> bool { | |
142 | match *self { | |
143 | TypeVariableValue::Unknown { .. } => true, | |
144 | TypeVariableValue::Known { .. } => false, | |
145 | } | |
146 | } | |
1a4d82fc JJ |
147 | } |
148 | ||
f9f354fc | 149 | pub(crate) struct Instantiate { |
cc61c64b | 150 | vid: ty::TyVid, |
1a4d82fc JJ |
151 | } |
152 | ||
f9f354fc | 153 | pub(crate) struct Delegate; |
1a4d82fc | 154 | |
f9f354fc XL |
155 | impl<'tcx> TypeVariableStorage<'tcx> { |
156 | pub fn new() -> TypeVariableStorage<'tcx> { | |
157 | TypeVariableStorage { | |
158 | values: sv::SnapshotVecStorage::new(), | |
159 | eq_relations: ut::UnificationTableStorage::new(), | |
160 | sub_relations: ut::UnificationTableStorage::new(), | |
54a0048b | 161 | } |
1a4d82fc JJ |
162 | } |
163 | ||
f9f354fc XL |
164 | #[inline] |
165 | pub(crate) fn with_log<'a>( | |
166 | &'a mut self, | |
167 | undo_log: &'a mut InferCtxtUndoLogs<'tcx>, | |
168 | ) -> TypeVariableTable<'a, 'tcx> { | |
169 | TypeVariableTable { storage: self, undo_log } | |
170 | } | |
171 | } | |
172 | ||
173 | impl<'tcx> TypeVariableTable<'_, 'tcx> { | |
0531ce1d XL |
174 | /// Returns the diverges flag given when `vid` was created. |
175 | /// | |
176 | /// Note that this function does not return care whether | |
177 | /// `vid` has been unified with something else or not. | |
416331ca | 178 | pub fn var_diverges(&self, vid: ty::TyVid) -> bool { |
f9f354fc | 179 | self.storage.values.get(vid.index as usize).diverging |
1a4d82fc JJ |
180 | } |
181 | ||
0531ce1d XL |
182 | /// Returns the origin that was given when `vid` was created. |
183 | /// | |
184 | /// Note that this function does not return care whether | |
185 | /// `vid` has been unified with something else or not. | |
476ff2be | 186 | pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { |
f9f354fc | 187 | &self.storage.values.get(vid.index as usize).origin |
476ff2be SL |
188 | } |
189 | ||
cc61c64b | 190 | /// Records that `a == b`, depending on `dir`. |
1a4d82fc JJ |
191 | /// |
192 | /// Precondition: neither `a` nor `b` are known. | |
cc61c64b | 193 | pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { |
0531ce1d XL |
194 | debug_assert!(self.probe(a).is_unknown()); |
195 | debug_assert!(self.probe(b).is_unknown()); | |
f9f354fc XL |
196 | self.eq_relations().union(a, b); |
197 | self.sub_relations().union(a, b); | |
1a4d82fc JJ |
198 | } |
199 | ||
cc61c64b | 200 | /// Records that `a <: b`, depending on `dir`. |
54a0048b | 201 | /// |
cc61c64b XL |
202 | /// Precondition: neither `a` nor `b` are known. |
203 | pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { | |
0531ce1d XL |
204 | debug_assert!(self.probe(a).is_unknown()); |
205 | debug_assert!(self.probe(b).is_unknown()); | |
f9f354fc | 206 | self.sub_relations().union(a, b); |
cc61c64b XL |
207 | } |
208 | ||
209 | /// Instantiates `vid` with the type `ty`. | |
210 | /// | |
211 | /// Precondition: `vid` must not have been previously instantiated. | |
212 | pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { | |
213 | let vid = self.root_var(vid); | |
0531ce1d | 214 | debug_assert!(self.probe(vid).is_unknown()); |
dfeec247 | 215 | debug_assert!( |
f9f354fc | 216 | self.eq_relations().probe_value(vid).is_unknown(), |
dfeec247 XL |
217 | "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", |
218 | vid, | |
219 | ty, | |
f9f354fc | 220 | self.eq_relations().probe_value(vid) |
dfeec247 | 221 | ); |
f9f354fc | 222 | self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty }); |
0531ce1d XL |
223 | |
224 | // Hack: we only need this so that `types_escaping_snapshot` | |
225 | // can see what has been unified; see the Delegate impl for | |
226 | // more details. | |
f9f354fc | 227 | self.undo_log.push(Instantiate { vid }); |
1a4d82fc JJ |
228 | } |
229 | ||
0531ce1d XL |
230 | /// Creates a new type variable. |
231 | /// | |
232 | /// - `diverging`: indicates if this is a "diverging" type | |
0731742a | 233 | /// variable, e.g., one created as the type of a `return` |
0531ce1d XL |
234 | /// expression. The code in this module doesn't care if a |
235 | /// variable is diverging, but the main Rust type-checker will | |
236 | /// sometimes "unify" such variables with the `!` or `()` types. | |
237 | /// - `origin`: indicates *why* the type variable was created. | |
238 | /// The code in this module doesn't care, but it can be useful | |
239 | /// for improving error messages. | |
dfeec247 XL |
240 | pub fn new_var( |
241 | &mut self, | |
242 | universe: ty::UniverseIndex, | |
243 | diverging: bool, | |
244 | origin: TypeVariableOrigin, | |
245 | ) -> ty::TyVid { | |
f9f354fc | 246 | let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); |
0531ce1d | 247 | |
f9f354fc | 248 | let sub_key = self.sub_relations().new_key(()); |
0531ce1d XL |
249 | assert_eq!(eq_key.vid, sub_key); |
250 | ||
f9f354fc | 251 | let index = self.values().push(TypeVariableData { origin, diverging }); |
0531ce1d XL |
252 | assert_eq!(eq_key.vid.index, index as u32); |
253 | ||
9fa01778 XL |
254 | debug!( |
255 | "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", | |
dfeec247 | 256 | eq_key.vid, universe, diverging, origin, |
9fa01778 | 257 | ); |
0531ce1d XL |
258 | |
259 | eq_key.vid | |
1a4d82fc JJ |
260 | } |
261 | ||
0531ce1d | 262 | /// Returns the number of type variables created thus far. |
476ff2be | 263 | pub fn num_vars(&self) -> usize { |
f9f354fc | 264 | self.storage.values.len() |
476ff2be SL |
265 | } |
266 | ||
cc61c64b XL |
267 | /// Returns the "root" variable of `vid` in the `eq_relations` |
268 | /// equivalence table. All type variables that have been equated | |
269 | /// will yield the same root variable (per the union-find | |
270 | /// algorithm), so `root_var(a) == root_var(b)` implies that `a == | |
271 | /// b` (transitively). | |
54a0048b | 272 | pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { |
f9f354fc | 273 | self.eq_relations().find(vid).vid |
54a0048b SL |
274 | } |
275 | ||
cc61c64b XL |
276 | /// Returns the "root" variable of `vid` in the `sub_relations` |
277 | /// equivalence table. All type variables that have been are | |
278 | /// related via equality or subtyping will yield the same root | |
279 | /// variable (per the union-find algorithm), so `sub_root_var(a) | |
280 | /// == sub_root_var(b)` implies that: | |
281 | /// | |
282 | /// exists X. (a <: X || X <: a) && (b <: X || X <: b) | |
283 | pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { | |
f9f354fc | 284 | self.sub_relations().find(vid) |
cc61c64b XL |
285 | } |
286 | ||
9fa01778 | 287 | /// Returns `true` if `a` and `b` have same "sub-root" (i.e., exists some |
cc61c64b XL |
288 | /// type X such that `forall i in {a, b}. (i <: X || X <: i)`. |
289 | pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool { | |
290 | self.sub_root_var(a) == self.sub_root_var(b) | |
291 | } | |
292 | ||
0531ce1d XL |
293 | /// Retrieves the type to which `vid` has been instantiated, if |
294 | /// any. | |
295 | pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { | |
e74abb32 XL |
296 | self.inlined_probe(vid) |
297 | } | |
298 | ||
299 | /// An always-inlined variant of `probe`, for very hot call sites. | |
300 | #[inline(always)] | |
301 | pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { | |
f9f354fc | 302 | self.eq_relations().inlined_probe_value(vid) |
1a4d82fc JJ |
303 | } |
304 | ||
0531ce1d XL |
305 | /// If `t` is a type-inference variable, and it has been |
306 | /// instantiated, then return the with which it was | |
307 | /// instantiated. Otherwise, returns `t`. | |
54a0048b | 308 | pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { |
e74abb32 | 309 | match t.kind { |
dfeec247 XL |
310 | ty::Infer(ty::TyVar(v)) => match self.probe(v) { |
311 | TypeVariableValue::Unknown { .. } => t, | |
312 | TypeVariableValue::Known { value } => value, | |
313 | }, | |
1a4d82fc JJ |
314 | _ => t, |
315 | } | |
316 | } | |
317 | ||
f9f354fc XL |
318 | #[inline] |
319 | fn values( | |
320 | &mut self, | |
321 | ) -> sv::SnapshotVec<Delegate, &mut Vec<TypeVariableData>, &mut InferCtxtUndoLogs<'tcx>> { | |
322 | self.storage.values.with_log(self.undo_log) | |
1a4d82fc JJ |
323 | } |
324 | ||
f9f354fc XL |
325 | #[inline] |
326 | fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> { | |
327 | self.storage.eq_relations.with_log(self.undo_log) | |
1a4d82fc JJ |
328 | } |
329 | ||
f9f354fc XL |
330 | #[inline] |
331 | fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> { | |
332 | self.storage.sub_relations.with_log(self.undo_log) | |
cc61c64b XL |
333 | } |
334 | ||
532ac7d7 XL |
335 | /// Returns a range of the type variables created during the snapshot. |
336 | pub fn vars_since_snapshot( | |
337 | &mut self, | |
f9f354fc | 338 | value_count: usize, |
532ac7d7 | 339 | ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) { |
f9f354fc | 340 | let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 }; |
dfeec247 | 341 | ( |
f9f354fc XL |
342 | range.start..range.end, |
343 | (range.start.index..range.end.index) | |
344 | .map(|index| self.storage.values.get(index as usize).origin) | |
dfeec247 XL |
345 | .collect(), |
346 | ) | |
1a4d82fc JJ |
347 | } |
348 | ||
9fa01778 | 349 | /// Finds the set of type variables that existed *before* `s` |
0531ce1d XL |
350 | /// but which have only been unified since `s` started, and |
351 | /// return the types with which they were unified. So if we had | |
352 | /// a type variable `V0`, then we started the snapshot, then we | |
a1dfa0c6 | 353 | /// created a type variable `V1`, unified `V0` with `T0`, and |
0531ce1d | 354 | /// unified `V1` with `T1`, this function would return `{T0}`. |
f9f354fc | 355 | pub fn types_escaping_snapshot(&mut self, s: &super::Snapshot<'tcx>) -> Vec<Ty<'tcx>> { |
1a4d82fc JJ |
356 | let mut new_elem_threshold = u32::MAX; |
357 | let mut escaping_types = Vec::new(); | |
f9f354fc | 358 | let actions_since_snapshot = self.undo_log.actions_since_snapshot(s); |
1a4d82fc | 359 | debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); |
f9f354fc XL |
360 | for i in 0..actions_since_snapshot.len() { |
361 | let actions_since_snapshot = self.undo_log.actions_since_snapshot(s); | |
362 | match actions_since_snapshot[i] { | |
363 | super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::NewElem(index))) => { | |
1a4d82fc JJ |
364 | // if any new variables were created during the |
365 | // snapshot, remember the lower index (which will | |
366 | // always be the first one we see). Note that this | |
367 | // action must precede those variables being | |
368 | // specified. | |
0531ce1d | 369 | new_elem_threshold = cmp::min(new_elem_threshold, index as u32); |
1a4d82fc JJ |
370 | debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); |
371 | } | |
372 | ||
f9f354fc XL |
373 | super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::Other( |
374 | Instantiate { vid, .. }, | |
375 | ))) => { | |
1a4d82fc JJ |
376 | if vid.index < new_elem_threshold { |
377 | // quick check to see if this variable was | |
378 | // created since the snapshot started or not. | |
f9f354fc XL |
379 | let mut eq_relations = ut::UnificationTable::with_log( |
380 | &mut self.storage.eq_relations, | |
381 | &mut *self.undo_log, | |
382 | ); | |
383 | let escaping_type = match eq_relations.probe_value(vid) { | |
0531ce1d XL |
384 | TypeVariableValue::Unknown { .. } => bug!(), |
385 | TypeVariableValue::Known { value } => value, | |
54a0048b | 386 | }; |
1a4d82fc JJ |
387 | escaping_types.push(escaping_type); |
388 | } | |
389 | debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold); | |
390 | } | |
391 | ||
dfeec247 | 392 | _ => {} |
1a4d82fc JJ |
393 | } |
394 | } | |
395 | ||
396 | escaping_types | |
397 | } | |
c1a9b12d | 398 | |
0531ce1d XL |
399 | /// Returns indices of all variables that are not yet |
400 | /// instantiated. | |
54a0048b | 401 | pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> { |
f9f354fc | 402 | (0..self.storage.values.len()) |
54a0048b SL |
403 | .filter_map(|i| { |
404 | let vid = ty::TyVid { index: i as u32 }; | |
0531ce1d XL |
405 | match self.probe(vid) { |
406 | TypeVariableValue::Unknown { .. } => Some(vid), | |
407 | TypeVariableValue::Known { .. } => None, | |
54a0048b | 408 | } |
c1a9b12d SL |
409 | }) |
410 | .collect() | |
411 | } | |
1a4d82fc JJ |
412 | } |
413 | ||
0531ce1d XL |
414 | impl sv::SnapshotVecDelegate for Delegate { |
415 | type Value = TypeVariableData; | |
416 | type Undo = Instantiate; | |
417 | ||
418 | fn reverse(_values: &mut Vec<TypeVariableData>, _action: Instantiate) { | |
419 | // We don't actually have to *do* anything to reverse an | |
48663c56 | 420 | // instantiation; the value for a variable is stored in the |
0531ce1d XL |
421 | // `eq_relations` and hence its rollback code will handle |
422 | // it. In fact, we could *almost* just remove the | |
423 | // `SnapshotVec` entirely, except that we would have to | |
424 | // reproduce *some* of its logic, since we want to know which | |
425 | // type variables have been instantiated since the snapshot | |
426 | // was started, so we can implement `types_escaping_snapshot`. | |
427 | // | |
428 | // (If we extended the `UnificationTable` to let us see which | |
429 | // values have been unified and so forth, that might also | |
430 | // suffice.) | |
431 | } | |
432 | } | |
433 | ||
434 | /////////////////////////////////////////////////////////////////////////// | |
435 | ||
436 | /// These structs (a newtyped TyVid) are used as the unification key | |
437 | /// for the `eq_relations`; they carry a `TypeVariableValue` along | |
438 | /// with them. | |
439 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | |
f9f354fc | 440 | pub(crate) struct TyVidEqKey<'tcx> { |
0531ce1d XL |
441 | vid: ty::TyVid, |
442 | ||
443 | // in the table, we map each ty-vid to one of these: | |
444 | phantom: PhantomData<TypeVariableValue<'tcx>>, | |
445 | } | |
446 | ||
447 | impl<'tcx> From<ty::TyVid> for TyVidEqKey<'tcx> { | |
448 | fn from(vid: ty::TyVid) -> Self { | |
449 | TyVidEqKey { vid, phantom: PhantomData } | |
450 | } | |
451 | } | |
452 | ||
453 | impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { | |
454 | type Value = TypeVariableValue<'tcx>; | |
dfeec247 XL |
455 | fn index(&self) -> u32 { |
456 | self.vid.index | |
457 | } | |
458 | fn from_index(i: u32) -> Self { | |
459 | TyVidEqKey::from(ty::TyVid { index: i }) | |
460 | } | |
461 | fn tag() -> &'static str { | |
462 | "TyVidEqKey" | |
463 | } | |
0531ce1d XL |
464 | } |
465 | ||
466 | impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { | |
467 | type Error = ut::NoError; | |
468 | ||
469 | fn unify_values(value1: &Self, value2: &Self) -> Result<Self, ut::NoError> { | |
470 | match (value1, value2) { | |
471 | // We never equate two type variables, both of which | |
472 | // have known types. Instead, we recursively equate | |
473 | // those types. | |
474 | (&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => { | |
475 | bug!("equating two type variables, both of which have known types") | |
476 | } | |
477 | ||
478 | // If one side is known, prefer that one. | |
479 | (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => Ok(*value1), | |
480 | (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => Ok(*value2), | |
1a4d82fc | 481 | |
0531ce1d | 482 | // If both sides are *unknown*, it hardly matters, does it? |
dfeec247 XL |
483 | ( |
484 | &TypeVariableValue::Unknown { universe: universe1 }, | |
485 | &TypeVariableValue::Unknown { universe: universe2 }, | |
486 | ) => { | |
83c7162d XL |
487 | // If we unify two unbound variables, ?T and ?U, then whatever |
488 | // value they wind up taking (which must be the same value) must | |
489 | // be nameable by both universes. Therefore, the resulting | |
490 | // universe is the minimum of the two universes, because that is | |
491 | // the one which contains the fewest names in scope. | |
492 | let universe = cmp::min(universe1, universe2); | |
493 | Ok(TypeVariableValue::Unknown { universe }) | |
494 | } | |
0531ce1d | 495 | } |
1a4d82fc JJ |
496 | } |
497 | } |