rustc_borrowck/type_check/
relate_tys.rs

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    /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
27    ///
28    /// - "Covariant" `a <: b`
29    /// - "Invariant" `a == b`
30    /// - "Contravariant" `a :> b`
31    ///
32    /// N.B., the type `a` is permitted to have unresolved inference
33    /// variables, but not the type `b`.
34    #[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    /// Add sufficient constraints to ensure `a == b`. See also [Self::relate_types].
49    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    /// Where (and why) is this relation taking place?
66    locations: Locations,
67
68    /// What category do we assign the resulting `'a: 'b` relationships?
69    category: ConstraintCategory<'tcx>,
70
71    /// Information so that error reporting knows what types we are relating
72    /// when reporting a bound region error.
73    universe_info: UniverseInfo<'tcx>,
74
75    /// How are we relating `a` and `b`?
76    ///
77    /// - Covariant means `a <: b`.
78    /// - Contravariant means `b <: a`.
79    /// - Invariant means `a == b`.
80    /// - Bivariant means that it doesn't matter.
81    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        // `handle_opaque_type` cannot handle subtyping, so to support subtyping
122        // we instead eagerly generalize here. This is a bit of a mess but will go
123        // away once we're using the new solver.
124        //
125        // Given `opaque rel B`, we create a new infer var `ty_vid` constrain it
126        // by using `ty_vid rel B` and then finally and end by equating `ty_vid` to
127        // the opaque.
128        let mut enable_subtyping = |ty, opaque_is_expected| {
129            // We create the fresh inference variable in the highest universe.
130            // In theory we could limit it to the highest universe in the args of
131            // the opaque but that isn't really worth the effort.
132            //
133            // We'll make sure that the opaque type can actually name everything
134            // in its hidden type later on.
135            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                    // The first time this closure is called, create a
179                    // new universe for the placeholders we will make
180                    // from here out.
181                    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            // Avoid fetching the variance if we are in an invariant context,
322            // slightly improves perf.
323            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        // In a bivariant context this always succeeds.
354        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                    // This behavior is only there for the old solver, the new solver
390                    // shouldn't ever fail. Instead, it unconditionally emits an
391                    // alias-relate goal.
392                    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                // Will also handle unification of `IntVar` and `FloatVar`.
411                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            // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
428            self.push_outlives(a, b, self.ambient_variance_info);
429        }
430
431        if self.ambient_contravariance() {
432            // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
433            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        // We want that
461        //
462        // ```
463        // for<'a> fn(&'a u32) -> &'a u32 <:
464        //   fn(&'b u32) -> &'b u32
465        // ```
466        //
467        // but not
468        //
469        // ```
470        // fn(&'a u32) -> &'a u32 <:
471        //   for<'b> fn(&'b u32) -> &'b u32
472        // ```
473        //
474        // We therefore proceed as follows:
475        //
476        // - Instantiate binders on `b` universally, yielding a universe U1.
477        // - Instantiate binders on `a` existentially in U1.
478
479        debug!(?self.ambient_variance);
480
481        if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
482            // Fast path for the common case.
483            self.relate(a, b)?;
484            return Ok(ty::Binder::dummy(a));
485        }
486
487        match self.ambient_variance {
488            ty::Covariant => {
489                // Covariance, so we want `for<..> A <: for<..> B` --
490                // therefore we compare any instantiation of A (i.e., A
491                // instantiated with existentials) against every
492                // instantiation of B (i.e., B instantiated with
493                // universals).
494
495                // Note: the order here is important. Create the placeholders first, otherwise
496                // we assign the wrong universe to the existential!
497                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                // Contravariance, so we want `for<..> A :> for<..> B` --
505                // therefore we compare every instantiation of A (i.e., A
506                // instantiated with universals) against any
507                // instantiation of B (i.e., B instantiated with
508                // existentials). Opposite of above.
509
510                // Note: the order here is important. Create the placeholders first, otherwise
511                // we assign the wrong universe to the existential!
512                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                // Invariant, so we want `for<..> A == for<..> B` --
520                // therefore we want `exists<..> A == for<..> B` and
521                // `exists<..> B == for<..> A`.
522                //
523                // See the comment in `fn Equate::binders` for more details.
524
525                // Note: the order here is important. Create the placeholders first, otherwise
526                // we assign the wrong universe to the existential!
527                self.enter_forall(b, |this, b| {
528                    let a = this.instantiate_binder_with_existentials(a);
529                    this.relate(a, b)
530                })?;
531                // Note: the order here is important. Create the placeholders first, otherwise
532                // we assign the wrong universe to the existential!
533                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                // These fields are filled in during execution of the operation
590                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            // a :> b is b <: a
604            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}