1 // Copyright 2014 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 //! Applies the "bivariance relationship" to two types and/or regions.
12 //! If (A,B) are bivariant then either A <: B or B <: A. It occurs
13 //! when type/lifetime parameters are unconstrained. Usually this is
14 //! an error, but we permit it in the specific case where a type
15 //! parameter is constrained in a where-clause via an associated type.
17 //! There are several ways one could implement bivariance. You could
18 //! just do nothing at all, for example, or you could fully verify
19 //! that one of the two subtyping relationships hold. We choose to
20 //! thread a middle line: we relate types up to regions, but ignore
21 //! all region relationships.
23 //! At one point, handling bivariance in this fashion was necessary
24 //! for inference, but I'm actually not sure if that is true anymore.
25 //! In particular, it might be enough to say (A,B) are bivariant for
28 use super::combine
::{self, CombineFields}
;
29 use super::type_variable
::{BiTo}
;
31 use middle
::ty
::{self, Ty}
;
32 use middle
::ty
::TyVar
;
33 use middle
::ty_relate
::{Relate, RelateResult, TypeRelation}
;
35 pub struct Bivariate
<'a
, 'tcx
: 'a
> {
36 fields
: CombineFields
<'a
, 'tcx
>
39 impl<'a
, 'tcx
> Bivariate
<'a
, 'tcx
> {
40 pub fn new(fields
: CombineFields
<'a
, 'tcx
>) -> Bivariate
<'a
, 'tcx
> {
41 Bivariate { fields: fields }
45 impl<'a
, 'tcx
> TypeRelation
<'a
, 'tcx
> for Bivariate
<'a
, 'tcx
> {
46 fn tag(&self) -> &'
static str { "Bivariate" }
48 fn tcx(&self) -> &'a ty
::ctxt
<'tcx
> { self.fields.tcx() }
50 fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
52 fn will_change(&mut self, _
: bool
, _
: bool
) -> bool
{
53 // since we are not comparing regions, we don't care
57 fn relate_with_variance
<T
:Relate
<'a
,'tcx
>>(&mut self,
58 variance
: ty
::Variance
,
61 -> RelateResult
<'tcx
, T
>
64 // If we have Foo<A> and Foo is invariant w/r/t A,
65 // and we want to assert that
67 // Foo<A> <: Foo<B> ||
70 // then still A must equal B.
71 ty
::Invariant
=> self.relate(a
, b
),
73 ty
::Covariant
=> self.relate(a
, b
),
74 ty
::Bivariant
=> self.relate(a
, b
),
75 ty
::Contravariant
=> self.relate(a
, b
),
79 fn tys(&mut self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> RelateResult
<'tcx
, Ty
<'tcx
>> {
80 debug
!("{}.tys({:?}, {:?})", self.tag(),
82 if a
== b { return Ok(a); }
84 let infcx
= self.fields
.infcx
;
85 let a
= infcx
.type_variables
.borrow().replace_if_possible(a
);
86 let b
= infcx
.type_variables
.borrow().replace_if_possible(b
);
87 match (&a
.sty
, &b
.sty
) {
88 (&ty
::TyInfer(TyVar(a_id
)), &ty
::TyInfer(TyVar(b_id
))) => {
89 infcx
.type_variables
.borrow_mut().relate_vars(a_id
, BiTo
, b_id
);
93 (&ty
::TyInfer(TyVar(a_id
)), _
) => {
94 try
!(self.fields
.instantiate(b
, BiTo
, a_id
));
98 (_
, &ty
::TyInfer(TyVar(b_id
))) => {
99 try
!(self.fields
.instantiate(a
, BiTo
, b_id
));
104 combine
::super_combine_tys(self.fields
.infcx
, self, a
, b
)
109 fn regions(&mut self, a
: ty
::Region
, _
: ty
::Region
) -> RelateResult
<'tcx
, ty
::Region
> {
113 fn binders
<T
>(&mut self, a
: &ty
::Binder
<T
>, b
: &ty
::Binder
<T
>)
114 -> RelateResult
<'tcx
, ty
::Binder
<T
>>
115 where T
: Relate
<'a
,'tcx
>
117 let a1
= ty
::erase_late_bound_regions(self.tcx(), a
);
118 let b1
= ty
::erase_late_bound_regions(self.tcx(), b
);
119 let c
= try
!(self.relate(&a1
, &b1
));