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::traits::ObligationCause;
11use rustc_middle::traits::query::NoSolution;
12use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys};
13use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeVisitableExt};
14use rustc_middle::{bug, span_bug};
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 =
219 self.next_existential_region_var(true, br.kind.get_name(infcx.infcx.tcx));
220 debug!(?ex_reg_var);
221 reg_map.insert(br, ex_reg_var);
222
223 ex_reg_var
224 }
225 },
226 types: &mut |_bound_ty: ty::BoundTy| {
227 unreachable!("we only replace regions in nll_relate, not types")
228 },
229 consts: &mut |_bound_var: ty::BoundVar| {
230 unreachable!("we only replace regions in nll_relate, not consts")
231 },
232 };
233
234 let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate);
235 debug!(?replaced);
236
237 replaced
238 }
239
240 fn create_next_universe(&mut self) -> ty::UniverseIndex {
241 let universe = self.type_checker.infcx.create_next_universe();
242 self.type_checker.constraints.universe_causes.insert(universe, self.universe_info.clone());
243 universe
244 }
245
246 #[instrument(skip(self), level = "debug")]
247 fn next_existential_region_var(
248 &mut self,
249 from_forall: bool,
250 name: Option<Symbol>,
251 ) -> ty::Region<'tcx> {
252 let origin = NllRegionVariableOrigin::Existential { from_forall };
253
254 let reg_var =
255 self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name));
256
257 reg_var
258 }
259
260 #[instrument(skip(self), level = "debug")]
261 fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
262 let reg =
263 self.type_checker.constraints.placeholder_region(self.type_checker.infcx, placeholder);
264
265 let reg_info = match placeholder.bound.kind {
266 ty::BoundRegionKind::Anon => sym::anon,
267 ty::BoundRegionKind::Named(def_id) => self.type_checker.tcx().item_name(def_id),
268 ty::BoundRegionKind::ClosureEnv => sym::env,
269 ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
270 };
271
272 if cfg!(debug_assertions) {
273 let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
274 let new = RegionCtxt::Placeholder(reg_info);
275 let prev = var_to_origin.insert(reg.as_var(), new);
276 if let Some(prev) = prev {
277 assert_eq!(new, prev);
278 }
279 }
280
281 reg
282 }
283
284 fn push_outlives(
285 &mut self,
286 sup: ty::Region<'tcx>,
287 sub: ty::Region<'tcx>,
288 info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
289 ) {
290 let sub = self.type_checker.universal_regions.to_region_vid(sub);
291 let sup = self.type_checker.universal_regions.to_region_vid(sup);
292 self.type_checker.constraints.outlives_constraints.push(OutlivesConstraint {
293 sup,
294 sub,
295 locations: self.locations,
296 span: self.locations.span(self.type_checker.body),
297 category: self.category,
298 variance_info: info,
299 from_closure: false,
300 });
301 }
302}
303
304impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
305 fn cx(&self) -> TyCtxt<'tcx> {
306 self.type_checker.infcx.tcx
307 }
308
309 #[instrument(skip(self, info), level = "trace", ret)]
310 fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
311 &mut self,
312 variance: ty::Variance,
313 info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
314 a: T,
315 b: T,
316 ) -> RelateResult<'tcx, T> {
317 let old_ambient_variance = self.ambient_variance;
318 self.ambient_variance = self.ambient_variance.xform(variance);
319 self.ambient_variance_info = self.ambient_variance_info.xform(info);
320
321 debug!(?self.ambient_variance);
322 let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
324
325 self.ambient_variance = old_ambient_variance;
326
327 r
328 }
329
330 #[instrument(skip(self), level = "debug")]
331 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
332 let infcx = self.type_checker.infcx;
333
334 let a = self.type_checker.infcx.shallow_resolve(a);
335 assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
336
337 if a == b {
338 return Ok(a);
339 }
340
341 match (a.kind(), b.kind()) {
342 (_, &ty::Infer(ty::TyVar(_))) => {
343 span_bug!(
344 self.span(),
345 "should not be relating type variables on the right in MIR typeck"
346 );
347 }
348
349 (&ty::Infer(ty::TyVar(a_vid)), _) => {
350 infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?
351 }
352
353 (
354 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
355 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
356 ) if a_def_id == b_def_id || infcx.next_trait_solver() => {
357 super_combine_tys(&infcx.infcx, self, a, b).map(|_| ()).or_else(|err| {
358 assert!(!self.type_checker.infcx.next_trait_solver());
362 self.cx().dcx().span_delayed_bug(
363 self.span(),
364 "failure to relate an opaque to itself should result in an error later on",
365 );
366 if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
367 })?;
368 }
369 (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
370 | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
371 if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() =>
372 {
373 self.relate_opaques(a, b)?;
374 }
375
376 _ => {
377 debug!(?a, ?b, ?self.ambient_variance);
378
379 super_combine_tys(&self.type_checker.infcx.infcx, self, a, b)?;
381 }
382 }
383
384 Ok(a)
385 }
386
387 #[instrument(skip(self), level = "trace")]
388 fn regions(
389 &mut self,
390 a: ty::Region<'tcx>,
391 b: ty::Region<'tcx>,
392 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
393 debug!(?self.ambient_variance);
394
395 if self.ambient_covariance() {
396 self.push_outlives(a, b, self.ambient_variance_info);
398 }
399
400 if self.ambient_contravariance() {
401 self.push_outlives(b, a, self.ambient_variance_info);
403 }
404
405 Ok(a)
406 }
407
408 fn consts(
409 &mut self,
410 a: ty::Const<'tcx>,
411 b: ty::Const<'tcx>,
412 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
413 let a = self.type_checker.infcx.shallow_resolve_const(a);
414 assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
415 assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
416
417 super_combine_consts(&self.type_checker.infcx.infcx, self, a, b)
418 }
419
420 #[instrument(skip(self), level = "trace")]
421 fn binders<T>(
422 &mut self,
423 a: ty::Binder<'tcx, T>,
424 b: ty::Binder<'tcx, T>,
425 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
426 where
427 T: Relate<TyCtxt<'tcx>>,
428 {
429 debug!(?self.ambient_variance);
449
450 if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
451 self.relate(a, b)?;
453 return Ok(ty::Binder::dummy(a));
454 }
455
456 match self.ambient_variance {
457 ty::Covariant => {
458 self.enter_forall(b, |this, b| {
467 let a = this.instantiate_binder_with_existentials(a);
468 this.relate(a, b)
469 })?;
470 }
471
472 ty::Contravariant => {
473 self.enter_forall(a, |this, a| {
482 let b = this.instantiate_binder_with_existentials(b);
483 this.relate(a, b)
484 })?;
485 }
486
487 ty::Invariant => {
488 self.enter_forall(b, |this, b| {
497 let a = this.instantiate_binder_with_existentials(a);
498 this.relate(a, b)
499 })?;
500 self.enter_forall(a, |this, a| {
503 let b = this.instantiate_binder_with_existentials(b);
504 this.relate(a, b)
505 })?;
506 }
507
508 ty::Bivariant => {}
509 }
510
511 Ok(a)
512 }
513}
514
515impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
516 fn span(&self) -> Span {
517 self.locations.span(self.type_checker.body)
518 }
519
520 fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
521 StructurallyRelateAliases::No
522 }
523
524 fn param_env(&self) -> ty::ParamEnv<'tcx> {
525 self.type_checker.infcx.param_env
526 }
527
528 fn register_predicates(
529 &mut self,
530 obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
531 ) {
532 let tcx = self.cx();
533 let param_env = self.param_env();
534 self.register_goals(
535 obligations.into_iter().map(|to_pred| Goal::new(tcx, param_env, to_pred)),
536 );
537 }
538
539 fn register_goals(
540 &mut self,
541 obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
542 ) {
543 let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
544 self.locations,
545 self.category,
546 InstantiateOpaqueType {
547 obligations: obligations
548 .into_iter()
549 .map(|goal| {
550 Obligation::new(
551 self.cx(),
552 ObligationCause::dummy_with_span(self.span()),
553 goal.param_env,
554 goal.predicate,
555 )
556 })
557 .collect(),
558 base_universe: None,
560 region_constraints: None,
561 },
562 );
563 }
564
565 fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
566 self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
567 ty::Covariant => ty::PredicateKind::AliasRelate(
568 a.into(),
569 b.into(),
570 ty::AliasRelationDirection::Subtype,
571 ),
572 ty::Contravariant => ty::PredicateKind::AliasRelate(
574 b.into(),
575 a.into(),
576 ty::AliasRelationDirection::Subtype,
577 ),
578 ty::Invariant => ty::PredicateKind::AliasRelate(
579 a.into(),
580 b.into(),
581 ty::AliasRelationDirection::Equate,
582 ),
583 ty::Bivariant => {
584 unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)")
585 }
586 })]);
587 }
588}