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;
8 use rustc_middle::ty::{self, ParamEnv, Ty};
10 pub use rustc_middle::traits::query::OutlivesBound;
12 type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
13 pub trait InferCtxtExt<'a, 'tcx> {
14 fn implied_outlives_bounds(
16 param_env: ty::ParamEnv<'tcx>,
19 ) -> Vec<OutlivesBound<'tcx>>;
21 fn implied_bounds_tys(
23 param_env: ty::ParamEnv<'tcx>,
25 tys: FxIndexSet<Ty<'tcx>>,
26 ) -> Bounds<'a, 'tcx>;
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:
37 /// fn foo<'a,T>(x: &'a T) {}
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`.
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)]
50 fn implied_outlives_bounds(
52 param_env: ty::ParamEnv<'tcx>,
55 ) -> Vec<OutlivesBound<'tcx>> {
56 let span = self.tcx.hir().span(body_id);
57 let result = param_env
58 .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
60 let result = match result {
63 self.tcx.sess.delay_span_bug(
65 "implied_outlives_bounds failed to solve all obligations",
71 let TypeOpOutput { output, constraints, .. } = result;
73 if let Some(constraints) = constraints {
75 // Instantiation may have produced new inference variables and constraints on those
76 // variables. Process these constraints.
77 let cause = ObligationCause::misc(span, body_id);
78 let errors = super::fully_solve_obligations(
80 constraints.outlives.iter().map(|constraint| {
81 self.query_outlives_constraint_to_obligation(
88 if !constraints.member_constraints.is_empty() {
89 span_bug!(span, "{:#?}", constraints.member_constraints);
91 if !errors.is_empty() {
92 self.tcx.sess.delay_span_bug(
94 "implied_outlives_bounds failed to solve obligations from instantiation",
102 fn implied_bounds_tys(
104 param_env: ParamEnv<'tcx>,
106 tys: FxIndexSet<Ty<'tcx>>,
107 ) -> Bounds<'a, 'tcx> {
110 let ty = self.resolve_vars_if_possible(ty);
111 self.implied_outlives_bounds(param_env, body_id, ty)