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