1 use super::combine
::{CombineFields, RelationDir}
;
2 use super::SubregionOrigin
;
4 use crate::infer
::combine
::ConstEquateRelation
;
5 use crate::traits
::Obligation
;
6 use rustc_middle
::ty
::fold
::TypeFoldable
;
7 use rustc_middle
::ty
::relate
::{Cause, Relate, RelateResult, TypeRelation}
;
8 use rustc_middle
::ty
::TyVar
;
9 use rustc_middle
::ty
::{self, ToPredicate, Ty, TyCtxt}
;
12 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
13 pub struct Sub
<'combine
, 'infcx
, 'tcx
> {
14 fields
: &'combine
mut CombineFields
<'infcx
, 'tcx
>,
18 impl<'combine
, 'infcx
, 'tcx
> Sub
<'combine
, 'infcx
, 'tcx
> {
20 f
: &'combine
mut CombineFields
<'infcx
, 'tcx
>,
22 ) -> Sub
<'combine
, 'infcx
, 'tcx
> {
23 Sub { fields: f, a_is_expected }
26 fn with_expected_switched
<R
, F
: FnOnce(&mut Self) -> R
>(&mut self, f
: F
) -> R
{
27 self.a_is_expected
= !self.a_is_expected
;
29 self.a_is_expected
= !self.a_is_expected
;
34 impl TypeRelation
<'tcx
> for Sub
<'combine
, 'infcx
, 'tcx
> {
35 fn tag(&self) -> &'
static str {
38 fn tcx(&self) -> TyCtxt
<'tcx
> {
42 fn param_env(&self) -> ty
::ParamEnv
<'tcx
> {
46 fn a_is_expected(&self) -> bool
{
50 fn with_cause
<F
, R
>(&mut self, cause
: Cause
, f
: F
) -> R
52 F
: FnOnce(&mut Self) -> R
,
54 debug
!("sub with_cause={:?}", cause
);
55 let old_cause
= mem
::replace(&mut self.fields
.cause
, Some(cause
));
57 debug
!("sub old_cause={:?}", old_cause
);
58 self.fields
.cause
= old_cause
;
62 fn relate_with_variance
<T
: Relate
<'tcx
>>(
64 variance
: ty
::Variance
,
67 ) -> RelateResult
<'tcx
, T
> {
69 ty
::Invariant
=> self.fields
.equate(self.a_is_expected
).relate(a
, b
),
70 ty
::Covariant
=> self.relate(a
, b
),
71 ty
::Bivariant
=> Ok(a
),
72 ty
::Contravariant
=> self.with_expected_switched(|this
| this
.relate(b
, a
)),
76 fn tys(&mut self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> RelateResult
<'tcx
, Ty
<'tcx
>> {
77 debug
!("{}.tys({:?}, {:?})", self.tag(), a
, b
);
83 let infcx
= self.fields
.infcx
;
84 let a
= infcx
.inner
.borrow_mut().type_variables().replace_if_possible(a
);
85 let b
= infcx
.inner
.borrow_mut().type_variables().replace_if_possible(b
);
86 match (&a
.kind
, &b
.kind
) {
87 (&ty
::Infer(TyVar(a_vid
)), &ty
::Infer(TyVar(b_vid
))) => {
88 // Shouldn't have any LBR here, so we can safely put
89 // this under a binder below without fear of accidental
91 assert
!(!a
.has_escaping_bound_vars());
92 assert
!(!b
.has_escaping_bound_vars());
94 // can't make progress on `A <: B` if both A and B are
95 // type variables, so record an obligation. We also
96 // have to record in the `type_variables` tracker that
97 // the two variables are equal modulo subtyping, which
98 // is important to the occurs check later on.
99 infcx
.inner
.borrow_mut().type_variables().sub(a_vid
, b_vid
);
100 self.fields
.obligations
.push(Obligation
::new(
101 self.fields
.trace
.cause
.clone(),
102 self.fields
.param_env
,
103 ty
::PredicateAtom
::Subtype(ty
::SubtypePredicate
{
104 a_is_expected
: self.a_is_expected
,
108 .to_predicate(self.tcx()),
113 (&ty
::Infer(TyVar(a_id
)), _
) => {
114 self.fields
.instantiate(b
, RelationDir
::SupertypeOf
, a_id
, !self.a_is_expected
)?
;
117 (_
, &ty
::Infer(TyVar(b_id
))) => {
118 self.fields
.instantiate(a
, RelationDir
::SubtypeOf
, b_id
, self.a_is_expected
)?
;
122 (&ty
::Error(_
), _
) | (_
, &ty
::Error(_
)) => {
123 infcx
.set_tainted_by_errors();
124 Ok(self.tcx().ty_error())
128 self.fields
.infcx
.super_combine_tys(self, a
, b
)?
;
138 ) -> RelateResult
<'tcx
, ty
::Region
<'tcx
>> {
139 debug
!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a
, b
, self.fields
.cause
);
141 // FIXME -- we have more fine-grained information available
142 // from the "cause" field, we could perhaps give more tailored
144 let origin
= SubregionOrigin
::Subtype(box self.fields
.trace
.clone());
149 .unwrap_region_constraints()
150 .make_subregion(origin
, a
, b
);
157 a
: &'tcx ty
::Const
<'tcx
>,
158 b
: &'tcx ty
::Const
<'tcx
>,
159 ) -> RelateResult
<'tcx
, &'tcx ty
::Const
<'tcx
>> {
160 self.fields
.infcx
.super_combine_consts(self, a
, b
)
167 ) -> RelateResult
<'tcx
, ty
::Binder
<T
>>
171 self.fields
.higher_ranked_sub(a
, b
, self.a_is_expected
)
175 impl<'tcx
> ConstEquateRelation
<'tcx
> for Sub
<'_
, '_
, 'tcx
> {
176 fn const_equate_obligation(&mut self, a
: &'tcx ty
::Const
<'tcx
>, b
: &'tcx ty
::Const
<'tcx
>) {
177 self.fields
.add_const_equate_obligation(self.a_is_expected
, a
, b
);