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