rustc_trait_selection/traits/
outlives_bounds.rs1use rustc_infer::infer::InferOk;
2use rustc_infer::infer::resolve::OpportunisticRegionResolver;
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, TypeFolder, TypeVisitableExt};
8use rustc_span::def_id::LocalDefId;
9use tracing::instrument;
10
11use crate::infer::InferCtxt;
12use crate::traits::ObligationCause;
13
14#[instrument(level = "debug", skip(infcx, param_env, body_id), ret)]
34fn implied_outlives_bounds<'a, 'tcx>(
35    infcx: &'a InferCtxt<'tcx>,
36    param_env: ty::ParamEnv<'tcx>,
37    body_id: LocalDefId,
38    ty: Ty<'tcx>,
39    disable_implied_bounds_hack: bool,
40) -> Vec<OutlivesBound<'tcx>> {
41    let ty = infcx.resolve_vars_if_possible(ty);
42    let ty = OpportunisticRegionResolver::new(infcx).fold_ty(ty);
43
44    assert!(!ty.has_non_region_infer());
51
52    let mut canonical_var_values = OriginalQueryValues::default();
53    let input = ImpliedOutlivesBounds { ty };
54    let canonical = infcx.canonicalize_query(param_env.and(input), &mut canonical_var_values);
55    let implied_bounds_result =
56        infcx.tcx.implied_outlives_bounds((canonical, disable_implied_bounds_hack));
57    let Ok(canonical_result) = implied_bounds_result else {
58        return vec![];
59    };
60
61    let mut constraints = QueryRegionConstraints::default();
62    let span = infcx.tcx.def_span(body_id);
63    let Ok(InferOk { value: mut bounds, obligations }) = infcx
64        .instantiate_nll_query_response_and_region_obligations(
65            &ObligationCause::dummy_with_span(span),
66            param_env,
67            &canonical_var_values,
68            canonical_result,
69            &mut constraints,
70        )
71    else {
72        return vec![];
73    };
74    assert_eq!(obligations.len(), 0);
75
76    bounds.retain(|bound| !bound.has_placeholders());
79
80    if !constraints.is_empty() {
81        let QueryRegionConstraints { outlives, assumptions: _ } = constraints;
85        let cause = ObligationCause::misc(span, body_id);
86        for &(predicate, _) in &outlives {
87            infcx.register_outlives_constraint(predicate, &cause);
88        }
89    };
90
91    bounds
92}
93
94#[extension(pub trait InferCtxtExt<'tcx>)]
95impl<'tcx> InferCtxt<'tcx> {
96    fn implied_bounds_tys<Tys: IntoIterator<Item = Ty<'tcx>>>(
99        &self,
100        body_id: LocalDefId,
101        param_env: ParamEnv<'tcx>,
102        tys: Tys,
103        disable_implied_bounds_hack: bool,
104    ) -> impl Iterator<Item = OutlivesBound<'tcx>> {
105        tys.into_iter().flat_map(move |ty| {
106            implied_outlives_bounds(self, param_env, body_id, ty, disable_implied_bounds_hack)
107        })
108    }
109}