]>
Commit | Line | Data |
---|---|---|
c620b35d FG |
1 | use rustc_data_structures::fx::FxHashMap; |
2 | use rustc_data_structures::undo_log::NoUndo; | |
3 | use rustc_data_structures::unify as ut; | |
4 | use rustc_middle::ty; | |
5 | ||
6 | use crate::infer::InferCtxt; | |
7 | ||
8 | #[derive(Debug, Copy, Clone, PartialEq)] | |
9 | struct SubId(u32); | |
10 | impl ut::UnifyKey for SubId { | |
11 | type Value = (); | |
12 | #[inline] | |
13 | fn index(&self) -> u32 { | |
14 | self.0 | |
15 | } | |
16 | #[inline] | |
17 | fn from_index(i: u32) -> SubId { | |
18 | SubId(i) | |
19 | } | |
20 | fn tag() -> &'static str { | |
21 | "SubId" | |
22 | } | |
23 | } | |
24 | ||
25 | /// When reporting ambiguity errors, we sometimes want to | |
26 | /// treat all inference vars which are subtypes of each | |
27 | /// others as if they are equal. For this case we compute | |
28 | /// the transitive closure of our subtype obligations here. | |
29 | /// | |
30 | /// E.g. when encountering ambiguity errors, we want to suggest | |
31 | /// specifying some method argument or to add a type annotation | |
32 | /// to a local variable. Because subtyping cannot change the | |
33 | /// shape of a type, it's fine if the cause of the ambiguity error | |
34 | /// is only related to the suggested variable via subtyping. | |
35 | /// | |
36 | /// Even for something like `let x = returns_arg(); x.method();` the | |
37 | /// type of `x` is only a supertype of the argument of `returns_arg`. We | |
38 | /// still want to suggest specifying the type of the argument. | |
39 | #[derive(Default)] | |
40 | pub struct SubRelations { | |
41 | map: FxHashMap<ty::TyVid, SubId>, | |
42 | table: ut::UnificationTableStorage<SubId>, | |
43 | } | |
44 | ||
45 | impl SubRelations { | |
46 | fn get_id<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, vid: ty::TyVid) -> SubId { | |
47 | let root_vid = infcx.root_var(vid); | |
48 | *self.map.entry(root_vid).or_insert_with(|| self.table.with_log(&mut NoUndo).new_key(())) | |
49 | } | |
50 | ||
51 | pub fn add_constraints<'tcx>( | |
52 | &mut self, | |
53 | infcx: &InferCtxt<'tcx>, | |
54 | obls: impl IntoIterator<Item = ty::Predicate<'tcx>>, | |
55 | ) { | |
56 | for p in obls { | |
57 | let (a, b) = match p.kind().skip_binder() { | |
58 | ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { | |
59 | (a, b) | |
60 | } | |
61 | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b), | |
62 | _ => continue, | |
63 | }; | |
64 | ||
65 | match (a.kind(), b.kind()) { | |
66 | (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { | |
67 | let a = self.get_id(infcx, a_vid); | |
68 | let b = self.get_id(infcx, b_vid); | |
69 | self.table.with_log(&mut NoUndo).unify_var_var(a, b).unwrap(); | |
70 | } | |
71 | _ => continue, | |
72 | } | |
73 | } | |
74 | } | |
75 | ||
76 | pub fn unified<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, a: ty::TyVid, b: ty::TyVid) -> bool { | |
77 | let a = self.get_id(infcx, a); | |
78 | let b = self.get_id(infcx, b); | |
79 | self.table.with_log(&mut NoUndo).unioned(a, b) | |
80 | } | |
81 | } |