• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::infer::InferCtxt;
2 use crate::traits::{ObligationCause, ObligationCtxt};
3 use rustc_data_structures::fx::FxIndexSet;
4 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
5 use rustc_infer::infer::InferOk;
6 use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
7 use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
8 use rustc_span::def_id::LocalDefId;
9 
10 pub use rustc_middle::traits::query::OutlivesBound;
11 
12 pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
13 pub trait InferCtxtExt<'a, 'tcx> {
implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ty: Ty<'tcx>, ) -> Vec<OutlivesBound<'tcx>>14     fn implied_outlives_bounds(
15         &self,
16         param_env: ty::ParamEnv<'tcx>,
17         body_id: LocalDefId,
18         ty: Ty<'tcx>,
19     ) -> Vec<OutlivesBound<'tcx>>;
20 
implied_bounds_tys( &'a self, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, tys: FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx>21     fn implied_bounds_tys(
22         &'a self,
23         param_env: ty::ParamEnv<'tcx>,
24         body_id: LocalDefId,
25         tys: FxIndexSet<Ty<'tcx>>,
26     ) -> Bounds<'a, 'tcx>;
27 }
28 
29 impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
30     /// Implied bounds are region relationships that we deduce
31     /// automatically. The idea is that (e.g.) a caller must check that a
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:
36     /// ```
37     /// fn foo<T>(x: &T) {}
38     /// ```
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.
49     #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ty: Ty<'tcx>, ) -> Vec<OutlivesBound<'tcx>>50     fn implied_outlives_bounds(
51         &self,
52         param_env: ty::ParamEnv<'tcx>,
53         body_id: LocalDefId,
54         ty: Ty<'tcx>,
55     ) -> Vec<OutlivesBound<'tcx>> {
56         let ty = self.resolve_vars_if_possible(ty);
57         let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
58 
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![];
88         };
89         assert_eq!(&obligations, &[]);
90 
91         if !constraints.is_empty() {
92             let span = self.tcx.def_span(body_id);
93 
94             debug!(?constraints);
95             if !constraints.member_constraints.is_empty() {
96                 span_bug!(span, "{:#?}", constraints.member_constraints);
97             }
98 
99             // Instantiation may have produced new inference variables and constraints on those
100             // variables. Process these constraints.
101             let ocx = ObligationCtxt::new(self);
102             let cause = ObligationCause::misc(span, body_id);
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                 ));
109             }
110 
111             let errors = ocx.select_all_or_error();
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         };
119 
120         value
121     }
122 
implied_bounds_tys( &'a self, param_env: ParamEnv<'tcx>, body_id: LocalDefId, tys: FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx>123     fn implied_bounds_tys(
124         &'a self,
125         param_env: ParamEnv<'tcx>,
126         body_id: LocalDefId,
127         tys: FxIndexSet<Ty<'tcx>>,
128     ) -> Bounds<'a, 'tcx> {
129         tys.into_iter().flat_map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
130     }
131 }
132