]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs
bump version to 1.79.0+dfsg1-1~bpo12+pve2
[rustc.git] / compiler / rustc_infer / src / infer / error_reporting / sub_relations.rs
CommitLineData
c620b35d
FG
1use rustc_data_structures::fx::FxHashMap;
2use rustc_data_structures::undo_log::NoUndo;
3use rustc_data_structures::unify as ut;
4use rustc_middle::ty;
5
6use crate::infer::InferCtxt;
7
8#[derive(Debug, Copy, Clone, PartialEq)]
9struct SubId(u32);
10impl 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)]
40pub struct SubRelations {
41 map: FxHashMap<ty::TyVid, SubId>,
42 table: ut::UnificationTableStorage<SubId>,
43}
44
45impl 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}