1use rustc_data_structures::fx::FxHashMap;
2use rustc_errors::ErrorGuaranteed;
3use rustc_hir::def_id::DefId;
4use rustc_infer::infer::relate::{
5 PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
6};
7use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
8use rustc_infer::traits::Obligation;
9use rustc_infer::traits::solve::Goal;
10use rustc_middle::mir::ConstraintCategory;
11use rustc_middle::traits::ObligationCause;
12use rustc_middle::traits::query::NoSolution;
13use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
14use rustc_middle::ty::relate::relate_args_invariantly;
15use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeVisitableExt};
16use rustc_middle::{bug, span_bug};
17use rustc_span::{Span, Symbol, sym};
18use tracing::{debug, instrument};
19
20use crate::constraints::OutlivesConstraint;
21use crate::diagnostics::UniverseInfo;
22use crate::renumber::RegionCtxt;
23use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker};
24
25impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
26 #[instrument(skip(self), level = "debug")]
35 pub(super) fn relate_types(
36 &mut self,
37 a: Ty<'tcx>,
38 v: ty::Variance,
39 b: Ty<'tcx>,
40 locations: Locations,
41 category: ConstraintCategory<'tcx>,
42 ) -> Result<(), NoSolution> {
43 NllTypeRelating::new(self, locations, category, UniverseInfo::relate(a, b), v)
44 .relate(a, b)?;
45 Ok(())
46 }
47
48 pub(super) fn eq_args(
50 &mut self,
51 a: ty::GenericArgsRef<'tcx>,
52 b: ty::GenericArgsRef<'tcx>,
53 locations: Locations,
54 category: ConstraintCategory<'tcx>,
55 ) -> Result<(), NoSolution> {
56 NllTypeRelating::new(self, locations, category, UniverseInfo::other(), ty::Invariant)
57 .relate(a, b)?;
58 Ok(())
59 }
60}
61
62struct NllTypeRelating<'a, 'b, 'tcx> {
63 type_checker: &'a mut TypeChecker<'b, 'tcx>,
64
65 locations: Locations,
67
68 category: ConstraintCategory<'tcx>,
70
71 universe_info: UniverseInfo<'tcx>,
74
75 ambient_variance: ty::Variance,
82
83 ambient_variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
84}
85
86impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
87 fn new(
88 type_checker: &'a mut TypeChecker<'b, 'tcx>,
89 locations: Locations,
90 category: ConstraintCategory<'tcx>,
91 universe_info: UniverseInfo<'tcx>,
92 ambient_variance: ty::Variance,
93 ) -> Self {
94 Self {
95 type_checker,
96 locations,
97 category,
98 universe_info,
99 ambient_variance,
100 ambient_variance_info: ty::VarianceDiagInfo::default(),
101 }
102 }
103
104 fn ambient_covariance(&self) -> bool {
105 match self.ambient_variance {
106 ty::Covariant | ty::Invariant => true,
107 ty::Contravariant | ty::Bivariant => false,
108 }
109 }
110
111 fn ambient_contravariance(&self) -> bool {
112 match self.ambient_variance {
113 ty::Contravariant | ty::Invariant => true,
114 ty::Covariant | ty::Bivariant => false,
115 }
116 }
117
118 fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
119 let infcx = self.type_checker.infcx;
120 debug_assert!(!infcx.next_trait_solver());
121 let mut enable_subtyping = |ty, opaque_is_expected| {
129 let ty_vid = infcx.next_ty_vid(self.span());
136 let variance = if opaque_is_expected {
137 self.ambient_variance
138 } else {
139 self.ambient_variance.xform(ty::Contravariant)
140 };
141
142 self.type_checker.infcx.instantiate_ty_var(
143 self,
144 opaque_is_expected,
145 ty_vid,
146 variance,
147 ty,
148 )?;
149 Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid))))
150 };
151
152 let (a, b) = match (a.kind(), b.kind()) {
153 (&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, true)?),
154 (_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, false)?, b),
155 _ => unreachable!(
156 "expected at least one opaque type in `relate_opaques`, got {a} and {b}."
157 ),
158 };
159 self.register_goals(infcx.handle_opaque_type(a, b, self.span(), self.param_env())?);
160 Ok(())
161 }
162
163 fn enter_forall<T, U>(
164 &mut self,
165 binder: ty::Binder<'tcx, T>,
166 f: impl FnOnce(&mut Self, T) -> U,
167 ) -> U
168 where
169 T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
170 {
171 let value = if let Some(inner) = binder.no_bound_vars() {
172 inner
173 } else {
174 let infcx = self.type_checker.infcx;
175 let mut lazy_universe = None;
176 let delegate = FnMutDelegate {
177 regions: &mut |br: ty::BoundRegion| {
178 let universe = lazy_universe.unwrap_or_else(|| {
182 let universe = self.create_next_universe();
183 lazy_universe = Some(universe);
184 universe
185 });
186
187 let placeholder = ty::PlaceholderRegion::new(universe, br);
188 debug!(?placeholder);
189 let placeholder_reg = self.next_placeholder_region(placeholder);
190 debug!(?placeholder_reg);
191
192 placeholder_reg
193 },
194 types: &mut |_bound_ty: ty::BoundTy| {
195 unreachable!("we only replace regions in nll_relate, not types")
196 },
197 consts: &mut |_bound_const: ty::BoundConst| {
198 unreachable!("we only replace regions in nll_relate, not consts")
199 },
200 };
201
202 infcx.tcx.replace_bound_vars_uncached(binder, delegate)
203 };
204
205 debug!(?value);
206 f(self, value)
207 }
208
209 #[instrument(skip(self), level = "debug")]
210 fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
211 where
212 T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
213 {
214 if let Some(inner) = binder.no_bound_vars() {
215 return inner;
216 }
217
218 let infcx = self.type_checker.infcx;
219 let mut reg_map = FxHashMap::default();
220 let delegate = FnMutDelegate {
221 regions: &mut |br: ty::BoundRegion| {
222 if let Some(ex_reg_var) = reg_map.get(&br) {
223 *ex_reg_var
224 } else {
225 let ex_reg_var =
226 self.next_existential_region_var(br.kind.get_name(infcx.infcx.tcx));
227 debug!(?ex_reg_var);
228 reg_map.insert(br, ex_reg_var);
229
230 ex_reg_var
231 }
232 },
233 types: &mut |_bound_ty: ty::BoundTy| {
234 unreachable!("we only replace regions in nll_relate, not types")
235 },
236 consts: &mut |_bound_const: ty::BoundConst| {
237 unreachable!("we only replace regions in nll_relate, not consts")
238 },
239 };
240
241 let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate);
242 debug!(?replaced);
243
244 replaced
245 }
246
247 fn create_next_universe(&mut self) -> ty::UniverseIndex {
248 let universe = self.type_checker.infcx.create_next_universe();
249 self.type_checker.constraints.universe_causes.insert(universe, self.universe_info.clone());
250 universe
251 }
252
253 #[instrument(skip(self), level = "debug")]
254 fn next_existential_region_var(&mut self, name: Option<Symbol>) -> ty::Region<'tcx> {
255 let origin = NllRegionVariableOrigin::Existential { name };
256 self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name))
257 }
258
259 #[instrument(skip(self), level = "debug")]
260 fn next_placeholder_region(
261 &mut self,
262 placeholder: ty::PlaceholderRegion<'tcx>,
263 ) -> ty::Region<'tcx> {
264 let reg =
265 self.type_checker.constraints.placeholder_region(self.type_checker.infcx, placeholder);
266
267 let reg_info = match placeholder.bound.kind {
268 ty::BoundRegionKind::Anon => sym::anon,
269 ty::BoundRegionKind::Named(def_id) => self.type_checker.tcx().item_name(def_id),
270 ty::BoundRegionKind::ClosureEnv => sym::env,
271 ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
272 };
273
274 if cfg!(debug_assertions) {
275 let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
276 let new = RegionCtxt::Placeholder(reg_info);
277 let prev = var_to_origin.insert(reg.as_var(), new);
278 if let Some(prev) = prev {
279 assert_eq!(new, prev);
280 }
281 }
282
283 reg
284 }
285
286 fn push_outlives(
287 &mut self,
288 sup: ty::Region<'tcx>,
289 sub: ty::Region<'tcx>,
290 info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
291 ) {
292 let sub = self.type_checker.universal_regions.to_region_vid(sub);
293 let sup = self.type_checker.universal_regions.to_region_vid(sup);
294 self.type_checker.constraints.outlives_constraints.push(OutlivesConstraint {
295 sup,
296 sub,
297 locations: self.locations,
298 span: self.locations.span(self.type_checker.body),
299 category: self.category,
300 variance_info: info,
301 from_closure: false,
302 });
303 }
304}
305
306impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
307 fn cx(&self) -> TyCtxt<'tcx> {
308 self.type_checker.infcx.tcx
309 }
310
311 fn relate_ty_args(
312 &mut self,
313 a_ty: Ty<'tcx>,
314 b_ty: Ty<'tcx>,
315 def_id: DefId,
316 a_args: ty::GenericArgsRef<'tcx>,
317 b_args: ty::GenericArgsRef<'tcx>,
318 _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
319 ) -> RelateResult<'tcx, Ty<'tcx>> {
320 if self.ambient_variance == ty::Invariant {
321 relate_args_invariantly(self, a_args, b_args)?;
324 Ok(a_ty)
325 } else {
326 let variances = self.cx().variances_of(def_id);
327 combine_ty_args(
328 &self.type_checker.infcx.infcx,
329 self,
330 a_ty,
331 b_ty,
332 variances,
333 a_args,
334 b_args,
335 |_| a_ty,
336 )
337 }
338 }
339
340 #[instrument(skip(self, info), level = "trace", ret)]
341 fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
342 &mut self,
343 variance: ty::Variance,
344 info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
345 a: T,
346 b: T,
347 ) -> RelateResult<'tcx, T> {
348 let old_ambient_variance = self.ambient_variance;
349 self.ambient_variance = self.ambient_variance.xform(variance);
350 self.ambient_variance_info = self.ambient_variance_info.xform(info);
351
352 debug!(?self.ambient_variance);
353 let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
355
356 self.ambient_variance = old_ambient_variance;
357
358 r
359 }
360
361 #[instrument(skip(self), level = "debug")]
362 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
363 let infcx = self.type_checker.infcx;
364
365 let a = infcx.shallow_resolve(a);
366 assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
367
368 if a == b {
369 return Ok(a);
370 }
371
372 match (a.kind(), b.kind()) {
373 (_, &ty::Infer(ty::TyVar(_))) => {
374 span_bug!(
375 self.span(),
376 "should not be relating type variables on the right in MIR typeck"
377 );
378 }
379
380 (&ty::Infer(ty::TyVar(a_vid)), _) => {
381 infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?
382 }
383
384 (
385 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
386 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
387 ) if a_def_id == b_def_id || infcx.next_trait_solver() => {
388 super_combine_tys(&infcx.infcx, self, a, b).map(|_| ()).or_else(|err| {
389 assert!(!self.type_checker.infcx.next_trait_solver());
393 self.cx().dcx().span_delayed_bug(
394 self.span(),
395 "failure to relate an opaque to itself should result in an error later on",
396 );
397 if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
398 })?;
399 }
400 (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
401 | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
402 if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() =>
403 {
404 self.relate_opaques(a, b)?;
405 }
406
407 _ => {
408 debug!(?a, ?b, ?self.ambient_variance);
409
410 super_combine_tys(&self.type_checker.infcx.infcx, self, a, b)?;
412 }
413 }
414
415 Ok(a)
416 }
417
418 #[instrument(skip(self), level = "trace")]
419 fn regions(
420 &mut self,
421 a: ty::Region<'tcx>,
422 b: ty::Region<'tcx>,
423 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
424 debug!(?self.ambient_variance);
425
426 if self.ambient_covariance() {
427 self.push_outlives(a, b, self.ambient_variance_info);
429 }
430
431 if self.ambient_contravariance() {
432 self.push_outlives(b, a, self.ambient_variance_info);
434 }
435
436 Ok(a)
437 }
438
439 fn consts(
440 &mut self,
441 a: ty::Const<'tcx>,
442 b: ty::Const<'tcx>,
443 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
444 let a = self.type_checker.infcx.shallow_resolve_const(a);
445 assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
446 assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
447
448 super_combine_consts(&self.type_checker.infcx.infcx, self, a, b)
449 }
450
451 #[instrument(skip(self), level = "trace")]
452 fn binders<T>(
453 &mut self,
454 a: ty::Binder<'tcx, T>,
455 b: ty::Binder<'tcx, T>,
456 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
457 where
458 T: Relate<TyCtxt<'tcx>>,
459 {
460 debug!(?self.ambient_variance);
480
481 if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
482 self.relate(a, b)?;
484 return Ok(ty::Binder::dummy(a));
485 }
486
487 match self.ambient_variance {
488 ty::Covariant => {
489 self.enter_forall(b, |this, b| {
498 let a = this.instantiate_binder_with_existentials(a);
499 this.relate(a, b)
500 })?;
501 }
502
503 ty::Contravariant => {
504 self.enter_forall(a, |this, a| {
513 let b = this.instantiate_binder_with_existentials(b);
514 this.relate(a, b)
515 })?;
516 }
517
518 ty::Invariant => {
519 self.enter_forall(b, |this, b| {
528 let a = this.instantiate_binder_with_existentials(a);
529 this.relate(a, b)
530 })?;
531 self.enter_forall(a, |this, a| {
534 let b = this.instantiate_binder_with_existentials(b);
535 this.relate(a, b)
536 })?;
537 }
538
539 ty::Bivariant => {}
540 }
541
542 Ok(a)
543 }
544}
545
546impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
547 fn span(&self) -> Span {
548 self.locations.span(self.type_checker.body)
549 }
550
551 fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
552 StructurallyRelateAliases::No
553 }
554
555 fn param_env(&self) -> ty::ParamEnv<'tcx> {
556 self.type_checker.infcx.param_env
557 }
558
559 fn register_predicates(
560 &mut self,
561 obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
562 ) {
563 let tcx = self.cx();
564 let param_env = self.param_env();
565 self.register_goals(
566 obligations.into_iter().map(|to_pred| Goal::new(tcx, param_env, to_pred)),
567 );
568 }
569
570 fn register_goals(
571 &mut self,
572 obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
573 ) {
574 let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
575 self.locations,
576 self.category,
577 InstantiateOpaqueType {
578 obligations: obligations
579 .into_iter()
580 .map(|goal| {
581 Obligation::new(
582 self.cx(),
583 ObligationCause::dummy_with_span(self.span()),
584 goal.param_env,
585 goal.predicate,
586 )
587 })
588 .collect(),
589 base_universe: None,
591 region_constraints: None,
592 },
593 );
594 }
595
596 fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
597 self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
598 ty::Covariant => ty::PredicateKind::AliasRelate(
599 a.into(),
600 b.into(),
601 ty::AliasRelationDirection::Subtype,
602 ),
603 ty::Contravariant => ty::PredicateKind::AliasRelate(
605 b.into(),
606 a.into(),
607 ty::AliasRelationDirection::Subtype,
608 ),
609 ty::Invariant => ty::PredicateKind::AliasRelate(
610 a.into(),
611 b.into(),
612 ty::AliasRelationDirection::Equate,
613 ),
614 ty::Bivariant => {
615 unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)")
616 }
617 })]);
618 }
619}