]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
Rollup merge of #107189 - cjgillot:meta-adt, r=compiler-errors
[rust.git] / compiler / rustc_trait_selection / src / traits / outlives_bounds.rs
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;
8
9 pub use rustc_middle::traits::query::OutlivesBound;
10
11 type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
12 pub trait InferCtxtExt<'a, 'tcx> {
13     fn implied_outlives_bounds(
14         &self,
15         param_env: ty::ParamEnv<'tcx>,
16         body_id: LocalDefId,
17         ty: Ty<'tcx>,
18     ) -> Vec<OutlivesBound<'tcx>>;
19
20     fn implied_bounds_tys(
21         &'a self,
22         param_env: ty::ParamEnv<'tcx>,
23         body_id: LocalDefId,
24         tys: FxIndexSet<Ty<'tcx>>,
25     ) -> Bounds<'a, 'tcx>;
26 }
27
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:
35     /// ```
36     /// fn foo<T>(x: &T) {}
37     /// ```
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.
48     #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
49     fn implied_outlives_bounds(
50         &self,
51         param_env: ty::ParamEnv<'tcx>,
52         body_id: LocalDefId,
53         ty: Ty<'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 })
58             .fully_perform(self);
59         let result = match result {
60             Ok(r) => r,
61             Err(NoSolution) => {
62                 self.tcx.sess.delay_span_bug(
63                     span,
64                     "implied_outlives_bounds failed to solve all obligations",
65                 );
66                 return vec![];
67             }
68         };
69
70         let TypeOpOutput { output, constraints, .. } = result;
71
72         if let Some(constraints) = constraints {
73             debug!(?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(
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             );
87             if !constraints.member_constraints.is_empty() {
88                 span_bug!(span, "{:#?}", constraints.member_constraints);
89             }
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         };
97
98         output
99     }
100
101     fn implied_bounds_tys(
102         &'a self,
103         param_env: ParamEnv<'tcx>,
104         body_id: LocalDefId,
105         tys: FxIndexSet<Ty<'tcx>>,
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     }
114 }