]> git.lizzy.rs Git - rust.git/blob - src/librustc_infer/infer/equate.rs
perf: Reduce snapshot/rollback overhead
[rust.git] / src / librustc_infer / infer / equate.rs
1 use super::combine::{CombineFields, RelationDir};
2 use super::Subtype;
3
4 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
5 use rustc_middle::ty::subst::SubstsRef;
6 use rustc_middle::ty::TyVar;
7 use rustc_middle::ty::{self, Ty, TyCtxt};
8
9 use rustc_hir::def_id::DefId;
10
11 /// Ensures `a` is made equal to `b`. Returns `a` on success.
12 pub struct Equate<'combine, 'infcx, 'tcx> {
13     fields: &'combine mut CombineFields<'infcx, 'tcx>,
14     a_is_expected: bool,
15 }
16
17 impl<'combine, 'infcx, 'tcx> Equate<'combine, 'infcx, 'tcx> {
18     pub fn new(
19         fields: &'combine mut CombineFields<'infcx, 'tcx>,
20         a_is_expected: bool,
21     ) -> Equate<'combine, 'infcx, 'tcx> {
22         Equate { fields, a_is_expected }
23     }
24 }
25
26 impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
27     fn tag(&self) -> &'static str {
28         "Equate"
29     }
30
31     fn tcx(&self) -> TyCtxt<'tcx> {
32         self.fields.tcx()
33     }
34
35     fn param_env(&self) -> ty::ParamEnv<'tcx> {
36         self.fields.param_env
37     }
38
39     fn a_is_expected(&self) -> bool {
40         self.a_is_expected
41     }
42
43     fn relate_item_substs(
44         &mut self,
45         _item_def_id: DefId,
46         a_subst: SubstsRef<'tcx>,
47         b_subst: SubstsRef<'tcx>,
48     ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
49         // N.B., once we are equating types, we don't care about
50         // variance, so don't try to lookup the variance here. This
51         // also avoids some cycles (e.g., #41849) since looking up
52         // variance requires computing types which can require
53         // performing trait matching (which then performs equality
54         // unification).
55
56         relate::relate_substs(self, None, a_subst, b_subst)
57     }
58
59     fn relate_with_variance<T: Relate<'tcx>>(
60         &mut self,
61         _: ty::Variance,
62         a: &T,
63         b: &T,
64     ) -> RelateResult<'tcx, T> {
65         self.relate(a, b)
66     }
67
68     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
69         debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
70         if a == b {
71             return Ok(a);
72         }
73
74         let infcx = self.fields.infcx;
75         let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
76         let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
77
78         debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b);
79
80         match (&a.kind, &b.kind) {
81             (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
82                 infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
83             }
84
85             (&ty::Infer(TyVar(a_id)), _) => {
86                 self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?;
87             }
88
89             (_, &ty::Infer(TyVar(b_id))) => {
90                 self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
91             }
92
93             _ => {
94                 self.fields.infcx.super_combine_tys(self, a, b)?;
95             }
96         }
97
98         Ok(a)
99     }
100
101     fn regions(
102         &mut self,
103         a: ty::Region<'tcx>,
104         b: ty::Region<'tcx>,
105     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
106         debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
107         let origin = Subtype(box self.fields.trace.clone());
108         self.fields
109             .infcx
110             .inner
111             .borrow_mut()
112             .unwrap_region_constraints()
113             .make_eqregion(origin, a, b);
114         Ok(a)
115     }
116
117     fn consts(
118         &mut self,
119         a: &'tcx ty::Const<'tcx>,
120         b: &'tcx ty::Const<'tcx>,
121     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
122         self.fields.infcx.super_combine_consts(self, a, b)
123     }
124
125     fn binders<T>(
126         &mut self,
127         a: &ty::Binder<T>,
128         b: &ty::Binder<T>,
129     ) -> RelateResult<'tcx, ty::Binder<T>>
130     where
131         T: Relate<'tcx>,
132     {
133         if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
134             self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
135             self.fields.higher_ranked_sub(b, a, self.a_is_expected)
136         } else {
137             // Fast path for the common case.
138             self.relate(a.skip_binder(), b.skip_binder())?;
139             Ok(a.clone())
140         }
141     }
142 }