rustc_infer/infer/outlives/
obligations.rs

1//! Code that handles "type-outlives" constraints like `T: 'a`. This
2//! is based on the `push_outlives_components` function defined in rustc_infer,
3//! but it adds a bit of heuristics on top, in particular to deal with
4//! associated types and projections.
5//!
6//! When we process a given `T: 'a` obligation, we may produce two
7//! kinds of constraints for the region inferencer:
8//!
9//! - Relationships between inference variables and other regions.
10//!   For example, if we have `&'?0 u32: 'a`, then we would produce
11//!   a constraint that `'a <= '?0`.
12//! - "Verifys" that must be checked after inferencing is done.
13//!   For example, if we know that, for some type parameter `T`,
14//!   `T: 'a + 'b`, and we have a requirement that `T: '?1`,
15//!   then we add a "verify" that checks that `'?1 <= 'a || '?1 <= 'b`.
16//!   - Note the difference with the previous case: here, the region
17//!     variable must be less than something else, so this doesn't
18//!     affect how inference works (it finds the smallest region that
19//!     will do); it's just a post-condition that we have to check.
20//!
21//! **The key point is that once this function is done, we have
22//! reduced all of our "type-region outlives" obligations into relationships
23//! between individual regions.**
24//!
25//! One key input to this function is the set of "region-bound pairs".
26//! These are basically the relationships between type parameters and
27//! regions that are in scope at the point where the outlives
28//! obligation was incurred. **When type-checking a function,
29//! particularly in the face of closures, this is not known until
30//! regionck runs!** This is because some of those bounds come
31//! from things we have yet to infer.
32//!
33//! Consider:
34//!
35//! ```
36//! fn bar<T>(a: T, b: impl for<'a> Fn(&'a T)) {}
37//! fn foo<T>(x: T) {
38//!     bar(x, |y| { /* ... */})
39//!     //      ^ closure arg
40//! }
41//! ```
42//!
43//! Here, the type of `y` may involve inference variables and the
44//! like, and it may also contain implied bounds that are needed to
45//! type-check the closure body (e.g., here it informs us that `T`
46//! outlives the late-bound region `'a`).
47//!
48//! Note that by delaying the gathering of implied bounds until all
49//! inference information is known, we may find relationships between
50//! bound regions and other regions in the environment. For example,
51//! when we first check a closure like the one expected as argument
52//! to `foo`:
53//!
54//! ```
55//! fn foo<U, F: for<'a> FnMut(&'a U)>(_f: F) {}
56//! ```
57//!
58//! the type of the closure's first argument would be `&'a ?U`. We
59//! might later infer `?U` to something like `&'b u32`, which would
60//! imply that `'b: 'a`.
61
62use rustc_data_structures::undo_log::UndoLogs;
63use rustc_middle::bug;
64use rustc_middle::mir::ConstraintCategory;
65use rustc_middle::traits::query::NoSolution;
66use rustc_middle::ty::outlives::{Component, push_outlives_components};
67use rustc_middle::ty::{
68    self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt,
69    TypeFoldable as _, TypeVisitableExt,
70};
71use smallvec::smallvec;
72use tracing::{debug, instrument};
73
74use super::env::OutlivesEnvironment;
75use crate::infer::outlives::env::RegionBoundPairs;
76use crate::infer::outlives::verify::VerifyBoundCx;
77use crate::infer::resolve::OpportunisticRegionResolver;
78use crate::infer::snapshot::undo_log::UndoLog;
79use crate::infer::{
80    self, GenericKind, InferCtxt, SubregionOrigin, TypeOutlivesConstraint, VerifyBound,
81};
82use crate::traits::{ObligationCause, ObligationCauseCode};
83
84impl<'tcx> InferCtxt<'tcx> {
85    pub fn register_outlives_constraint(
86        &self,
87        ty::OutlivesPredicate(arg, r2): ty::ArgOutlivesPredicate<'tcx>,
88        cause: &ObligationCause<'tcx>,
89    ) {
90        match arg.kind() {
91            ty::GenericArgKind::Lifetime(r1) => {
92                self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), cause);
93            }
94            ty::GenericArgKind::Type(ty1) => {
95                self.register_type_outlives_constraint(ty1, r2, cause);
96            }
97            ty::GenericArgKind::Const(_) => unreachable!(),
98        }
99    }
100
101    pub fn register_region_outlives_constraint(
102        &self,
103        ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>,
104        cause: &ObligationCause<'tcx>,
105    ) {
106        let origin = SubregionOrigin::from_obligation_cause(cause, || {
107            SubregionOrigin::RelateRegionParamBound(cause.span, None)
108        });
109        // `'a: 'b` ==> `'b <= 'a`
110        self.sub_regions(origin, r_b, r_a);
111    }
112
113    /// Registers that the given region obligation must be resolved
114    /// from within the scope of `body_id`. These regions are enqueued
115    /// and later processed by regionck, when full type information is
116    /// available (see `region_obligations` field for more
117    /// information).
118    #[instrument(level = "debug", skip(self))]
119    pub fn register_type_outlives_constraint_inner(
120        &self,
121        obligation: TypeOutlivesConstraint<'tcx>,
122    ) {
123        let mut inner = self.inner.borrow_mut();
124        inner.undo_log.push(UndoLog::PushTypeOutlivesConstraint);
125        inner.region_obligations.push(obligation);
126    }
127
128    pub fn register_type_outlives_constraint(
129        &self,
130        sup_type: Ty<'tcx>,
131        sub_region: Region<'tcx>,
132        cause: &ObligationCause<'tcx>,
133    ) {
134        // `is_global` means the type has no params, infer, placeholder, or non-`'static`
135        // free regions. If the type has none of these things, then we can skip registering
136        // this outlives obligation since it has no components which affect lifetime
137        // checking in an interesting way.
138        if sup_type.is_global() {
139            return;
140        }
141
142        debug!(?sup_type, ?sub_region, ?cause);
143        let origin = SubregionOrigin::from_obligation_cause(cause, || {
144            SubregionOrigin::RelateParamBound(
145                cause.span,
146                sup_type,
147                match cause.code().peel_derives() {
148                    ObligationCauseCode::WhereClause(_, span)
149                    | ObligationCauseCode::WhereClauseInExpr(_, span, ..)
150                    | ObligationCauseCode::OpaqueTypeBound(span, _)
151                        if !span.is_dummy() =>
152                    {
153                        Some(*span)
154                    }
155                    _ => None,
156                },
157            )
158        });
159
160        self.register_type_outlives_constraint_inner(TypeOutlivesConstraint {
161            sup_type,
162            sub_region,
163            origin,
164        });
165    }
166
167    /// Trait queries just want to pass back type obligations "as is"
168    pub fn take_registered_region_obligations(&self) -> Vec<TypeOutlivesConstraint<'tcx>> {
169        assert!(!self.in_snapshot(), "cannot take registered region obligations in a snapshot");
170        std::mem::take(&mut self.inner.borrow_mut().region_obligations)
171    }
172
173    pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) {
174        let mut inner = self.inner.borrow_mut();
175        inner.undo_log.push(UndoLog::PushRegionAssumption);
176        inner.region_assumptions.push(assumption);
177    }
178
179    pub fn take_registered_region_assumptions(&self) -> Vec<ty::ArgOutlivesPredicate<'tcx>> {
180        assert!(!self.in_snapshot(), "cannot take registered region assumptions in a snapshot");
181        std::mem::take(&mut self.inner.borrow_mut().region_assumptions)
182    }
183
184    /// Process the region obligations that must be proven (during
185    /// `regionck`) for the given `body_id`, given information about
186    /// the region bounds in scope and so forth.
187    ///
188    /// See the `region_obligations` field of `InferCtxt` for some
189    /// comments about how this function fits into the overall expected
190    /// flow of the inferencer. The key point is that it is
191    /// invoked after all type-inference variables have been bound --
192    /// right before lexical region resolution.
193    #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
194    pub fn process_registered_region_obligations(
195        &self,
196        outlives_env: &OutlivesEnvironment<'tcx>,
197        mut deeply_normalize_ty: impl FnMut(
198            PolyTypeOutlivesPredicate<'tcx>,
199            SubregionOrigin<'tcx>,
200        )
201            -> Result<PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
202    ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
203        assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
204
205        // Must loop since the process of normalizing may itself register region obligations.
206        for iteration in 0.. {
207            let my_region_obligations = self.take_registered_region_obligations();
208            if my_region_obligations.is_empty() {
209                break;
210            }
211
212            if !self.tcx.recursion_limit().value_within_limit(iteration) {
213                // This may actually be reachable. If so, we should convert
214                // this to a proper error/consider whether we should detect
215                // this somewhere else.
216                bug!(
217                    "unexpected overflowed when processing region obligations: {my_region_obligations:#?}"
218                );
219            }
220
221            for TypeOutlivesConstraint { sup_type, sub_region, origin } in my_region_obligations {
222                let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region));
223                let ty::OutlivesPredicate(sup_type, sub_region) =
224                    deeply_normalize_ty(outlives, origin.clone())
225                        .map_err(|NoSolution| (outlives, origin.clone()))?
226                        .no_bound_vars()
227                        .expect("started with no bound vars, should end with no bound vars");
228                // `TypeOutlives` is structural, so we should try to opportunistically resolve all
229                // region vids before processing regions, so we have a better chance to match clauses
230                // in our param-env.
231                let (sup_type, sub_region) =
232                    (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self));
233
234                if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
235                    && outlives_env
236                        .higher_ranked_assumptions()
237                        .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region))
238                {
239                    continue;
240                }
241
242                debug!(?sup_type, ?sub_region, ?origin);
243
244                let outlives = &mut TypeOutlives::new(
245                    self,
246                    self.tcx,
247                    outlives_env.region_bound_pairs(),
248                    None,
249                    outlives_env.known_type_outlives(),
250                );
251                let category = origin.to_constraint_category();
252                outlives.type_must_outlive(origin, sup_type, sub_region, category);
253            }
254        }
255
256        Ok(())
257    }
258}
259
260/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
261/// obligation into a series of `'a: 'b` constraints and "verify"s, as
262/// described on the module comment. The final constraints are emitted
263/// via a "delegate" of type `D` -- this is usually the `infcx`, which
264/// accrues them into the `region_obligations` code, but for NLL we
265/// use something else.
266pub struct TypeOutlives<'cx, 'tcx, D>
267where
268    D: TypeOutlivesDelegate<'tcx>,
269{
270    // See the comments on `process_registered_region_obligations` for the meaning
271    // of these fields.
272    delegate: D,
273    tcx: TyCtxt<'tcx>,
274    verify_bound: VerifyBoundCx<'cx, 'tcx>,
275}
276
277pub trait TypeOutlivesDelegate<'tcx> {
278    fn push_sub_region_constraint(
279        &mut self,
280        origin: SubregionOrigin<'tcx>,
281        a: ty::Region<'tcx>,
282        b: ty::Region<'tcx>,
283        constraint_category: ConstraintCategory<'tcx>,
284    );
285
286    fn push_verify(
287        &mut self,
288        origin: SubregionOrigin<'tcx>,
289        kind: GenericKind<'tcx>,
290        a: ty::Region<'tcx>,
291        bound: VerifyBound<'tcx>,
292    );
293}
294
295impl<'cx, 'tcx, D> TypeOutlives<'cx, 'tcx, D>
296where
297    D: TypeOutlivesDelegate<'tcx>,
298{
299    pub fn new(
300        delegate: D,
301        tcx: TyCtxt<'tcx>,
302        region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
303        implicit_region_bound: Option<ty::Region<'tcx>>,
304        caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>],
305    ) -> Self {
306        Self {
307            delegate,
308            tcx,
309            verify_bound: VerifyBoundCx::new(
310                tcx,
311                region_bound_pairs,
312                implicit_region_bound,
313                caller_bounds,
314            ),
315        }
316    }
317
318    /// Adds constraints to inference such that `T: 'a` holds (or
319    /// reports an error if it cannot).
320    ///
321    /// # Parameters
322    ///
323    /// - `origin`, the reason we need this constraint
324    /// - `ty`, the type `T`
325    /// - `region`, the region `'a`
326    #[instrument(level = "debug", skip(self))]
327    pub fn type_must_outlive(
328        &mut self,
329        origin: infer::SubregionOrigin<'tcx>,
330        ty: Ty<'tcx>,
331        region: ty::Region<'tcx>,
332        category: ConstraintCategory<'tcx>,
333    ) {
334        assert!(!ty.has_escaping_bound_vars());
335
336        let mut components = smallvec![];
337        push_outlives_components(self.tcx, ty, &mut components);
338        self.components_must_outlive(origin, &components, region, category);
339    }
340
341    fn components_must_outlive(
342        &mut self,
343        origin: infer::SubregionOrigin<'tcx>,
344        components: &[Component<TyCtxt<'tcx>>],
345        region: ty::Region<'tcx>,
346        category: ConstraintCategory<'tcx>,
347    ) {
348        for component in components.iter() {
349            let origin = origin.clone();
350            match component {
351                Component::Region(region1) => {
352                    self.delegate.push_sub_region_constraint(origin, region, *region1, category);
353                }
354                Component::Param(param_ty) => {
355                    self.param_ty_must_outlive(origin, region, *param_ty);
356                }
357                Component::Placeholder(placeholder_ty) => {
358                    self.placeholder_ty_must_outlive(origin, region, *placeholder_ty);
359                }
360                Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty),
361                Component::EscapingAlias(subcomponents) => {
362                    self.components_must_outlive(origin, subcomponents, region, category);
363                }
364                Component::UnresolvedInferenceVariable(v) => {
365                    // Ignore this, we presume it will yield an error later,
366                    // since if a type variable is not resolved by this point
367                    // it never will be.
368                    self.tcx.dcx().span_delayed_bug(
369                        origin.span(),
370                        format!("unresolved inference variable in outlives: {v:?}"),
371                    );
372                }
373            }
374        }
375    }
376
377    #[instrument(level = "debug", skip(self))]
378    fn param_ty_must_outlive(
379        &mut self,
380        origin: infer::SubregionOrigin<'tcx>,
381        region: ty::Region<'tcx>,
382        param_ty: ty::ParamTy,
383    ) {
384        let verify_bound = self.verify_bound.param_or_placeholder_bound(param_ty.to_ty(self.tcx));
385        self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound);
386    }
387
388    #[instrument(level = "debug", skip(self))]
389    fn placeholder_ty_must_outlive(
390        &mut self,
391        origin: infer::SubregionOrigin<'tcx>,
392        region: ty::Region<'tcx>,
393        placeholder_ty: ty::PlaceholderType,
394    ) {
395        let verify_bound = self
396            .verify_bound
397            .param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty));
398        self.delegate.push_verify(
399            origin,
400            GenericKind::Placeholder(placeholder_ty),
401            region,
402            verify_bound,
403        );
404    }
405
406    #[instrument(level = "debug", skip(self))]
407    fn alias_ty_must_outlive(
408        &mut self,
409        origin: infer::SubregionOrigin<'tcx>,
410        region: ty::Region<'tcx>,
411        alias_ty: ty::AliasTy<'tcx>,
412    ) {
413        // An optimization for a common case with opaque types.
414        if alias_ty.args.is_empty() {
415            return;
416        }
417
418        if alias_ty.has_non_region_infer() {
419            self.tcx
420                .dcx()
421                .span_delayed_bug(origin.span(), "an alias has infers during region solving");
422            return;
423        }
424
425        // This case is thorny for inference. The fundamental problem is
426        // that there are many cases where we have choice, and inference
427        // doesn't like choice (the current region inference in
428        // particular). :) First off, we have to choose between using the
429        // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and
430        // OutlivesProjectionComponent rules, any one of which is
431        // sufficient. If there are no inference variables involved, it's
432        // not hard to pick the right rule, but if there are, we're in a
433        // bit of a catch 22: if we picked which rule we were going to
434        // use, we could add constraints to the region inference graph
435        // that make it apply, but if we don't add those constraints, the
436        // rule might not apply (but another rule might). For now, we err
437        // on the side of adding too few edges into the graph.
438
439        // Compute the bounds we can derive from the trait definition.
440        // These are guaranteed to apply, no matter the inference
441        // results.
442        let trait_bounds: Vec<_> =
443            self.verify_bound.declared_bounds_from_definition(alias_ty).collect();
444
445        debug!(?trait_bounds);
446
447        // Compute the bounds we can derive from the environment. This
448        // is an "approximate" match -- in some cases, these bounds
449        // may not apply.
450        let approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty);
451        debug!(?approx_env_bounds);
452
453        // If declared bounds list is empty, the only applicable rule is
454        // OutlivesProjectionComponent. If there are inference variables,
455        // then, we can break down the outlives into more primitive
456        // components without adding unnecessary edges.
457        //
458        // If there are *no* inference variables, however, we COULD do
459        // this, but we choose not to, because the error messages are less
460        // good. For example, a requirement like `T::Item: 'r` would be
461        // translated to a requirement that `T: 'r`; when this is reported
462        // to the user, it will thus say "T: 'r must hold so that T::Item:
463        // 'r holds". But that makes it sound like the only way to fix
464        // the problem is to add `T: 'r`, which isn't true. So, if there are no
465        // inference variables, we use a verify constraint instead of adding
466        // edges, which winds up enforcing the same condition.
467        let kind = alias_ty.kind(self.tcx);
468        if approx_env_bounds.is_empty()
469            && trait_bounds.is_empty()
470            && (alias_ty.has_infer_regions() || kind == ty::Opaque)
471        {
472            debug!("no declared bounds");
473            let opt_variances = self.tcx.opt_alias_variances(kind, alias_ty.def_id);
474            self.args_must_outlive(alias_ty.args, origin, region, opt_variances);
475            return;
476        }
477
478        // If we found a unique bound `'b` from the trait, and we
479        // found nothing else from the environment, then the best
480        // action is to require that `'b: 'r`, so do that.
481        //
482        // This is best no matter what rule we use:
483        //
484        // - OutlivesProjectionEnv: these would translate to the requirement that `'b:'r`
485        // - OutlivesProjectionTraitDef: these would translate to the requirement that `'b:'r`
486        // - OutlivesProjectionComponent: this would require `'b:'r`
487        //   in addition to other conditions
488        if !trait_bounds.is_empty()
489            && trait_bounds[1..]
490                .iter()
491                .map(|r| Some(*r))
492                .chain(
493                    // NB: The environment may contain `for<'a> T: 'a` style bounds.
494                    // In that case, we don't know if they are equal to the trait bound
495                    // or not (since we don't *know* whether the environment bound even applies),
496                    // so just map to `None` here if there are bound vars, ensuring that
497                    // the call to `all` will fail below.
498                    approx_env_bounds.iter().map(|b| b.map_bound(|b| b.1).no_bound_vars()),
499                )
500                .all(|b| b == Some(trait_bounds[0]))
501        {
502            let unique_bound = trait_bounds[0];
503            debug!(?unique_bound);
504            debug!("unique declared bound appears in trait ref");
505            let category = origin.to_constraint_category();
506            self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
507            return;
508        }
509
510        // Fallback to verifying after the fact that there exists a
511        // declared bound, or that all the components appearing in the
512        // projection outlive; in some cases, this may add insufficient
513        // edges into the inference graph, leading to inference failures
514        // even though a satisfactory solution exists.
515        let verify_bound = self.verify_bound.alias_bound(alias_ty);
516        debug!("alias_must_outlive: pushing {:?}", verify_bound);
517        self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
518    }
519
520    #[instrument(level = "debug", skip(self))]
521    fn args_must_outlive(
522        &mut self,
523        args: GenericArgsRef<'tcx>,
524        origin: infer::SubregionOrigin<'tcx>,
525        region: ty::Region<'tcx>,
526        opt_variances: Option<&[ty::Variance]>,
527    ) {
528        let constraint = origin.to_constraint_category();
529        for (index, arg) in args.iter().enumerate() {
530            match arg.kind() {
531                GenericArgKind::Lifetime(lt) => {
532                    let variance = if let Some(variances) = opt_variances {
533                        variances[index]
534                    } else {
535                        ty::Invariant
536                    };
537                    if variance == ty::Invariant {
538                        self.delegate.push_sub_region_constraint(
539                            origin.clone(),
540                            region,
541                            lt,
542                            constraint,
543                        );
544                    }
545                }
546                GenericArgKind::Type(ty) => {
547                    self.type_must_outlive(origin.clone(), ty, region, constraint);
548                }
549                GenericArgKind::Const(_) => {
550                    // Const parameters don't impose constraints.
551                }
552            }
553        }
554    }
555}
556
557impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> {
558    fn push_sub_region_constraint(
559        &mut self,
560        origin: SubregionOrigin<'tcx>,
561        a: ty::Region<'tcx>,
562        b: ty::Region<'tcx>,
563        _constraint_category: ConstraintCategory<'tcx>,
564    ) {
565        self.sub_regions(origin, a, b)
566    }
567
568    fn push_verify(
569        &mut self,
570        origin: SubregionOrigin<'tcx>,
571        kind: GenericKind<'tcx>,
572        a: ty::Region<'tcx>,
573        bound: VerifyBound<'tcx>,
574    ) {
575        self.verify_generic_bound(origin, kind, a, bound)
576    }
577}