1use tracing::{debug, instrument};
2
3use self::combine::{PredicateEmittingRelation, super_combine_consts, super_combine_tys};
4use crate::data_structures::DelayedSet;
5pub use crate::relate::*;
6use crate::solve::Goal;
7use crate::{self as ty, InferCtxtLike, Interner};
8
9pub trait RelateExt: InferCtxtLike {
10 fn relate<T: Relate<Self::Interner>>(
11 &self,
12 param_env: <Self::Interner as Interner>::ParamEnv,
13 lhs: T,
14 variance: ty::Variance,
15 rhs: T,
16 span: <Self::Interner as Interner>::Span,
17 ) -> Result<
18 Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
19 TypeError<Self::Interner>,
20 >;
21
22 fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
23 &self,
24 param_env: <Self::Interner as Interner>::ParamEnv,
25 lhs: T,
26 rhs: T,
27 span: <Self::Interner as Interner>::Span,
28 ) -> Result<
29 Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
30 TypeError<Self::Interner>,
31 >;
32}
33
34impl<Infcx: InferCtxtLike> RelateExt for Infcx {
35 fn relate<T: Relate<Self::Interner>>(
36 &self,
37 param_env: <Self::Interner as Interner>::ParamEnv,
38 lhs: T,
39 variance: ty::Variance,
40 rhs: T,
41 span: <Self::Interner as Interner>::Span,
42 ) -> Result<
43 Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
44 TypeError<Self::Interner>,
45 > {
46 let mut relate =
47 SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span);
48 relate.relate(lhs, rhs)?;
49 Ok(relate.goals)
50 }
51
52 fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
53 &self,
54 param_env: <Self::Interner as Interner>::ParamEnv,
55 lhs: T,
56 rhs: T,
57 span: <Self::Interner as Interner>::Span,
58 ) -> Result<
59 Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
60 TypeError<Self::Interner>,
61 > {
62 let mut relate = SolverRelating::new(
63 self,
64 StructurallyRelateAliases::Yes,
65 ty::Invariant,
66 param_env,
67 span,
68 );
69 relate.relate(lhs, rhs)?;
70 Ok(relate.goals)
71 }
72}
73
74pub struct SolverRelating<'infcx, Infcx, I: Interner> {
76 infcx: &'infcx Infcx,
77 structurally_relate_aliases: StructurallyRelateAliases,
79 param_env: I::ParamEnv,
80 span: I::Span,
81 ambient_variance: ty::Variance,
83 goals: Vec<Goal<I, I::Predicate>>,
84 cache: DelayedSet<(ty::Variance, I::Ty, I::Ty)>,
107}
108
109impl<'infcx, Infcx, I> SolverRelating<'infcx, Infcx, I>
110where
111 Infcx: InferCtxtLike<Interner = I>,
112 I: Interner,
113{
114 pub fn new(
115 infcx: &'infcx Infcx,
116 structurally_relate_aliases: StructurallyRelateAliases,
117 ambient_variance: ty::Variance,
118 param_env: I::ParamEnv,
119 span: I::Span,
120 ) -> Self {
121 SolverRelating {
122 infcx,
123 structurally_relate_aliases,
124 span,
125 ambient_variance,
126 param_env,
127 goals: vec![],
128 cache: Default::default(),
129 }
130 }
131}
132
133impl<Infcx, I> TypeRelation<I> for SolverRelating<'_, Infcx, I>
134where
135 Infcx: InferCtxtLike<Interner = I>,
136 I: Interner,
137{
138 fn cx(&self) -> I {
139 self.infcx.cx()
140 }
141
142 fn relate_item_args(
143 &mut self,
144 item_def_id: I::DefId,
145 a_arg: I::GenericArgs,
146 b_arg: I::GenericArgs,
147 ) -> RelateResult<I, I::GenericArgs> {
148 if self.ambient_variance == ty::Invariant {
149 relate_args_invariantly(self, a_arg, b_arg)
153 } else {
154 let tcx = self.cx();
155 let opt_variances = tcx.variances_of(item_def_id);
156 relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false)
157 }
158 }
159
160 fn relate_with_variance<T: Relate<I>>(
161 &mut self,
162 variance: ty::Variance,
163 _info: VarianceDiagInfo<I>,
164 a: T,
165 b: T,
166 ) -> RelateResult<I, T> {
167 let old_ambient_variance = self.ambient_variance;
168 self.ambient_variance = self.ambient_variance.xform(variance);
169 debug!(?self.ambient_variance, "new ambient variance");
170
171 let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
172
173 self.ambient_variance = old_ambient_variance;
174 r
175 }
176
177 #[instrument(skip(self), level = "trace")]
178 fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty> {
179 if a == b {
180 return Ok(a);
181 }
182
183 let infcx = self.infcx;
184 let a = infcx.shallow_resolve(a);
185 let b = infcx.shallow_resolve(b);
186
187 if self.cache.contains(&(self.ambient_variance, a, b)) {
188 return Ok(a);
189 }
190
191 match (a.kind(), b.kind()) {
192 (ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => {
193 match self.ambient_variance {
194 ty::Covariant => {
195 self.goals.push(Goal::new(
198 self.cx(),
199 self.param_env,
200 ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
201 a_is_expected: true,
202 a,
203 b,
204 })),
205 ));
206 }
207 ty::Contravariant => {
208 self.goals.push(Goal::new(
211 self.cx(),
212 self.param_env,
213 ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
214 a_is_expected: false,
215 a: b,
216 b: a,
217 })),
218 ));
219 }
220 ty::Invariant => {
221 infcx.equate_ty_vids_raw(a_id, b_id);
222 }
223 ty::Bivariant => {
224 unreachable!("Expected bivariance to be handled in relate_with_variance")
225 }
226 }
227 }
228
229 (ty::Infer(ty::TyVar(a_vid)), _) => {
230 infcx.instantiate_ty_var_raw(self, true, a_vid, self.ambient_variance, b)?;
231 }
232 (_, ty::Infer(ty::TyVar(b_vid))) => {
233 infcx.instantiate_ty_var_raw(
234 self,
235 false,
236 b_vid,
237 self.ambient_variance.xform(ty::Contravariant),
238 a,
239 )?;
240 }
241
242 _ => {
243 super_combine_tys(self.infcx, self, a, b)?;
244 }
245 }
246
247 assert!(self.cache.insert((self.ambient_variance, a, b)));
248
249 Ok(a)
250 }
251
252 #[instrument(skip(self), level = "trace")]
253 fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region> {
254 match self.ambient_variance {
255 ty::Covariant => self.infcx.sub_regions(b, a, self.span),
257 ty::Contravariant => self.infcx.sub_regions(a, b, self.span),
259 ty::Invariant => self.infcx.equate_regions(a, b, self.span),
260 ty::Bivariant => {
261 unreachable!("Expected bivariance to be handled in relate_with_variance")
262 }
263 }
264
265 Ok(a)
266 }
267
268 #[instrument(skip(self), level = "trace")]
269 fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const> {
270 super_combine_consts(self.infcx, self, a, b)
271 }
272
273 fn binders<T>(
274 &mut self,
275 a: ty::Binder<I, T>,
276 b: ty::Binder<I, T>,
277 ) -> RelateResult<I, ty::Binder<I, T>>
278 where
279 T: Relate<I>,
280 {
281 if a == b {
283 return Ok(a);
284 }
285
286 if let Some(a_inner) = a.no_bound_vars() {
288 if let Some(b_inner) = b.no_bound_vars() {
289 self.relate(a_inner, b_inner)?;
290 return Ok(a);
291 }
292 };
293
294 match self.ambient_variance {
295 ty::Covariant => {
311 self.infcx.enter_forall(b, |b| {
312 let a = self.infcx.instantiate_binder_with_infer(a);
313 self.relate(a, b)
314 })?;
315 }
316 ty::Contravariant => {
317 self.infcx.enter_forall(a, |a| {
318 let b = self.infcx.instantiate_binder_with_infer(b);
319 self.relate(a, b)
320 })?;
321 }
322
323 ty::Invariant => {
334 self.infcx.enter_forall(b, |b| {
335 let a = self.infcx.instantiate_binder_with_infer(a);
336 self.relate(a, b)
337 })?;
338
339 self.infcx.enter_forall(a, |a| {
341 let b = self.infcx.instantiate_binder_with_infer(b);
342 self.relate(a, b)
343 })?;
344 }
345 ty::Bivariant => {
346 unreachable!("Expected bivariance to be handled in relate_with_variance")
347 }
348 }
349 Ok(a)
350 }
351}
352
353impl<Infcx, I> PredicateEmittingRelation<Infcx> for SolverRelating<'_, Infcx, I>
354where
355 Infcx: InferCtxtLike<Interner = I>,
356 I: Interner,
357{
358 fn span(&self) -> I::Span {
359 Span::dummy()
360 }
361
362 fn param_env(&self) -> I::ParamEnv {
363 self.param_env
364 }
365
366 fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
367 self.structurally_relate_aliases
368 }
369
370 fn register_predicates(
371 &mut self,
372 obligations: impl IntoIterator<Item: ty::Upcast<I, I::Predicate>>,
373 ) {
374 self.goals.extend(
375 obligations.into_iter().map(|pred| Goal::new(self.infcx.cx(), self.param_env, pred)),
376 );
377 }
378
379 fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>) {
380 self.goals.extend(obligations);
381 }
382
383 fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty) {
384 self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
385 ty::Covariant => ty::PredicateKind::AliasRelate(
386 a.into(),
387 b.into(),
388 ty::AliasRelationDirection::Subtype,
389 ),
390 ty::Contravariant => ty::PredicateKind::AliasRelate(
392 b.into(),
393 a.into(),
394 ty::AliasRelationDirection::Subtype,
395 ),
396 ty::Invariant => ty::PredicateKind::AliasRelate(
397 a.into(),
398 b.into(),
399 ty::AliasRelationDirection::Equate,
400 ),
401 ty::Bivariant => {
402 unreachable!("Expected bivariance to be handled in relate_with_variance")
403 }
404 })]);
405 }
406}