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