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