]>
Commit | Line | Data |
---|---|---|
e1599b0c | 1 | use super::combine::{CombineFields, RelationDir}; |
dfeec247 | 2 | use super::SubregionOrigin; |
1a4d82fc | 3 | |
f9f354fc | 4 | use crate::infer::combine::ConstEquateRelation; |
ee023bcb | 5 | use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; |
9fa01778 | 6 | use crate::traits::Obligation; |
ba9703b0 XL |
7 | use rustc_middle::ty::fold::TypeFoldable; |
8 | use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; | |
9 | use rustc_middle::ty::TyVar; | |
f9f354fc | 10 | use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; |
62682a34 | 11 | use std::mem; |
1a4d82fc | 12 | |
b039eaaf | 13 | /// Ensures `a` is made a subtype of `b`. Returns `a` on success. |
dc9dc135 XL |
14 | pub struct Sub<'combine, 'infcx, 'tcx> { |
15 | fields: &'combine mut CombineFields<'infcx, 'tcx>, | |
5bcae85e | 16 | a_is_expected: bool, |
1a4d82fc JJ |
17 | } |
18 | ||
dc9dc135 XL |
19 | impl<'combine, 'infcx, 'tcx> Sub<'combine, 'infcx, 'tcx> { |
20 | pub fn new( | |
21 | f: &'combine mut CombineFields<'infcx, 'tcx>, | |
22 | a_is_expected: bool, | |
23 | ) -> Sub<'combine, 'infcx, 'tcx> { | |
74b04a01 | 24 | Sub { fields: f, a_is_expected } |
c34b1796 | 25 | } |
54a0048b | 26 | |
5bcae85e SL |
27 | fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R { |
28 | self.a_is_expected = !self.a_is_expected; | |
29 | let result = f(self); | |
30 | self.a_is_expected = !self.a_is_expected; | |
31 | result | |
54a0048b | 32 | } |
1a4d82fc JJ |
33 | } |
34 | ||
a2a8927a | 35 | impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { |
dfeec247 XL |
36 | fn tag(&self) -> &'static str { |
37 | "Sub" | |
38 | } | |
39 | fn tcx(&self) -> TyCtxt<'tcx> { | |
40 | self.fields.infcx.tcx | |
41 | } | |
416331ca | 42 | |
dfeec247 XL |
43 | fn param_env(&self) -> ty::ParamEnv<'tcx> { |
44 | self.fields.param_env | |
45 | } | |
416331ca | 46 | |
dfeec247 XL |
47 | fn a_is_expected(&self) -> bool { |
48 | self.a_is_expected | |
49 | } | |
85aaf69f | 50 | |
dfeec247 XL |
51 | fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R |
52 | where | |
53 | F: FnOnce(&mut Self) -> R, | |
62682a34 SL |
54 | { |
55 | debug!("sub with_cause={:?}", cause); | |
56 | let old_cause = mem::replace(&mut self.fields.cause, Some(cause)); | |
57 | let r = f(self); | |
58 | debug!("sub old_cause={:?}", old_cause); | |
59 | self.fields.cause = old_cause; | |
60 | r | |
61 | } | |
62 | ||
dfeec247 XL |
63 | fn relate_with_variance<T: Relate<'tcx>>( |
64 | &mut self, | |
65 | variance: ty::Variance, | |
17df50a5 | 66 | _info: ty::VarianceDiagInfo<'tcx>, |
f035d41b XL |
67 | a: T, |
68 | b: T, | |
dfeec247 | 69 | ) -> RelateResult<'tcx, T> { |
c34b1796 | 70 | match variance { |
5bcae85e | 71 | ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), |
c34b1796 | 72 | ty::Covariant => self.relate(a, b), |
3dfed10e | 73 | ty::Bivariant => Ok(a), |
dfeec247 | 74 | ty::Contravariant => self.with_expected_switched(|this| this.relate(b, a)), |
85aaf69f | 75 | } |
1a4d82fc JJ |
76 | } |
77 | ||
ee023bcb | 78 | #[instrument(skip(self), level = "debug")] |
c34b1796 | 79 | fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { |
dfeec247 XL |
80 | if a == b { |
81 | return Ok(a); | |
82 | } | |
1a4d82fc JJ |
83 | |
84 | let infcx = self.fields.infcx; | |
f9f354fc XL |
85 | let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); |
86 | let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); | |
ee023bcb | 87 | |
1b1a35ee | 88 | match (a.kind(), b.kind()) { |
94222f64 | 89 | (&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => { |
cc61c64b XL |
90 | // Shouldn't have any LBR here, so we can safely put |
91 | // this under a binder below without fear of accidental | |
92 | // capture. | |
a1dfa0c6 XL |
93 | assert!(!a.has_escaping_bound_vars()); |
94 | assert!(!b.has_escaping_bound_vars()); | |
cc61c64b XL |
95 | |
96 | // can't make progress on `A <: B` if both A and B are | |
94222f64 | 97 | // type variables, so record an obligation. |
dfeec247 XL |
98 | self.fields.obligations.push(Obligation::new( |
99 | self.fields.trace.cause.clone(), | |
100 | self.fields.param_env, | |
c295e0f8 | 101 | ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { |
dfeec247 XL |
102 | a_is_expected: self.a_is_expected, |
103 | a, | |
104 | b, | |
c295e0f8 | 105 | })) |
f9f354fc | 106 | .to_predicate(self.tcx()), |
dfeec247 | 107 | )); |
cc61c64b | 108 | |
1a4d82fc JJ |
109 | Ok(a) |
110 | } | |
b7449926 | 111 | (&ty::Infer(TyVar(a_id)), _) => { |
dfeec247 | 112 | self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; |
1a4d82fc JJ |
113 | Ok(a) |
114 | } | |
b7449926 | 115 | (_, &ty::Infer(TyVar(b_id))) => { |
cc61c64b | 116 | self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; |
1a4d82fc JJ |
117 | Ok(a) |
118 | } | |
119 | ||
f035d41b | 120 | (&ty::Error(_), _) | (_, &ty::Error(_)) => { |
a7813a04 | 121 | infcx.set_tainted_by_errors(); |
f035d41b | 122 | Ok(self.tcx().ty_error()) |
1a4d82fc JJ |
123 | } |
124 | ||
ee023bcb FG |
125 | (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { |
126 | self.fields.infcx.super_combine_tys(self, a, b)?; | |
127 | Ok(a) | |
128 | } | |
129 | (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) | |
130 | if self.fields.define_opaque_types && did.is_local() => | |
131 | { | |
132 | let mut generalize = |ty, ty_is_expected| { | |
133 | let var = infcx.next_ty_var_id_in_universe( | |
134 | TypeVariableOrigin { | |
135 | kind: TypeVariableOriginKind::MiscVariable, | |
136 | span: self.fields.trace.cause.span, | |
137 | }, | |
138 | ty::UniverseIndex::ROOT, | |
139 | ); | |
140 | self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?; | |
141 | Ok(infcx.tcx.mk_ty_var(var)) | |
142 | }; | |
143 | let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) }; | |
144 | let (a, b) = match (a.kind(), b.kind()) { | |
145 | (&ty::Opaque(..), _) => (a, generalize(b, true)?), | |
146 | (_, &ty::Opaque(..)) => (generalize(a, false)?, b), | |
147 | _ => unreachable!(), | |
148 | }; | |
149 | self.fields.obligations.extend( | |
150 | infcx | |
151 | .handle_opaque_type(a, b, true, &self.fields.trace.cause, self.param_env())? | |
152 | .obligations, | |
153 | ); | |
154 | Ok(a) | |
155 | } | |
156 | ||
1a4d82fc | 157 | _ => { |
a7813a04 | 158 | self.fields.infcx.super_combine_tys(self, a, b)?; |
b039eaaf | 159 | Ok(a) |
1a4d82fc JJ |
160 | } |
161 | } | |
162 | } | |
163 | ||
dfeec247 XL |
164 | fn regions( |
165 | &mut self, | |
166 | a: ty::Region<'tcx>, | |
167 | b: ty::Region<'tcx>, | |
168 | ) -> RelateResult<'tcx, ty::Region<'tcx>> { | |
169 | debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause); | |
476ff2be | 170 | |
c1a9b12d SL |
171 | // FIXME -- we have more fine-grained information available |
172 | // from the "cause" field, we could perhaps give more tailored | |
173 | // error messages. | |
94222f64 | 174 | let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); |
74b04a01 XL |
175 | self.fields |
176 | .infcx | |
177 | .inner | |
178 | .borrow_mut() | |
179 | .unwrap_region_constraints() | |
180 | .make_subregion(origin, a, b); | |
476ff2be | 181 | |
c34b1796 AL |
182 | Ok(a) |
183 | } | |
184 | ||
48663c56 XL |
185 | fn consts( |
186 | &mut self, | |
5099ac24 FG |
187 | a: ty::Const<'tcx>, |
188 | b: ty::Const<'tcx>, | |
189 | ) -> RelateResult<'tcx, ty::Const<'tcx>> { | |
e1599b0c | 190 | self.fields.infcx.super_combine_consts(self, a, b) |
48663c56 XL |
191 | } |
192 | ||
dfeec247 XL |
193 | fn binders<T>( |
194 | &mut self, | |
cdc7bbd5 XL |
195 | a: ty::Binder<'tcx, T>, |
196 | b: ty::Binder<'tcx, T>, | |
197 | ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> | |
dfeec247 XL |
198 | where |
199 | T: Relate<'tcx>, | |
1a4d82fc | 200 | { |
5bcae85e | 201 | self.fields.higher_ranked_sub(a, b, self.a_is_expected) |
1a4d82fc JJ |
202 | } |
203 | } | |
f9f354fc XL |
204 | |
205 | impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> { | |
5099ac24 | 206 | fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { |
f9f354fc XL |
207 | self.fields.add_const_equate_obligation(self.a_is_expected, a, b); |
208 | } | |
209 | } |