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