]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / outlives_bounds.rs
CommitLineData
f2b60f7d 1use crate::infer::InferCtxt;
353b0b11 2use crate::traits::{ObligationCause, ObligationCtxt};
487cf647 3use rustc_data_structures::fx::FxIndexSet;
353b0b11 4use rustc_infer::infer::resolve::OpportunisticRegionResolver;
49aad941
FG
5use rustc_infer::infer::InferOk;
6use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
353b0b11 7use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
9ffffee4 8use rustc_span::def_id::LocalDefId;
8faf50e0 9
ba9703b0 10pub use rustc_middle::traits::query::OutlivesBound;
8faf50e0 11
f2b60f7d
FG
12type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
13pub trait InferCtxtExt<'a, 'tcx> {
ba9703b0
XL
14 fn implied_outlives_bounds(
15 &self,
16 param_env: ty::ParamEnv<'tcx>,
9ffffee4 17 body_id: LocalDefId,
ba9703b0 18 ty: Ty<'tcx>,
ba9703b0 19 ) -> Vec<OutlivesBound<'tcx>>;
f2b60f7d
FG
20
21 fn implied_bounds_tys(
22 &'a self,
23 param_env: ty::ParamEnv<'tcx>,
9ffffee4 24 body_id: LocalDefId,
487cf647 25 tys: FxIndexSet<Ty<'tcx>>,
f2b60f7d 26 ) -> Bounds<'a, 'tcx>;
ba9703b0
XL
27}
28
2b03887a 29impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
8faf50e0 30 /// Implied bounds are region relationships that we deduce
9fa01778 31 /// automatically. The idea is that (e.g.) a caller must check that a
8faf50e0
XL
32 /// function's argument types are well-formed immediately before
33 /// calling that fn, and hence the *callee* can assume that its
34 /// argument types are well-formed. This may imply certain relationships
35 /// between generic parameters. For example:
04454e1e 36 /// ```
9c376795 37 /// fn foo<T>(x: &T) {}
04454e1e 38 /// ```
8faf50e0
XL
39 /// can only be called with a `'a` and `T` such that `&'a T` is WF.
40 /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
41 ///
42 /// # Parameters
43 ///
44 /// - `param_env`, the where-clauses in scope
45 /// - `body_id`, the body-id to use when normalizing assoc types.
46 /// Note that this may cause outlives obligations to be injected
47 /// into the inference context with this body-id.
48 /// - `ty`, the type that we are supposed to assume is WF.
f2b60f7d 49 #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
ba9703b0 50 fn implied_outlives_bounds(
8faf50e0
XL
51 &self,
52 param_env: ty::ParamEnv<'tcx>,
9ffffee4 53 body_id: LocalDefId,
8faf50e0 54 ty: Ty<'tcx>,
8faf50e0 55 ) -> Vec<OutlivesBound<'tcx>> {
353b0b11
FG
56 let ty = self.resolve_vars_if_possible(ty);
57 let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
353b0b11 58
49aad941
FG
59 // We do not expect existential variables in implied bounds.
60 // We may however encounter unconstrained lifetime variables in invalid
61 // code. See #110161 for context.
62 assert!(!ty.has_non_region_infer());
63 if ty.has_infer() {
64 self.tcx.sess.delay_span_bug(
65 self.tcx.def_span(body_id),
66 "skipped implied_outlives_bounds due to unconstrained lifetimes",
67 );
68 return vec![];
69 }
70
71 let mut canonical_var_values = OriginalQueryValues::default();
72 let canonical_ty =
73 self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values);
74 let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else {
75 return vec![];
76 };
77
78 let mut constraints = QueryRegionConstraints::default();
79 let Ok(InferOk { value, obligations }) = self
80 .instantiate_nll_query_response_and_region_obligations(
81 &ObligationCause::dummy(),
82 param_env,
83 &canonical_var_values,
84 canonical_result,
85 &mut constraints,
86 ) else {
87 return vec![];
8faf50e0 88 };
49aad941 89 assert_eq!(&obligations, &[]);
8faf50e0 90
49aad941
FG
91 if !constraints.is_empty() {
92 let span = self.tcx.def_span(body_id);
8faf50e0 93
f2b60f7d 94 debug!(?constraints);
353b0b11
FG
95 if !constraints.member_constraints.is_empty() {
96 span_bug!(span, "{:#?}", constraints.member_constraints);
97 }
98
923072b8
FG
99 // Instantiation may have produced new inference variables and constraints on those
100 // variables. Process these constraints.
353b0b11 101 let ocx = ObligationCtxt::new(self);
923072b8 102 let cause = ObligationCause::misc(span, body_id);
353b0b11
FG
103 for &constraint in &constraints.outlives {
104 ocx.register_obligation(self.query_outlives_constraint_to_obligation(
105 constraint,
106 cause.clone(),
107 param_env,
108 ));
923072b8 109 }
353b0b11
FG
110
111 let errors = ocx.select_all_or_error();
923072b8
FG
112 if !errors.is_empty() {
113 self.tcx.sess.delay_span_bug(
114 span,
115 "implied_outlives_bounds failed to solve obligations from instantiation",
116 );
117 }
118 };
8faf50e0 119
49aad941 120 value
8faf50e0 121 }
f2b60f7d
FG
122
123 fn implied_bounds_tys(
124 &'a self,
125 param_env: ParamEnv<'tcx>,
9ffffee4 126 body_id: LocalDefId,
487cf647 127 tys: FxIndexSet<Ty<'tcx>>,
f2b60f7d 128 ) -> Bounds<'a, 'tcx> {
353b0b11 129 tys.into_iter().flat_map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
f2b60f7d 130 }
8faf50e0 131}