]>
Commit | Line | Data |
---|---|---|
f2b60f7d FG |
1 | use crate::infer::InferCtxt; |
2 | use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; | |
3 | use crate::traits::query::NoSolution; | |
487cf647 FG |
4 | use crate::traits::ObligationCause; |
5 | use rustc_data_structures::fx::FxIndexSet; | |
f2b60f7d | 6 | use rustc_middle::ty::{self, ParamEnv, Ty}; |
9ffffee4 | 7 | use rustc_span::def_id::LocalDefId; |
8faf50e0 | 8 | |
ba9703b0 | 9 | pub use rustc_middle::traits::query::OutlivesBound; |
8faf50e0 | 10 | |
f2b60f7d FG |
11 | type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a; |
12 | pub trait InferCtxtExt<'a, 'tcx> { | |
ba9703b0 XL |
13 | fn implied_outlives_bounds( |
14 | &self, | |
15 | param_env: ty::ParamEnv<'tcx>, | |
9ffffee4 | 16 | body_id: LocalDefId, |
ba9703b0 | 17 | ty: Ty<'tcx>, |
ba9703b0 | 18 | ) -> Vec<OutlivesBound<'tcx>>; |
f2b60f7d FG |
19 | |
20 | fn implied_bounds_tys( | |
21 | &'a self, | |
22 | param_env: ty::ParamEnv<'tcx>, | |
9ffffee4 | 23 | body_id: LocalDefId, |
487cf647 | 24 | tys: FxIndexSet<Ty<'tcx>>, |
f2b60f7d | 25 | ) -> Bounds<'a, 'tcx>; |
ba9703b0 XL |
26 | } |
27 | ||
2b03887a | 28 | impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { |
8faf50e0 | 29 | /// Implied bounds are region relationships that we deduce |
9fa01778 | 30 | /// automatically. The idea is that (e.g.) a caller must check that a |
8faf50e0 XL |
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: | |
04454e1e | 35 | /// ``` |
9c376795 | 36 | /// fn foo<T>(x: &T) {} |
04454e1e | 37 | /// ``` |
8faf50e0 XL |
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`. | |
40 | /// | |
41 | /// # Parameters | |
42 | /// | |
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. | |
f2b60f7d | 48 | #[instrument(level = "debug", skip(self, param_env, body_id), ret)] |
ba9703b0 | 49 | fn implied_outlives_bounds( |
8faf50e0 XL |
50 | &self, |
51 | param_env: ty::ParamEnv<'tcx>, | |
9ffffee4 | 52 | body_id: LocalDefId, |
8faf50e0 | 53 | ty: Ty<'tcx>, |
8faf50e0 | 54 | ) -> Vec<OutlivesBound<'tcx>> { |
9ffffee4 | 55 | let span = self.tcx.def_span(body_id); |
923072b8 FG |
56 | let result = param_env |
57 | .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) | |
58 | .fully_perform(self); | |
59 | let result = match result { | |
8faf50e0 XL |
60 | Ok(r) => r, |
61 | Err(NoSolution) => { | |
62 | self.tcx.sess.delay_span_bug( | |
63 | span, | |
dfeec247 | 64 | "implied_outlives_bounds failed to solve all obligations", |
8faf50e0 XL |
65 | ); |
66 | return vec![]; | |
67 | } | |
68 | }; | |
8faf50e0 | 69 | |
923072b8 | 70 | let TypeOpOutput { output, constraints, .. } = result; |
8faf50e0 | 71 | |
923072b8 | 72 | if let Some(constraints) = constraints { |
f2b60f7d | 73 | debug!(?constraints); |
923072b8 FG |
74 | // Instantiation may have produced new inference variables and constraints on those |
75 | // variables. Process these constraints. | |
923072b8 | 76 | let cause = ObligationCause::misc(span, body_id); |
487cf647 FG |
77 | let errors = super::fully_solve_obligations( |
78 | self, | |
79 | constraints.outlives.iter().map(|constraint| { | |
80 | self.query_outlives_constraint_to_obligation( | |
81 | *constraint, | |
82 | cause.clone(), | |
83 | param_env, | |
84 | ) | |
85 | }), | |
86 | ); | |
923072b8 FG |
87 | if !constraints.member_constraints.is_empty() { |
88 | span_bug!(span, "{:#?}", constraints.member_constraints); | |
89 | } | |
923072b8 FG |
90 | if !errors.is_empty() { |
91 | self.tcx.sess.delay_span_bug( | |
92 | span, | |
93 | "implied_outlives_bounds failed to solve obligations from instantiation", | |
94 | ); | |
95 | } | |
96 | }; | |
8faf50e0 | 97 | |
923072b8 | 98 | output |
8faf50e0 | 99 | } |
f2b60f7d FG |
100 | |
101 | fn implied_bounds_tys( | |
102 | &'a self, | |
103 | param_env: ParamEnv<'tcx>, | |
9ffffee4 | 104 | body_id: LocalDefId, |
487cf647 | 105 | tys: FxIndexSet<Ty<'tcx>>, |
f2b60f7d FG |
106 | ) -> Bounds<'a, 'tcx> { |
107 | tys.into_iter() | |
108 | .map(move |ty| { | |
109 | let ty = self.resolve_vars_if_possible(ty); | |
110 | self.implied_outlives_bounds(param_env, body_id, ty) | |
111 | }) | |
112 | .flatten() | |
113 | } | |
8faf50e0 | 114 | } |