]>
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 | ||
a7813a04 | 11 | use super::combine::CombineFields; |
62682a34 | 12 | use super::SubregionOrigin; |
1a4d82fc JJ |
13 | use super::type_variable::{SubtypeOf, SupertypeOf}; |
14 | ||
54a0048b SL |
15 | use ty::{self, Ty, TyCtxt}; |
16 | use ty::TyVar; | |
17 | use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; | |
62682a34 | 18 | use std::mem; |
1a4d82fc | 19 | |
b039eaaf | 20 | /// Ensures `a` is made a subtype of `b`. Returns `a` on success. |
5bcae85e SL |
21 | pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { |
22 | fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, | |
23 | a_is_expected: bool, | |
1a4d82fc JJ |
24 | } |
25 | ||
5bcae85e SL |
26 | impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> { |
27 | pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) | |
28 | -> Sub<'combine, 'infcx, 'gcx, 'tcx> | |
29 | { | |
30 | Sub { fields: f, a_is_expected: a_is_expected } | |
c34b1796 | 31 | } |
54a0048b | 32 | |
5bcae85e SL |
33 | fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R { |
34 | self.a_is_expected = !self.a_is_expected; | |
35 | let result = f(self); | |
36 | self.a_is_expected = !self.a_is_expected; | |
37 | result | |
54a0048b | 38 | } |
1a4d82fc JJ |
39 | } |
40 | ||
5bcae85e SL |
41 | impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> |
42 | for Sub<'combine, 'infcx, 'gcx, 'tcx> | |
43 | { | |
c34b1796 | 44 | fn tag(&self) -> &'static str { "Sub" } |
5bcae85e SL |
45 | fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx } |
46 | fn a_is_expected(&self) -> bool { self.a_is_expected } | |
85aaf69f | 47 | |
62682a34 SL |
48 | fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R |
49 | where F: FnOnce(&mut Self) -> R | |
50 | { | |
51 | debug!("sub with_cause={:?}", cause); | |
52 | let old_cause = mem::replace(&mut self.fields.cause, Some(cause)); | |
53 | let r = f(self); | |
54 | debug!("sub old_cause={:?}", old_cause); | |
55 | self.fields.cause = old_cause; | |
56 | r | |
57 | } | |
58 | ||
a7813a04 XL |
59 | fn relate_with_variance<T: Relate<'tcx>>(&mut self, |
60 | variance: ty::Variance, | |
61 | a: &T, | |
62 | b: &T) | |
63 | -> RelateResult<'tcx, T> | |
85aaf69f | 64 | { |
c34b1796 | 65 | match variance { |
5bcae85e | 66 | ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), |
c34b1796 | 67 | ty::Covariant => self.relate(a, b), |
5bcae85e SL |
68 | ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), |
69 | ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), | |
85aaf69f | 70 | } |
1a4d82fc JJ |
71 | } |
72 | ||
c34b1796 | 73 | fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { |
62682a34 | 74 | debug!("{}.tys({:?}, {:?})", self.tag(), a, b); |
1a4d82fc | 75 | |
1a4d82fc JJ |
76 | if a == b { return Ok(a); } |
77 | ||
78 | let infcx = self.fields.infcx; | |
54a0048b SL |
79 | let a = infcx.type_variables.borrow_mut().replace_if_possible(a); |
80 | let b = infcx.type_variables.borrow_mut().replace_if_possible(b); | |
1a4d82fc | 81 | match (&a.sty, &b.sty) { |
62682a34 | 82 | (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { |
1a4d82fc JJ |
83 | infcx.type_variables |
84 | .borrow_mut() | |
85 | .relate_vars(a_id, SubtypeOf, b_id); | |
86 | Ok(a) | |
87 | } | |
62682a34 | 88 | (&ty::TyInfer(TyVar(a_id)), _) => { |
54a0048b | 89 | self.fields |
5bcae85e | 90 | .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?; |
1a4d82fc JJ |
91 | Ok(a) |
92 | } | |
62682a34 | 93 | (_, &ty::TyInfer(TyVar(b_id))) => { |
5bcae85e | 94 | self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?; |
1a4d82fc JJ |
95 | Ok(a) |
96 | } | |
97 | ||
62682a34 | 98 | (&ty::TyError, _) | (_, &ty::TyError) => { |
a7813a04 | 99 | infcx.set_tainted_by_errors(); |
1a4d82fc JJ |
100 | Ok(self.tcx().types.err) |
101 | } | |
102 | ||
103 | _ => { | |
a7813a04 | 104 | self.fields.infcx.super_combine_tys(self, a, b)?; |
b039eaaf | 105 | Ok(a) |
1a4d82fc JJ |
106 | } |
107 | } | |
108 | } | |
109 | ||
9e0c209e SL |
110 | fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) |
111 | -> RelateResult<'tcx, &'tcx ty::Region> { | |
62682a34 SL |
112 | debug!("{}.regions({:?}, {:?}) self.cause={:?}", |
113 | self.tag(), a, b, self.fields.cause); | |
c1a9b12d SL |
114 | // FIXME -- we have more fine-grained information available |
115 | // from the "cause" field, we could perhaps give more tailored | |
116 | // error messages. | |
117 | let origin = SubregionOrigin::Subtype(self.fields.trace.clone()); | |
c34b1796 AL |
118 | self.fields.infcx.region_vars.make_subregion(origin, a, b); |
119 | Ok(a) | |
120 | } | |
121 | ||
122 | fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>) | |
123 | -> RelateResult<'tcx, ty::Binder<T>> | |
a7813a04 | 124 | where T: Relate<'tcx> |
1a4d82fc | 125 | { |
5bcae85e | 126 | self.fields.higher_ranked_sub(a, b, self.a_is_expected) |
1a4d82fc JJ |
127 | } |
128 | } |