Skip to main content

rustc_trait_selection/traits/
outlives_bounds.rs

1use rustc_infer::infer::InferOk;
2use rustc_infer::infer::canonical::QueryRegionConstraint;
3use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
4use rustc_macros::extension;
5use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
6pub use rustc_middle::traits::query::OutlivesBound;
7use rustc_middle::ty::{self, ParamEnv, Ty, TypeVisitableExt};
8use rustc_span::def_id::LocalDefId;
9use tracing::instrument;
10
11use crate::infer::InferCtxt;
12use crate::traits::ObligationCause;
13
14/// Implied bounds are region relationships that we deduce
15/// automatically. The idea is that (e.g.) a caller must check that a
16/// function's argument types are well-formed immediately before
17/// calling that fn, and hence the *callee* can assume that its
18/// argument types are well-formed. This may imply certain relationships
19/// between generic parameters. For example:
20/// ```
21/// fn foo<T>(x: &T) {}
22/// ```
23/// can only be called with a `'a` and `T` such that `&'a T` is WF.
24/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
25///
26/// # Parameters
27///
28/// - `param_env`, the where-clauses in scope
29/// - `body_def_id`, the body_def_id to use when normalizing assoc types.
30///   Note that this may cause outlives obligations to be injected
31///   into the inference context with this body-id.
32/// - `ty`, the type that we are supposed to assume is WF.
33{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::DEBUG <=
                ::tracing::level_filters::LevelFilter::current() || { false }
    {
    __tracing_attr_span =
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("implied_outlives_bounds",
                                "rustc_trait_selection::traits::outlives_bounds",
                                ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/c36f1457196e315bc204b9564a6a5a7fe7f5a51f/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs"),
                                ::tracing_core::__macro_support::Option::Some(33u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::outlives_bounds"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("ty")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("ty");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("disable_implied_bounds_hack")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("disable_implied_bounds_hack");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        { interest = __CALLSITE.interest(); !interest.is_never() }
                    &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest) {
                let meta = __CALLSITE.metadata();
                ::tracing::Span::new(meta,
                    &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&disable_implied_bounds_hack
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return: Vec<OutlivesBound<'tcx>> =
                            loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let ty = infcx.deeply_resolve_via_unification_table(ty);
                        if !!ty.has_non_region_infer() {
                            ::core::panicking::panic("assertion failed: !ty.has_non_region_infer()")
                        };
                        let mut canonical_var_values =
                            OriginalQueryValues::default();
                        let input = ImpliedOutlivesBounds { ty };
                        let canonical =
                            infcx.canonicalize_query(param_env.and(input),
                                &mut canonical_var_values);
                        let implied_bounds_result =
                            infcx.tcx.implied_outlives_bounds((canonical,
                                    disable_implied_bounds_hack));
                        let Ok(canonical_result) =
                            implied_bounds_result else {
                                return ::alloc::vec::Vec::new();
                            };
                        let mut constraints = QueryRegionConstraints::default();
                        let span = infcx.tcx.def_span(body_def_id);
                        let Ok(InferOk { value: mut bounds, obligations }) =
                            infcx.instantiate_nll_query_response_and_region_obligations(&ObligationCause::dummy_with_span(span),
                                param_env, &canonical_var_values, canonical_result,
                                &mut constraints) else { return ::alloc::vec::Vec::new(); };
                        {
                            match (&obligations.len(), &0) {
                                (left_val, right_val) => {
                                    if !(*left_val == *right_val) {
                                        let kind = ::core::panicking::AssertKind::Eq;
                                        ::core::panicking::assert_failed(kind, &*left_val,
                                            &*right_val, ::core::option::Option::None);
                                    }
                                }
                            }
                        };
                        bounds.retain(|bound| !bound.has_placeholders());
                        if !constraints.is_empty() {
                            let QueryRegionConstraints { constraints, assumptions: _ } =
                                constraints;
                            let cause = ObligationCause::misc(span, body_def_id);
                            for &QueryRegionConstraint {
                                constraint, visible_for_leak_check: vis, .. } in
                                &constraints {
                                match constraint {
                                    ty::RegionConstraint::Outlives(predicate) => {
                                        infcx.register_outlives_constraint(predicate, vis, &cause)
                                    }
                                    ty::RegionConstraint::Eq(predicate) => {
                                        infcx.register_region_eq_constraint(predicate, vis, &cause)
                                    }
                                }
                            }
                        };
                        bounds
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/c36f1457196e315bc204b9564a6a5a7fe7f5a51f/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs:33",
                        "rustc_trait_selection::traits::outlives_bounds",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/c36f1457196e315bc204b9564a6a5a7fe7f5a51f/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs"),
                        ::tracing_core::__macro_support::Option::Some(33u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::outlives_bounds"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "debug", skip(infcx, param_env, body_def_id), ret)]
34fn implied_outlives_bounds<'a, 'tcx>(
35    infcx: &'a InferCtxt<'tcx>,
36    param_env: ty::ParamEnv<'tcx>,
37    body_def_id: LocalDefId,
38    ty: Ty<'tcx>,
39    disable_implied_bounds_hack: bool,
40) -> Vec<OutlivesBound<'tcx>> {
41    let ty = infcx.deeply_resolve_via_unification_table(ty);
42
43    // We do not expect existential variables in implied bounds.
44    // We may however encounter unconstrained lifetime variables
45    // in very rare cases.
46    //
47    // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
48    // an example.
49    assert!(!ty.has_non_region_infer());
50
51    let mut canonical_var_values = OriginalQueryValues::default();
52    let input = ImpliedOutlivesBounds { ty };
53    let canonical = infcx.canonicalize_query(param_env.and(input), &mut canonical_var_values);
54    let implied_bounds_result =
55        infcx.tcx.implied_outlives_bounds((canonical, disable_implied_bounds_hack));
56    let Ok(canonical_result) = implied_bounds_result else {
57        return vec![];
58    };
59
60    let mut constraints = QueryRegionConstraints::default();
61    let span = infcx.tcx.def_span(body_def_id);
62    let Ok(InferOk { value: mut bounds, obligations }) = infcx
63        .instantiate_nll_query_response_and_region_obligations(
64            &ObligationCause::dummy_with_span(span),
65            param_env,
66            &canonical_var_values,
67            canonical_result,
68            &mut constraints,
69        )
70    else {
71        return vec![];
72    };
73    assert_eq!(obligations.len(), 0);
74
75    // Because of #109628, we may have unexpected placeholders. Ignore them!
76    // FIXME(#109628): panic in this case once the issue is fixed.
77    bounds.retain(|bound| !bound.has_placeholders());
78
79    if !constraints.is_empty() {
80        // FIXME(higher_ranked_auto): Should we register assumptions here?
81        // We otherwise would get spurious errors if normalizing an implied
82        // outlives bound required proving some higher-ranked coroutine obl.
83        let QueryRegionConstraints { constraints, assumptions: _ } = constraints;
84        let cause = ObligationCause::misc(span, body_def_id);
85        for &QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in &constraints {
86            match constraint {
87                ty::RegionConstraint::Outlives(predicate) => {
88                    infcx.register_outlives_constraint(predicate, vis, &cause)
89                }
90                ty::RegionConstraint::Eq(predicate) => {
91                    infcx.register_region_eq_constraint(predicate, vis, &cause)
92                }
93            }
94        }
95    };
96
97    bounds
98}
99
100pub trait InferCtxtExt<'tcx> {
    #[doc =
    " Do *NOT* call this directly. You probably want to construct a `OutlivesEnvironment`"]
    #[doc =
    " instead if you\'re interested in the implied bounds for a given signature."]
    fn implied_bounds_tys<Tys: IntoIterator<Item =
    Ty<'tcx>>>(&self, body_def_id: LocalDefId, param_env: ParamEnv<'tcx>,
    tys: Tys, disable_implied_bounds_hack: bool)
    -> impl Iterator<Item = OutlivesBound<'tcx>>;
}
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
    #[doc =
    " Do *NOT* call this directly. You probably want to construct a `OutlivesEnvironment`"]
    #[doc =
    " instead if you\'re interested in the implied bounds for a given signature."]
    fn implied_bounds_tys<Tys: IntoIterator<Item =
        Ty<'tcx>>>(&self, body_def_id: LocalDefId, param_env: ParamEnv<'tcx>,
        tys: Tys, disable_implied_bounds_hack: bool)
        -> impl Iterator<Item = OutlivesBound<'tcx>> {
        tys.into_iter().flat_map(move |ty|
                {
                    implied_outlives_bounds(self, param_env, body_def_id, ty,
                        disable_implied_bounds_hack)
                })
    }
}#[extension(pub trait InferCtxtExt<'tcx>)]
101impl<'tcx> InferCtxt<'tcx> {
102    /// Do *NOT* call this directly. You probably want to construct a `OutlivesEnvironment`
103    /// instead if you're interested in the implied bounds for a given signature.
104    fn implied_bounds_tys<Tys: IntoIterator<Item = Ty<'tcx>>>(
105        &self,
106        body_def_id: LocalDefId,
107        param_env: ParamEnv<'tcx>,
108        tys: Tys,
109        disable_implied_bounds_hack: bool,
110    ) -> impl Iterator<Item = OutlivesBound<'tcx>> {
111        tys.into_iter().flat_map(move |ty| {
112            implied_outlives_bounds(self, param_env, body_def_id, ty, disable_implied_bounds_hack)
113        })
114    }
115}