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::infer::resolve::DeepRegionResolver;
4use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
5use rustc_macros::extension;
6use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
7pub use rustc_middle::traits::query::OutlivesBound;
8use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
9use rustc_span::def_id::LocalDefId;
10use tracing::instrument;
11
12use crate::infer::InferCtxt;
13use crate::traits::ObligationCause;
14
15/// Implied bounds are region relationships that we deduce
16/// automatically. The idea is that (e.g.) a caller must check that a
17/// function's argument types are well-formed immediately before
18/// calling that fn, and hence the *callee* can assume that its
19/// argument types are well-formed. This may imply certain relationships
20/// between generic parameters. For example:
21/// ```
22/// fn foo<T>(x: &T) {}
23/// ```
24/// can only be called with a `'a` and `T` such that `&'a T` is WF.
25/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
26///
27/// # Parameters
28///
29/// - `param_env`, the where-clauses in scope
30/// - `body_def_id`, the body_def_id to use when normalizing assoc types.
31///   Note that this may cause outlives obligations to be injected
32///   into the inference context with this body-id.
33/// - `ty`, the type that we are supposed to assume is WF.
34{}
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/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs"),
                                ::tracing_core::__macro_support::Option::Some(34u32),
                                ::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_ignoring_regions(ty);
                        let ty = DeepRegionResolver::new(infcx).fold_ty(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/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs:34",
                        "rustc_trait_selection::traits::outlives_bounds",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs"),
                        ::tracing_core::__macro_support::Option::Some(34u32),
                        ::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)]
35fn implied_outlives_bounds<'a, 'tcx>(
36    infcx: &'a InferCtxt<'tcx>,
37    param_env: ty::ParamEnv<'tcx>,
38    body_def_id: LocalDefId,
39    ty: Ty<'tcx>,
40    disable_implied_bounds_hack: bool,
41) -> Vec<OutlivesBound<'tcx>> {
42    let ty = infcx.deeply_resolve_ignoring_regions(ty);
43    let ty = DeepRegionResolver::new(infcx).fold_ty(ty);
44
45    // We do not expect existential variables in implied bounds.
46    // We may however encounter unconstrained lifetime variables
47    // in very rare cases.
48    //
49    // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
50    // an example.
51    assert!(!ty.has_non_region_infer());
52
53    let mut canonical_var_values = OriginalQueryValues::default();
54    let input = ImpliedOutlivesBounds { ty };
55    let canonical = infcx.canonicalize_query(param_env.and(input), &mut canonical_var_values);
56    let implied_bounds_result =
57        infcx.tcx.implied_outlives_bounds((canonical, disable_implied_bounds_hack));
58    let Ok(canonical_result) = implied_bounds_result else {
59        return vec![];
60    };
61
62    let mut constraints = QueryRegionConstraints::default();
63    let span = infcx.tcx.def_span(body_def_id);
64    let Ok(InferOk { value: mut bounds, obligations }) = infcx
65        .instantiate_nll_query_response_and_region_obligations(
66            &ObligationCause::dummy_with_span(span),
67            param_env,
68            &canonical_var_values,
69            canonical_result,
70            &mut constraints,
71        )
72    else {
73        return vec![];
74    };
75    assert_eq!(obligations.len(), 0);
76
77    // Because of #109628, we may have unexpected placeholders. Ignore them!
78    // FIXME(#109628): panic in this case once the issue is fixed.
79    bounds.retain(|bound| !bound.has_placeholders());
80
81    if !constraints.is_empty() {
82        // FIXME(higher_ranked_auto): Should we register assumptions here?
83        // We otherwise would get spurious errors if normalizing an implied
84        // outlives bound required proving some higher-ranked coroutine obl.
85        let QueryRegionConstraints { constraints, assumptions: _ } = constraints;
86        let cause = ObligationCause::misc(span, body_def_id);
87        for &QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in &constraints {
88            match constraint {
89                ty::RegionConstraint::Outlives(predicate) => {
90                    infcx.register_outlives_constraint(predicate, vis, &cause)
91                }
92                ty::RegionConstraint::Eq(predicate) => {
93                    infcx.register_region_eq_constraint(predicate, vis, &cause)
94                }
95            }
96        }
97    };
98
99    bounds
100}
101
102pub 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>)]
103impl<'tcx> InferCtxt<'tcx> {
104    /// Do *NOT* call this directly. You probably want to construct a `OutlivesEnvironment`
105    /// instead if you're interested in the implied bounds for a given signature.
106    fn implied_bounds_tys<Tys: IntoIterator<Item = Ty<'tcx>>>(
107        &self,
108        body_def_id: LocalDefId,
109        param_env: ParamEnv<'tcx>,
110        tys: Tys,
111        disable_implied_bounds_hack: bool,
112    ) -> impl Iterator<Item = OutlivesBound<'tcx>> {
113        tys.into_iter().flat_map(move |ty| {
114            implied_outlives_bounds(self, param_env, body_def_id, ty, disable_implied_bounds_hack)
115        })
116    }
117}