1 use crate::infer::InferCtxt;
2 use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
3 use crate::traits::query::NoSolution;
4 use crate::traits::ObligationCause;
5 use rustc_data_structures::fx::FxIndexSet;
6 use rustc_middle::ty::{self, ParamEnv, Ty};
7 use rustc_span::def_id::LocalDefId;
9 pub use rustc_middle::traits::query::OutlivesBound;
11 type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
12 pub trait InferCtxtExt<'a, 'tcx> {
13 fn implied_outlives_bounds(
15 param_env: ty::ParamEnv<'tcx>,
18 ) -> Vec<OutlivesBound<'tcx>>;
20 fn implied_bounds_tys(
22 param_env: ty::ParamEnv<'tcx>,
24 tys: FxIndexSet<Ty<'tcx>>,
25 ) -> Bounds<'a, 'tcx>;
28 impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
29 /// Implied bounds are region relationships that we deduce
30 /// automatically. The idea is that (e.g.) a caller must check that a
31 /// function's argument types are well-formed immediately before
32 /// calling that fn, and hence the *callee* can assume that its
33 /// argument types are well-formed. This may imply certain relationships
34 /// between generic parameters. For example:
36 /// fn foo<T>(x: &T) {}
38 /// can only be called with a `'a` and `T` such that `&'a T` is WF.
39 /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
43 /// - `param_env`, the where-clauses in scope
44 /// - `body_id`, the body-id to use when normalizing assoc types.
45 /// Note that this may cause outlives obligations to be injected
46 /// into the inference context with this body-id.
47 /// - `ty`, the type that we are supposed to assume is WF.
48 #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
49 fn implied_outlives_bounds(
51 param_env: ty::ParamEnv<'tcx>,
54 ) -> Vec<OutlivesBound<'tcx>> {
55 let span = self.tcx.def_span(body_id);
56 let result = param_env
57 .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
59 let result = match result {
62 self.tcx.sess.delay_span_bug(
64 "implied_outlives_bounds failed to solve all obligations",
70 let TypeOpOutput { output, constraints, .. } = result;
72 if let Some(constraints) = constraints {
74 // Instantiation may have produced new inference variables and constraints on those
75 // variables. Process these constraints.
76 let cause = ObligationCause::misc(span, body_id);
77 let errors = super::fully_solve_obligations(
79 constraints.outlives.iter().map(|constraint| {
80 self.query_outlives_constraint_to_obligation(
87 if !constraints.member_constraints.is_empty() {
88 span_bug!(span, "{:#?}", constraints.member_constraints);
90 if !errors.is_empty() {
91 self.tcx.sess.delay_span_bug(
93 "implied_outlives_bounds failed to solve obligations from instantiation",
101 fn implied_bounds_tys(
103 param_env: ParamEnv<'tcx>,
105 tys: FxIndexSet<Ty<'tcx>>,
106 ) -> Bounds<'a, 'tcx> {
109 let ty = self.resolve_vars_if_possible(ty);
110 self.implied_outlives_bounds(param_env, body_id, ty)