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, ObligationCtxt};
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 } = constraints;
82 let ocx = ObligationCtxt::new(infcx);
85 let cause = ObligationCause::misc(span, body_id);
86 for &constraint in &outlives {
87 ocx.register_obligation(infcx.query_outlives_constraint_to_obligation(
88 constraint,
89 cause.clone(),
90 param_env,
91 ));
92 }
93
94 let errors = ocx.select_all_or_error();
95 if !errors.is_empty() {
96 infcx.dcx().span_bug(
97 span,
98 "implied_outlives_bounds failed to solve obligations from instantiation",
99 );
100 }
101 };
102
103 bounds
104}
105
106#[extension(pub trait InferCtxtExt<'tcx>)]
107impl<'tcx> InferCtxt<'tcx> {
108 fn implied_bounds_tys<Tys: IntoIterator<Item = Ty<'tcx>>>(
111 &self,
112 body_id: LocalDefId,
113 param_env: ParamEnv<'tcx>,
114 tys: Tys,
115 disable_implied_bounds_hack: bool,
116 ) -> impl Iterator<Item = OutlivesBound<'tcx>> {
117 tys.into_iter().flat_map(move |ty| {
118 implied_outlives_bounds(self, param_env, body_id, ty, disable_implied_bounds_hack)
119 })
120 }
121}