rustc_infer/infer/relate/
type_relating.rs1use rustc_middle::traits::solve::Goal;
2use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
3use rustc_middle::ty::relate::{
4 Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances,
5};
6use rustc_middle::ty::{self, DelayedSet, Ty, TyCtxt, TyVar};
7use rustc_span::Span;
8use tracing::{debug, instrument};
9
10use crate::infer::BoundRegionConversionTime::HigherRankedType;
11use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
12use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
13use crate::traits::{Obligation, PredicateObligations};
14
15pub(crate) struct TypeRelating<'infcx, 'tcx> {
17 infcx: &'infcx InferCtxt<'tcx>,
18
19 trace: TypeTrace<'tcx>,
21 param_env: ty::ParamEnv<'tcx>,
22 define_opaque_types: DefineOpaqueTypes,
23
24 ambient_variance: ty::Variance,
26 obligations: PredicateObligations<'tcx>,
27 cache: DelayedSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>,
50}
51
52impl<'infcx, 'tcx> TypeRelating<'infcx, 'tcx> {
53 pub(crate) fn new(
54 infcx: &'infcx InferCtxt<'tcx>,
55 trace: TypeTrace<'tcx>,
56 param_env: ty::ParamEnv<'tcx>,
57 define_opaque_types: DefineOpaqueTypes,
58 ambient_variance: ty::Variance,
59 ) -> TypeRelating<'infcx, 'tcx> {
60 assert!(!infcx.next_trait_solver);
61 TypeRelating {
62 infcx,
63 trace,
64 param_env,
65 define_opaque_types,
66 ambient_variance,
67 obligations: PredicateObligations::new(),
68 cache: Default::default(),
69 }
70 }
71
72 pub(crate) fn into_obligations(self) -> PredicateObligations<'tcx> {
73 self.obligations
74 }
75}
76
77impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, 'tcx> {
78 fn cx(&self) -> TyCtxt<'tcx> {
79 self.infcx.tcx
80 }
81
82 fn relate_item_args(
83 &mut self,
84 item_def_id: rustc_hir::def_id::DefId,
85 a_arg: ty::GenericArgsRef<'tcx>,
86 b_arg: ty::GenericArgsRef<'tcx>,
87 ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
88 if self.ambient_variance == ty::Invariant {
89 relate_args_invariantly(self, a_arg, b_arg)
93 } else {
94 let tcx = self.cx();
95 let opt_variances = tcx.variances_of(item_def_id);
96 relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false)
97 }
98 }
99
100 fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
101 &mut self,
102 variance: ty::Variance,
103 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
104 a: T,
105 b: T,
106 ) -> RelateResult<'tcx, T> {
107 let old_ambient_variance = self.ambient_variance;
108 self.ambient_variance = self.ambient_variance.xform(variance);
109 debug!(?self.ambient_variance, "new ambient variance");
110
111 let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
112
113 self.ambient_variance = old_ambient_variance;
114 r
115 }
116
117 #[instrument(skip(self), level = "trace")]
118 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
119 if a == b {
120 return Ok(a);
121 }
122
123 let infcx = self.infcx;
124 let a = infcx.shallow_resolve(a);
125 let b = infcx.shallow_resolve(b);
126
127 if self.cache.contains(&(self.ambient_variance, a, b)) {
128 return Ok(a);
129 }
130
131 match (a.kind(), b.kind()) {
132 (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
133 match self.ambient_variance {
134 ty::Covariant => {
135 self.obligations.push(Obligation::new(
138 self.cx(),
139 self.trace.cause.clone(),
140 self.param_env,
141 ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
142 a_is_expected: true,
143 a,
144 b,
145 })),
146 ));
147 }
148 ty::Contravariant => {
149 self.obligations.push(Obligation::new(
152 self.cx(),
153 self.trace.cause.clone(),
154 self.param_env,
155 ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
156 a_is_expected: false,
157 a: b,
158 b: a,
159 })),
160 ));
161 }
162 ty::Invariant => {
163 infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
164 }
165 ty::Bivariant => {
166 unreachable!("Expected bivariance to be handled in relate_with_variance")
167 }
168 }
169 }
170
171 (&ty::Infer(TyVar(a_vid)), _) => {
172 infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?;
173 }
174 (_, &ty::Infer(TyVar(b_vid))) => {
175 infcx.instantiate_ty_var(
176 self,
177 false,
178 b_vid,
179 self.ambient_variance.xform(ty::Contravariant),
180 a,
181 )?;
182 }
183
184 (
185 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
186 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
187 ) if a_def_id == b_def_id => {
188 super_combine_tys(infcx, self, a, b)?;
189 }
190
191 (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
192 | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
193 if self.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() =>
194 {
195 self.register_goals(infcx.handle_opaque_type(
196 a,
197 b,
198 self.trace.cause.span,
199 self.param_env(),
200 )?);
201 }
202
203 _ => {
204 super_combine_tys(infcx, self, a, b)?;
205 }
206 }
207
208 assert!(self.cache.insert((self.ambient_variance, a, b)));
209
210 Ok(a)
211 }
212
213 #[instrument(skip(self), level = "trace")]
214 fn regions(
215 &mut self,
216 a: ty::Region<'tcx>,
217 b: ty::Region<'tcx>,
218 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
219 let origin = SubregionOrigin::Subtype(Box::new(self.trace.clone()));
220
221 match self.ambient_variance {
222 ty::Covariant => {
224 self.infcx
225 .inner
226 .borrow_mut()
227 .unwrap_region_constraints()
228 .make_subregion(origin, b, a);
229 }
230 ty::Contravariant => {
232 self.infcx
233 .inner
234 .borrow_mut()
235 .unwrap_region_constraints()
236 .make_subregion(origin, a, b);
237 }
238 ty::Invariant => {
239 self.infcx
240 .inner
241 .borrow_mut()
242 .unwrap_region_constraints()
243 .make_eqregion(origin, a, b);
244 }
245 ty::Bivariant => {
246 unreachable!("Expected bivariance to be handled in relate_with_variance")
247 }
248 }
249
250 Ok(a)
251 }
252
253 #[instrument(skip(self), level = "trace")]
254 fn consts(
255 &mut self,
256 a: ty::Const<'tcx>,
257 b: ty::Const<'tcx>,
258 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
259 super_combine_consts(self.infcx, self, a, b)
260 }
261
262 fn binders<T>(
263 &mut self,
264 a: ty::Binder<'tcx, T>,
265 b: ty::Binder<'tcx, T>,
266 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
267 where
268 T: Relate<TyCtxt<'tcx>>,
269 {
270 if a == b {
271 } else if let Some(a) = a.no_bound_vars()
273 && let Some(b) = b.no_bound_vars()
274 {
275 self.relate(a, b)?;
276 } else {
277 let span = self.trace.cause.span;
278 let infcx = self.infcx;
279
280 match self.ambient_variance {
281 ty::Covariant => {
297 infcx.enter_forall(b, |b| {
298 let a = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, a);
299 self.relate(a, b)
300 })?;
301 }
302 ty::Contravariant => {
303 infcx.enter_forall(a, |a| {
304 let b = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, b);
305 self.relate(a, b)
306 })?;
307 }
308
309 ty::Invariant => {
320 infcx.enter_forall(b, |b| {
321 let a = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, a);
322 self.relate(a, b)
323 })?;
324
325 infcx.enter_forall(a, |a| {
327 let b = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, b);
328 self.relate(a, b)
329 })?;
330 }
331 ty::Bivariant => {
332 unreachable!("Expected bivariance to be handled in relate_with_variance")
333 }
334 }
335 }
336
337 Ok(a)
338 }
339}
340
341impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, 'tcx> {
342 fn span(&self) -> Span {
343 self.trace.span()
344 }
345
346 fn param_env(&self) -> ty::ParamEnv<'tcx> {
347 self.param_env
348 }
349
350 fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
351 StructurallyRelateAliases::No
352 }
353
354 fn register_predicates(
355 &mut self,
356 preds: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
357 ) {
358 self.obligations.extend(preds.into_iter().map(|pred| {
359 Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, pred)
360 }))
361 }
362
363 fn register_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
364 self.obligations.extend(goals.into_iter().map(|goal| {
365 Obligation::new(
366 self.infcx.tcx,
367 self.trace.cause.clone(),
368 goal.param_env,
369 goal.predicate,
370 )
371 }))
372 }
373
374 fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
375 self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
376 ty::Covariant => ty::PredicateKind::AliasRelate(
377 a.into(),
378 b.into(),
379 ty::AliasRelationDirection::Subtype,
380 ),
381 ty::Contravariant => ty::PredicateKind::AliasRelate(
383 b.into(),
384 a.into(),
385 ty::AliasRelationDirection::Subtype,
386 ),
387 ty::Invariant => ty::PredicateKind::AliasRelate(
388 a.into(),
389 b.into(),
390 ty::AliasRelationDirection::Equate,
391 ),
392 ty::Bivariant => {
393 unreachable!("Expected bivariance to be handled in relate_with_variance")
394 }
395 })]);
396 }
397}