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.
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.
11 use super::SubregionOrigin
;
12 use super::combine
::CombineFields
;
13 use super::type_variable
::{SubtypeOf, SupertypeOf}
;
15 use ty
::{self, Ty, TyCtxt}
;
17 use ty
::relate
::{Cause, Relate, RelateResult, TypeRelation}
;
20 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
21 pub struct Sub
<'combine
, 'infcx
: 'combine
, 'gcx
: 'infcx
+'tcx
, 'tcx
: 'infcx
> {
22 fields
: &'combine
mut CombineFields
<'infcx
, 'gcx
, 'tcx
>,
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
>
30 Sub { fields: f, a_is_expected: a_is_expected }
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
;
36 self.a_is_expected
= !self.a_is_expected
;
41 impl<'combine
, 'infcx
, 'gcx
, 'tcx
> TypeRelation
<'infcx
, 'gcx
, 'tcx
>
42 for Sub
<'combine
, 'infcx
, 'gcx
, 'tcx
>
44 fn tag(&self) -> &'
static str { "Sub" }
45 fn tcx(&self) -> TyCtxt
<'infcx
, 'gcx
, 'tcx
> { self.fields.infcx.tcx }
46 fn a_is_expected(&self) -> bool { self.a_is_expected }
48 fn with_cause
<F
,R
>(&mut self, cause
: Cause
, f
: F
) -> R
49 where F
: FnOnce(&mut Self) -> R
51 debug
!("sub with_cause={:?}", cause
);
52 let old_cause
= mem
::replace(&mut self.fields
.cause
, Some(cause
));
54 debug
!("sub old_cause={:?}", old_cause
);
55 self.fields
.cause
= old_cause
;
59 fn relate_with_variance
<T
: Relate
<'tcx
>>(&mut self,
60 variance
: ty
::Variance
,
63 -> RelateResult
<'tcx
, T
>
66 ty
::Invariant
=> self.fields
.equate(self.a_is_expected
).relate(a
, b
),
67 ty
::Covariant
=> self.relate(a
, b
),
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) }
),
73 fn tys(&mut self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> RelateResult
<'tcx
, Ty
<'tcx
>> {
74 debug
!("{}.tys({:?}, {:?})", self.tag(), a
, b
);
76 if a
== b { return Ok(a); }
78 let infcx
= self.fields
.infcx
;
79 let a
= infcx
.type_variables
.borrow_mut().replace_if_possible(a
);
80 let b
= infcx
.type_variables
.borrow_mut().replace_if_possible(b
);
81 match (&a
.sty
, &b
.sty
) {
82 (&ty
::TyInfer(TyVar(a_id
)), &ty
::TyInfer(TyVar(b_id
))) => {
85 .relate_vars(a_id
, SubtypeOf
, b_id
);
88 (&ty
::TyInfer(TyVar(a_id
)), _
) => {
90 .instantiate(b
, SupertypeOf
, a_id
, !self.a_is_expected
)?
;
93 (_
, &ty
::TyInfer(TyVar(b_id
))) => {
94 self.fields
.instantiate(a
, SubtypeOf
, b_id
, self.a_is_expected
)?
;
98 (&ty
::TyError
, _
) | (_
, &ty
::TyError
) => {
99 infcx
.set_tainted_by_errors();
100 Ok(self.tcx().types
.err
)
104 self.fields
.infcx
.super_combine_tys(self, a
, b
)?
;
110 fn regions(&mut self, a
: &'tcx ty
::Region
, b
: &'tcx ty
::Region
)
111 -> RelateResult
<'tcx
, &'tcx ty
::Region
> {
112 debug
!("{}.regions({:?}, {:?}) self.cause={:?}",
113 self.tag(), a
, b
, self.fields
.cause
);
115 // FIXME -- we have more fine-grained information available
116 // from the "cause" field, we could perhaps give more tailored
118 let origin
= SubregionOrigin
::Subtype(self.fields
.trace
.clone());
119 self.fields
.infcx
.region_vars
.make_subregion(origin
, a
, b
);
124 fn binders
<T
>(&mut self, a
: &ty
::Binder
<T
>, b
: &ty
::Binder
<T
>)
125 -> RelateResult
<'tcx
, ty
::Binder
<T
>>
126 where T
: Relate
<'tcx
>
128 self.fields
.higher_ranked_sub(a
, b
, self.a_is_expected
)