rustc_borrowck/type_check/
relate_tys.rs

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    /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
25    ///
26    /// - "Covariant" `a <: b`
27    /// - "Invariant" `a == b`
28    /// - "Contravariant" `a :> b`
29    ///
30    /// N.B., the type `a` is permitted to have unresolved inference
31    /// variables, but not the type `b`.
32    #[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    /// Add sufficient constraints to ensure `a == b`. See also [Self::relate_types].
47    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    /// Where (and why) is this relation taking place?
64    locations: Locations,
65
66    /// What category do we assign the resulting `'a: 'b` relationships?
67    category: ConstraintCategory<'tcx>,
68
69    /// Information so that error reporting knows what types we are relating
70    /// when reporting a bound region error.
71    universe_info: UniverseInfo<'tcx>,
72
73    /// How are we relating `a` and `b`?
74    ///
75    /// - Covariant means `a <: b`.
76    /// - Contravariant means `b <: a`.
77    /// - Invariant means `a == b`.
78    /// - Bivariant means that it doesn't matter.
79    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        // `handle_opaque_type` cannot handle subtyping, so to support subtyping
120        // we instead eagerly generalize here. This is a bit of a mess but will go
121        // away once we're using the new solver.
122        //
123        // Given `opaque rel B`, we create a new infer var `ty_vid` constrain it
124        // by using `ty_vid rel B` and then finally and end by equating `ty_vid` to
125        // the opaque.
126        let mut enable_subtyping = |ty, opaque_is_expected| {
127            // We create the fresh inference variable in the highest universe.
128            // In theory we could limit it to the highest universe in the args of
129            // the opaque but that isn't really worth the effort.
130            //
131            // We'll make sure that the opaque type can actually name everything
132            // in its hidden type later on.
133            let ty_vid = infcx.next_ty_vid(self.span());
134            let variance = if opaque_is_expected {
135                self.ambient_variance
136            } else {
137                self.ambient_variance.xform(ty::Contravariant)
138            };
139
140            self.type_checker.infcx.instantiate_ty_var(
141                self,
142                opaque_is_expected,
143                ty_vid,
144                variance,
145                ty,
146            )?;
147            Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid))))
148        };
149
150        let (a, b) = match (a.kind(), b.kind()) {
151            (&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, true)?),
152            (_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, false)?, b),
153            _ => unreachable!(
154                "expected at least one opaque type in `relate_opaques`, got {a} and {b}."
155            ),
156        };
157        self.register_goals(infcx.handle_opaque_type(a, b, self.span(), self.param_env())?);
158        Ok(())
159    }
160
161    fn enter_forall<T, U>(
162        &mut self,
163        binder: ty::Binder<'tcx, T>,
164        f: impl FnOnce(&mut Self, T) -> U,
165    ) -> U
166    where
167        T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
168    {
169        let value = if let Some(inner) = binder.no_bound_vars() {
170            inner
171        } else {
172            let infcx = self.type_checker.infcx;
173            let mut lazy_universe = None;
174            let delegate = FnMutDelegate {
175                regions: &mut |br: ty::BoundRegion| {
176                    // The first time this closure is called, create a
177                    // new universe for the placeholders we will make
178                    // from here out.
179                    let universe = lazy_universe.unwrap_or_else(|| {
180                        let universe = self.create_next_universe();
181                        lazy_universe = Some(universe);
182                        universe
183                    });
184
185                    let placeholder = ty::PlaceholderRegion { universe, bound: br };
186                    debug!(?placeholder);
187                    let placeholder_reg = self.next_placeholder_region(placeholder);
188                    debug!(?placeholder_reg);
189
190                    placeholder_reg
191                },
192                types: &mut |_bound_ty: ty::BoundTy| {
193                    unreachable!("we only replace regions in nll_relate, not types")
194                },
195                consts: &mut |_bound_const: ty::BoundConst| {
196                    unreachable!("we only replace regions in nll_relate, not consts")
197                },
198            };
199
200            infcx.tcx.replace_bound_vars_uncached(binder, delegate)
201        };
202
203        debug!(?value);
204        f(self, value)
205    }
206
207    #[instrument(skip(self), level = "debug")]
208    fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
209    where
210        T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
211    {
212        if let Some(inner) = binder.no_bound_vars() {
213            return inner;
214        }
215
216        let infcx = self.type_checker.infcx;
217        let mut reg_map = FxHashMap::default();
218        let delegate = FnMutDelegate {
219            regions: &mut |br: ty::BoundRegion| {
220                if let Some(ex_reg_var) = reg_map.get(&br) {
221                    *ex_reg_var
222                } else {
223                    let ex_reg_var =
224                        self.next_existential_region_var(br.kind.get_name(infcx.infcx.tcx));
225                    debug!(?ex_reg_var);
226                    reg_map.insert(br, ex_reg_var);
227
228                    ex_reg_var
229                }
230            },
231            types: &mut |_bound_ty: ty::BoundTy| {
232                unreachable!("we only replace regions in nll_relate, not types")
233            },
234            consts: &mut |_bound_const: ty::BoundConst| {
235                unreachable!("we only replace regions in nll_relate, not consts")
236            },
237        };
238
239        let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate);
240        debug!(?replaced);
241
242        replaced
243    }
244
245    fn create_next_universe(&mut self) -> ty::UniverseIndex {
246        let universe = self.type_checker.infcx.create_next_universe();
247        self.type_checker.constraints.universe_causes.insert(universe, self.universe_info.clone());
248        universe
249    }
250
251    #[instrument(skip(self), level = "debug")]
252    fn next_existential_region_var(&mut self, name: Option<Symbol>) -> ty::Region<'tcx> {
253        let origin = NllRegionVariableOrigin::Existential { name };
254        self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name))
255    }
256
257    #[instrument(skip(self), level = "debug")]
258    fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
259        let reg =
260            self.type_checker.constraints.placeholder_region(self.type_checker.infcx, placeholder);
261
262        let reg_info = match placeholder.bound.kind {
263            ty::BoundRegionKind::Anon => sym::anon,
264            ty::BoundRegionKind::Named(def_id) => self.type_checker.tcx().item_name(def_id),
265            ty::BoundRegionKind::ClosureEnv => sym::env,
266            ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
267        };
268
269        if cfg!(debug_assertions) {
270            let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
271            let new = RegionCtxt::Placeholder(reg_info);
272            let prev = var_to_origin.insert(reg.as_var(), new);
273            if let Some(prev) = prev {
274                assert_eq!(new, prev);
275            }
276        }
277
278        reg
279    }
280
281    fn push_outlives(
282        &mut self,
283        sup: ty::Region<'tcx>,
284        sub: ty::Region<'tcx>,
285        info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
286    ) {
287        let sub = self.type_checker.universal_regions.to_region_vid(sub);
288        let sup = self.type_checker.universal_regions.to_region_vid(sup);
289        self.type_checker.constraints.outlives_constraints.push(OutlivesConstraint {
290            sup,
291            sub,
292            locations: self.locations,
293            span: self.locations.span(self.type_checker.body),
294            category: self.category,
295            variance_info: info,
296            from_closure: false,
297        });
298    }
299}
300
301impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
302    fn cx(&self) -> TyCtxt<'tcx> {
303        self.type_checker.infcx.tcx
304    }
305
306    #[instrument(skip(self, info), level = "trace", ret)]
307    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
308        &mut self,
309        variance: ty::Variance,
310        info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
311        a: T,
312        b: T,
313    ) -> RelateResult<'tcx, T> {
314        let old_ambient_variance = self.ambient_variance;
315        self.ambient_variance = self.ambient_variance.xform(variance);
316        self.ambient_variance_info = self.ambient_variance_info.xform(info);
317
318        debug!(?self.ambient_variance);
319        // In a bivariant context this always succeeds.
320        let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
321
322        self.ambient_variance = old_ambient_variance;
323
324        r
325    }
326
327    #[instrument(skip(self), level = "debug")]
328    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
329        let infcx = self.type_checker.infcx;
330
331        let a = self.type_checker.infcx.shallow_resolve(a);
332        assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
333
334        if a == b {
335            return Ok(a);
336        }
337
338        match (a.kind(), b.kind()) {
339            (_, &ty::Infer(ty::TyVar(_))) => {
340                span_bug!(
341                    self.span(),
342                    "should not be relating type variables on the right in MIR typeck"
343                );
344            }
345
346            (&ty::Infer(ty::TyVar(a_vid)), _) => {
347                infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?
348            }
349
350            (
351                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
352                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
353            ) if a_def_id == b_def_id || infcx.next_trait_solver() => {
354                super_combine_tys(&infcx.infcx, self, a, b).map(|_| ()).or_else(|err| {
355                    // This behavior is only there for the old solver, the new solver
356                    // shouldn't ever fail. Instead, it unconditionally emits an
357                    // alias-relate goal.
358                    assert!(!self.type_checker.infcx.next_trait_solver());
359                    self.cx().dcx().span_delayed_bug(
360                        self.span(),
361                        "failure to relate an opaque to itself should result in an error later on",
362                    );
363                    if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
364                })?;
365            }
366            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
367            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
368                if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() =>
369            {
370                self.relate_opaques(a, b)?;
371            }
372
373            _ => {
374                debug!(?a, ?b, ?self.ambient_variance);
375
376                // Will also handle unification of `IntVar` and `FloatVar`.
377                super_combine_tys(&self.type_checker.infcx.infcx, self, a, b)?;
378            }
379        }
380
381        Ok(a)
382    }
383
384    #[instrument(skip(self), level = "trace")]
385    fn regions(
386        &mut self,
387        a: ty::Region<'tcx>,
388        b: ty::Region<'tcx>,
389    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
390        debug!(?self.ambient_variance);
391
392        if self.ambient_covariance() {
393            // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
394            self.push_outlives(a, b, self.ambient_variance_info);
395        }
396
397        if self.ambient_contravariance() {
398            // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
399            self.push_outlives(b, a, self.ambient_variance_info);
400        }
401
402        Ok(a)
403    }
404
405    fn consts(
406        &mut self,
407        a: ty::Const<'tcx>,
408        b: ty::Const<'tcx>,
409    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
410        let a = self.type_checker.infcx.shallow_resolve_const(a);
411        assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
412        assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
413
414        super_combine_consts(&self.type_checker.infcx.infcx, self, a, b)
415    }
416
417    #[instrument(skip(self), level = "trace")]
418    fn binders<T>(
419        &mut self,
420        a: ty::Binder<'tcx, T>,
421        b: ty::Binder<'tcx, T>,
422    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
423    where
424        T: Relate<TyCtxt<'tcx>>,
425    {
426        // We want that
427        //
428        // ```
429        // for<'a> fn(&'a u32) -> &'a u32 <:
430        //   fn(&'b u32) -> &'b u32
431        // ```
432        //
433        // but not
434        //
435        // ```
436        // fn(&'a u32) -> &'a u32 <:
437        //   for<'b> fn(&'b u32) -> &'b u32
438        // ```
439        //
440        // We therefore proceed as follows:
441        //
442        // - Instantiate binders on `b` universally, yielding a universe U1.
443        // - Instantiate binders on `a` existentially in U1.
444
445        debug!(?self.ambient_variance);
446
447        if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
448            // Fast path for the common case.
449            self.relate(a, b)?;
450            return Ok(ty::Binder::dummy(a));
451        }
452
453        match self.ambient_variance {
454            ty::Covariant => {
455                // Covariance, so we want `for<..> A <: for<..> B` --
456                // therefore we compare any instantiation of A (i.e., A
457                // instantiated with existentials) against every
458                // instantiation of B (i.e., B instantiated with
459                // universals).
460
461                // Note: the order here is important. Create the placeholders first, otherwise
462                // we assign the wrong universe to the existential!
463                self.enter_forall(b, |this, b| {
464                    let a = this.instantiate_binder_with_existentials(a);
465                    this.relate(a, b)
466                })?;
467            }
468
469            ty::Contravariant => {
470                // Contravariance, so we want `for<..> A :> for<..> B` --
471                // therefore we compare every instantiation of A (i.e., A
472                // instantiated with universals) against any
473                // instantiation of B (i.e., B instantiated with
474                // existentials). Opposite of above.
475
476                // Note: the order here is important. Create the placeholders first, otherwise
477                // we assign the wrong universe to the existential!
478                self.enter_forall(a, |this, a| {
479                    let b = this.instantiate_binder_with_existentials(b);
480                    this.relate(a, b)
481                })?;
482            }
483
484            ty::Invariant => {
485                // Invariant, so we want `for<..> A == for<..> B` --
486                // therefore we want `exists<..> A == for<..> B` and
487                // `exists<..> B == for<..> A`.
488                //
489                // See the comment in `fn Equate::binders` for more details.
490
491                // Note: the order here is important. Create the placeholders first, otherwise
492                // we assign the wrong universe to the existential!
493                self.enter_forall(b, |this, b| {
494                    let a = this.instantiate_binder_with_existentials(a);
495                    this.relate(a, b)
496                })?;
497                // Note: the order here is important. Create the placeholders first, otherwise
498                // we assign the wrong universe to the existential!
499                self.enter_forall(a, |this, a| {
500                    let b = this.instantiate_binder_with_existentials(b);
501                    this.relate(a, b)
502                })?;
503            }
504
505            ty::Bivariant => {}
506        }
507
508        Ok(a)
509    }
510}
511
512impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
513    fn span(&self) -> Span {
514        self.locations.span(self.type_checker.body)
515    }
516
517    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
518        StructurallyRelateAliases::No
519    }
520
521    fn param_env(&self) -> ty::ParamEnv<'tcx> {
522        self.type_checker.infcx.param_env
523    }
524
525    fn register_predicates(
526        &mut self,
527        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
528    ) {
529        let tcx = self.cx();
530        let param_env = self.param_env();
531        self.register_goals(
532            obligations.into_iter().map(|to_pred| Goal::new(tcx, param_env, to_pred)),
533        );
534    }
535
536    fn register_goals(
537        &mut self,
538        obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
539    ) {
540        let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
541            self.locations,
542            self.category,
543            InstantiateOpaqueType {
544                obligations: obligations
545                    .into_iter()
546                    .map(|goal| {
547                        Obligation::new(
548                            self.cx(),
549                            ObligationCause::dummy_with_span(self.span()),
550                            goal.param_env,
551                            goal.predicate,
552                        )
553                    })
554                    .collect(),
555                // These fields are filled in during execution of the operation
556                base_universe: None,
557                region_constraints: None,
558            },
559        );
560    }
561
562    fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
563        self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
564            ty::Covariant => ty::PredicateKind::AliasRelate(
565                a.into(),
566                b.into(),
567                ty::AliasRelationDirection::Subtype,
568            ),
569            // a :> b is b <: a
570            ty::Contravariant => ty::PredicateKind::AliasRelate(
571                b.into(),
572                a.into(),
573                ty::AliasRelationDirection::Subtype,
574            ),
575            ty::Invariant => ty::PredicateKind::AliasRelate(
576                a.into(),
577                b.into(),
578                ty::AliasRelationDirection::Equate,
579            ),
580            ty::Bivariant => {
581                unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)")
582            }
583        })]);
584    }
585}