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