]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/outlives/outlives_bounds.rs
Rollup merge of #99573 - tbodt:stabilize-backtrace, r=yaahc
[rust.git] / compiler / rustc_typeck / src / outlives / outlives_bounds.rs
1 use rustc_hir as hir;
2 use rustc_middle::ty::{self, Ty};
3 use rustc_trait_selection::infer::InferCtxt;
4 use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
5 use rustc_trait_selection::traits::query::NoSolution;
6 use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt};
7
8 pub use rustc_middle::traits::query::OutlivesBound;
9
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>,
16     ) -> Vec<OutlivesBound<'tcx>>;
17 }
18
19 impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
20     /// Implied bounds are region relationships that we deduce
21     /// automatically. The idea is that (e.g.) a caller must check that a
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:
26     /// ```
27     /// fn foo<'a,T>(x: &'a T) {}
28     /// ```
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.
39     #[instrument(level = "debug", skip(self, param_env, body_id))]
40     fn implied_outlives_bounds(
41         &self,
42         param_env: ty::ParamEnv<'tcx>,
43         body_id: hir::HirId,
44         ty: Ty<'tcx>,
45     ) -> Vec<OutlivesBound<'tcx>> {
46         let span = self.tcx.hir().span(body_id);
47         let result = param_env
48             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
49             .fully_perform(self);
50         let result = match result {
51             Ok(r) => r,
52             Err(NoSolution) => {
53                 self.tcx.sess.delay_span_bug(
54                     span,
55                     "implied_outlives_bounds failed to solve all obligations",
56                 );
57                 return vec![];
58             }
59         };
60
61         let TypeOpOutput { output, constraints, .. } = result;
62
63         if let Some(constraints) = constraints {
64             // Instantiation may have produced new inference variables and constraints on those
65             // variables. Process these constraints.
66             let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
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         };
87
88         output
89     }
90 }