]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use rustc_hir as hir; |
ba9703b0 | 2 | use rustc_middle::ty::{self, Ty}; |
c295e0f8 | 3 | use rustc_trait_selection::infer::InferCtxt; |
923072b8 | 4 | use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput}; |
c295e0f8 | 5 | use rustc_trait_selection::traits::query::NoSolution; |
064997fb | 6 | use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt}; |
8faf50e0 | 7 | |
ba9703b0 | 8 | pub use rustc_middle::traits::query::OutlivesBound; |
8faf50e0 | 9 | |
ba9703b0 XL |
10 | pub trait InferCtxtExt<'tcx> { |
11 | fn implied_outlives_bounds( | |
12 | &self, | |
13 | param_env: ty::ParamEnv<'tcx>, | |
14 | body_id: hir::HirId, | |
15 | ty: Ty<'tcx>, | |
ba9703b0 XL |
16 | ) -> Vec<OutlivesBound<'tcx>>; |
17 | } | |
18 | ||
19 | impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { | |
8faf50e0 | 20 | /// Implied bounds are region relationships that we deduce |
9fa01778 | 21 | /// automatically. The idea is that (e.g.) a caller must check that a |
8faf50e0 XL |
22 | /// function's argument types are well-formed immediately before |
23 | /// calling that fn, and hence the *callee* can assume that its | |
24 | /// argument types are well-formed. This may imply certain relationships | |
25 | /// between generic parameters. For example: | |
04454e1e FG |
26 | /// ``` |
27 | /// fn foo<'a,T>(x: &'a T) {} | |
28 | /// ``` | |
8faf50e0 XL |
29 | /// can only be called with a `'a` and `T` such that `&'a T` is WF. |
30 | /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. | |
31 | /// | |
32 | /// # Parameters | |
33 | /// | |
34 | /// - `param_env`, the where-clauses in scope | |
35 | /// - `body_id`, the body-id to use when normalizing assoc types. | |
36 | /// Note that this may cause outlives obligations to be injected | |
37 | /// into the inference context with this body-id. | |
38 | /// - `ty`, the type that we are supposed to assume is WF. | |
064997fb | 39 | #[instrument(level = "debug", skip(self, param_env, body_id))] |
ba9703b0 | 40 | fn implied_outlives_bounds( |
8faf50e0 XL |
41 | &self, |
42 | param_env: ty::ParamEnv<'tcx>, | |
9fa01778 | 43 | body_id: hir::HirId, |
8faf50e0 | 44 | ty: Ty<'tcx>, |
8faf50e0 | 45 | ) -> Vec<OutlivesBound<'tcx>> { |
064997fb | 46 | let span = self.tcx.hir().span(body_id); |
923072b8 FG |
47 | let result = param_env |
48 | .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) | |
49 | .fully_perform(self); | |
50 | let result = match result { | |
8faf50e0 XL |
51 | Ok(r) => r, |
52 | Err(NoSolution) => { | |
53 | self.tcx.sess.delay_span_bug( | |
54 | span, | |
dfeec247 | 55 | "implied_outlives_bounds failed to solve all obligations", |
8faf50e0 XL |
56 | ); |
57 | return vec![]; | |
58 | } | |
59 | }; | |
8faf50e0 | 60 | |
923072b8 | 61 | let TypeOpOutput { output, constraints, .. } = result; |
8faf50e0 | 62 | |
923072b8 FG |
63 | if let Some(constraints) = constraints { |
64 | // Instantiation may have produced new inference variables and constraints on those | |
65 | // variables. Process these constraints. | |
064997fb | 66 | let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx); |
923072b8 FG |
67 | let cause = ObligationCause::misc(span, body_id); |
68 | for &constraint in &constraints.outlives { | |
69 | let obligation = self.query_outlives_constraint_to_obligation( | |
70 | constraint, | |
71 | cause.clone(), | |
72 | param_env, | |
73 | ); | |
74 | fulfill_cx.register_predicate_obligation(self, obligation); | |
75 | } | |
76 | if !constraints.member_constraints.is_empty() { | |
77 | span_bug!(span, "{:#?}", constraints.member_constraints); | |
78 | } | |
79 | let errors = fulfill_cx.select_all_or_error(self); | |
80 | if !errors.is_empty() { | |
81 | self.tcx.sess.delay_span_bug( | |
82 | span, | |
83 | "implied_outlives_bounds failed to solve obligations from instantiation", | |
84 | ); | |
85 | } | |
86 | }; | |
8faf50e0 | 87 | |
923072b8 | 88 | output |
8faf50e0 XL |
89 | } |
90 | } |