]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/sub.rs
b285d59729110706964e151360e6e126a67a1a3b
[rust.git] / src / librustc / infer / sub.rs
1 use super::SubregionOrigin;
2 use super::combine::{CombineFields, RelationDir, const_unification_error};
3
4 use crate::traits::Obligation;
5 use crate::ty::{self, Ty, TyCtxt, InferConst};
6 use crate::ty::TyVar;
7 use crate::ty::fold::TypeFoldable;
8 use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
9 use crate::mir::interpret::ConstValue;
10 use std::mem;
11
12 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
13 pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
14     fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
15     a_is_expected: bool,
16 }
17
18 impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> {
19     pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
20         -> Sub<'combine, 'infcx, 'gcx, 'tcx>
21     {
22         Sub { fields: f, a_is_expected: a_is_expected }
23     }
24
25     fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
26         self.a_is_expected = !self.a_is_expected;
27         let result = f(self);
28         self.a_is_expected = !self.a_is_expected;
29         result
30     }
31 }
32
33 impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
34     for Sub<'combine, 'infcx, 'gcx, 'tcx>
35 {
36     fn tag(&self) -> &'static str { "Sub" }
37     fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx }
38     fn a_is_expected(&self) -> bool { self.a_is_expected }
39
40     fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
41         where F: FnOnce(&mut Self) -> R
42     {
43         debug!("sub with_cause={:?}", cause);
44         let old_cause = mem::replace(&mut self.fields.cause, Some(cause));
45         let r = f(self);
46         debug!("sub old_cause={:?}", old_cause);
47         self.fields.cause = old_cause;
48         r
49     }
50
51     fn relate_with_variance<T: Relate<'tcx>>(&mut self,
52                                              variance: ty::Variance,
53                                              a: &T,
54                                              b: &T)
55                                              -> RelateResult<'tcx, T>
56     {
57         match variance {
58             ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
59             ty::Covariant => self.relate(a, b),
60             ty::Bivariant => Ok(a.clone()),
61             ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }),
62         }
63     }
64
65     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
66         debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
67
68         if a == b { return Ok(a); }
69
70         let infcx = self.fields.infcx;
71         let a = infcx.type_variables.borrow_mut().replace_if_possible(a);
72         let b = infcx.type_variables.borrow_mut().replace_if_possible(b);
73         match (&a.sty, &b.sty) {
74             (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => {
75                 // Shouldn't have any LBR here, so we can safely put
76                 // this under a binder below without fear of accidental
77                 // capture.
78                 assert!(!a.has_escaping_bound_vars());
79                 assert!(!b.has_escaping_bound_vars());
80
81                 // can't make progress on `A <: B` if both A and B are
82                 // type variables, so record an obligation. We also
83                 // have to record in the `type_variables` tracker that
84                 // the two variables are equal modulo subtyping, which
85                 // is important to the occurs check later on.
86                 infcx.type_variables.borrow_mut().sub(a_vid, b_vid);
87                 self.fields.obligations.push(
88                     Obligation::new(
89                         self.fields.trace.cause.clone(),
90                         self.fields.param_env,
91                         ty::Predicate::Subtype(
92                             ty::Binder::dummy(ty::SubtypePredicate {
93                                 a_is_expected: self.a_is_expected,
94                                 a,
95                                 b,
96                             }))));
97
98                 Ok(a)
99             }
100             (&ty::Infer(TyVar(a_id)), _) => {
101                 self.fields
102                     .instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?;
103                 Ok(a)
104             }
105             (_, &ty::Infer(TyVar(b_id))) => {
106                 self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?;
107                 Ok(a)
108             }
109
110             (&ty::Error, _) | (_, &ty::Error) => {
111                 infcx.set_tainted_by_errors();
112                 Ok(self.tcx().types.err)
113             }
114
115             _ => {
116                 self.fields.infcx.super_combine_tys(self, a, b)?;
117                 Ok(a)
118             }
119         }
120     }
121
122     fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
123                -> RelateResult<'tcx, ty::Region<'tcx>> {
124         debug!("{}.regions({:?}, {:?}) self.cause={:?}",
125                self.tag(), a, b, self.fields.cause);
126
127         // FIXME -- we have more fine-grained information available
128         // from the "cause" field, we could perhaps give more tailored
129         // error messages.
130         let origin = SubregionOrigin::Subtype(self.fields.trace.clone());
131         self.fields.infcx.borrow_region_constraints()
132                          .make_subregion(origin, a, b);
133
134         Ok(a)
135     }
136
137     fn consts(
138         &mut self,
139         a: &'tcx ty::LazyConst<'tcx>,
140         b: &'tcx ty::LazyConst<'tcx>,
141     ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
142         debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
143         if a == b { return Ok(a); }
144
145         let infcx = self.fields.infcx;
146         let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a);
147         let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b);
148
149         // Consts can only be equal or unequal to each other: there's no subtyping
150         // relation, so we're just going to perform equating here instead.
151         let a_is_expected = self.a_is_expected();
152         if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) {
153             match (a_eval.val, b_eval.val) {
154                 (ConstValue::Infer(InferConst::Var(a_vid)),
155                  ConstValue::Infer(InferConst::Var(b_vid))) => {
156                     infcx.const_unification_table
157                         .borrow_mut()
158                         .unify_var_var(a_vid, b_vid)
159                         .map_err(|e| const_unification_error(a_is_expected, e))?;
160                     return Ok(a);
161                 }
162
163                 (ConstValue::Infer(InferConst::Var(a_id)), _) => {
164                     self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?;
165                     return Ok(a);
166                 }
167
168                 (_, ConstValue::Infer(InferConst::Var(b_id))) => {
169                     self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?;
170                     return Ok(a);
171                 }
172
173                 _ => {}
174             }
175         }
176
177         self.fields.infcx.super_combine_consts(self, a, b)?;
178         Ok(a)
179     }
180
181     fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
182                   -> RelateResult<'tcx, ty::Binder<T>>
183         where T: Relate<'tcx>
184     {
185         self.fields.higher_ranked_sub(a, b, self.a_is_expected)
186     }
187 }