rustc_trait_selection/error_reporting/infer/
sub_relations.rs

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}