]>
Commit | Line | Data |
---|---|---|
62682a34 | 1 | use super::SubregionOrigin; |
cc61c64b | 2 | use super::combine::{CombineFields, RelationDir}; |
1a4d82fc | 3 | |
9fa01778 XL |
4 | use crate::traits::Obligation; |
5 | use crate::ty::{self, Ty, TyCtxt}; | |
6 | use crate::ty::TyVar; | |
7 | use crate::ty::fold::TypeFoldable; | |
8 | use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; | |
62682a34 | 9 | use std::mem; |
1a4d82fc | 10 | |
b039eaaf | 11 | /// Ensures `a` is made a subtype of `b`. Returns `a` on success. |
5bcae85e SL |
12 | pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { |
13 | fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, | |
14 | a_is_expected: bool, | |
1a4d82fc JJ |
15 | } |
16 | ||
5bcae85e SL |
17 | impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> { |
18 | pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) | |
19 | -> Sub<'combine, 'infcx, 'gcx, 'tcx> | |
20 | { | |
21 | Sub { fields: f, a_is_expected: a_is_expected } | |
c34b1796 | 22 | } |
54a0048b | 23 | |
5bcae85e SL |
24 | fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R { |
25 | self.a_is_expected = !self.a_is_expected; | |
26 | let result = f(self); | |
27 | self.a_is_expected = !self.a_is_expected; | |
28 | result | |
54a0048b | 29 | } |
1a4d82fc JJ |
30 | } |
31 | ||
5bcae85e SL |
32 | impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> |
33 | for Sub<'combine, 'infcx, 'gcx, 'tcx> | |
34 | { | |
c34b1796 | 35 | fn tag(&self) -> &'static str { "Sub" } |
5bcae85e SL |
36 | fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx } |
37 | fn a_is_expected(&self) -> bool { self.a_is_expected } | |
85aaf69f | 38 | |
62682a34 SL |
39 | fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R |
40 | where F: FnOnce(&mut Self) -> R | |
41 | { | |
42 | debug!("sub with_cause={:?}", cause); | |
43 | let old_cause = mem::replace(&mut self.fields.cause, Some(cause)); | |
44 | let r = f(self); | |
45 | debug!("sub old_cause={:?}", old_cause); | |
46 | self.fields.cause = old_cause; | |
47 | r | |
48 | } | |
49 | ||
a7813a04 XL |
50 | fn relate_with_variance<T: Relate<'tcx>>(&mut self, |
51 | variance: ty::Variance, | |
52 | a: &T, | |
53 | b: &T) | |
54 | -> RelateResult<'tcx, T> | |
85aaf69f | 55 | { |
c34b1796 | 56 | match variance { |
5bcae85e | 57 | ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), |
c34b1796 | 58 | ty::Covariant => self.relate(a, b), |
cc61c64b | 59 | ty::Bivariant => Ok(a.clone()), |
5bcae85e | 60 | ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), |
85aaf69f | 61 | } |
1a4d82fc JJ |
62 | } |
63 | ||
c34b1796 | 64 | fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { |
62682a34 | 65 | debug!("{}.tys({:?}, {:?})", self.tag(), a, b); |
1a4d82fc | 66 | |
1a4d82fc JJ |
67 | if a == b { return Ok(a); } |
68 | ||
69 | let infcx = self.fields.infcx; | |
54a0048b SL |
70 | let a = infcx.type_variables.borrow_mut().replace_if_possible(a); |
71 | let b = infcx.type_variables.borrow_mut().replace_if_possible(b); | |
1a4d82fc | 72 | match (&a.sty, &b.sty) { |
b7449926 | 73 | (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { |
cc61c64b XL |
74 | // Shouldn't have any LBR here, so we can safely put |
75 | // this under a binder below without fear of accidental | |
76 | // capture. | |
a1dfa0c6 XL |
77 | assert!(!a.has_escaping_bound_vars()); |
78 | assert!(!b.has_escaping_bound_vars()); | |
cc61c64b XL |
79 | |
80 | // can't make progress on `A <: B` if both A and B are | |
81 | // type variables, so record an obligation. We also | |
82 | // have to record in the `type_variables` tracker that | |
83 | // the two variables are equal modulo subtyping, which | |
84 | // is important to the occurs check later on. | |
85 | infcx.type_variables.borrow_mut().sub(a_vid, b_vid); | |
86 | self.fields.obligations.push( | |
87 | Obligation::new( | |
88 | self.fields.trace.cause.clone(), | |
7cac9316 | 89 | self.fields.param_env, |
cc61c64b | 90 | ty::Predicate::Subtype( |
83c7162d | 91 | ty::Binder::dummy(ty::SubtypePredicate { |
cc61c64b XL |
92 | a_is_expected: self.a_is_expected, |
93 | a, | |
94 | b, | |
95 | })))); | |
96 | ||
1a4d82fc JJ |
97 | Ok(a) |
98 | } | |
b7449926 | 99 | (&ty::Infer(TyVar(a_id)), _) => { |
54a0048b | 100 | self.fields |
cc61c64b | 101 | .instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; |
1a4d82fc JJ |
102 | Ok(a) |
103 | } | |
b7449926 | 104 | (_, &ty::Infer(TyVar(b_id))) => { |
cc61c64b | 105 | self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; |
1a4d82fc JJ |
106 | Ok(a) |
107 | } | |
108 | ||
b7449926 | 109 | (&ty::Error, _) | (_, &ty::Error) => { |
a7813a04 | 110 | infcx.set_tainted_by_errors(); |
1a4d82fc JJ |
111 | Ok(self.tcx().types.err) |
112 | } | |
113 | ||
114 | _ => { | |
a7813a04 | 115 | self.fields.infcx.super_combine_tys(self, a, b)?; |
b039eaaf | 116 | Ok(a) |
1a4d82fc JJ |
117 | } |
118 | } | |
119 | } | |
120 | ||
7cac9316 XL |
121 | fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) |
122 | -> RelateResult<'tcx, ty::Region<'tcx>> { | |
62682a34 SL |
123 | debug!("{}.regions({:?}, {:?}) self.cause={:?}", |
124 | self.tag(), a, b, self.fields.cause); | |
476ff2be | 125 | |
c1a9b12d SL |
126 | // FIXME -- we have more fine-grained information available |
127 | // from the "cause" field, we could perhaps give more tailored | |
128 | // error messages. | |
129 | let origin = SubregionOrigin::Subtype(self.fields.trace.clone()); | |
abe05a73 XL |
130 | self.fields.infcx.borrow_region_constraints() |
131 | .make_subregion(origin, a, b); | |
476ff2be | 132 | |
c34b1796 AL |
133 | Ok(a) |
134 | } | |
135 | ||
136 | fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>) | |
137 | -> RelateResult<'tcx, ty::Binder<T>> | |
a7813a04 | 138 | where T: Relate<'tcx> |
1a4d82fc | 139 | { |
5bcae85e | 140 | self.fields.higher_ranked_sub(a, b, self.a_is_expected) |
1a4d82fc JJ |
141 | } |
142 | } |