]> git.lizzy.rs Git - rust.git/blob - src/librustc_trait_selection/infer.rs
f244785b49d2fdf3dd5e4050543217b5549171e5
[rust.git] / src / librustc_trait_selection / infer.rs
1 use crate::traits::query::outlives_bounds::InferCtxtExt as _;
2 use crate::traits::{self, TraitEngine, TraitEngineExt};
3
4 use rustc_hir as hir;
5 use rustc_hir::lang_items;
6 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
7 use rustc_infer::traits::ObligationCause;
8 use rustc_middle::arena::ArenaAllocatable;
9 use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse};
10 use rustc_middle::traits::query::Fallible;
11 use rustc_middle::ty::{self, Ty, TypeFoldable};
12 use rustc_span::{Span, DUMMY_SP};
13
14 use std::fmt::Debug;
15
16 pub use rustc_infer::infer::*;
17
18 pub trait InferCtxtExt<'tcx> {
19     fn type_is_copy_modulo_regions(
20         &self,
21         param_env: ty::ParamEnv<'tcx>,
22         ty: Ty<'tcx>,
23         span: Span,
24     ) -> bool;
25
26     fn partially_normalize_associated_types_in<T>(
27         &self,
28         span: Span,
29         body_id: hir::HirId,
30         param_env: ty::ParamEnv<'tcx>,
31         value: &T,
32     ) -> InferOk<'tcx, T>
33     where
34         T: TypeFoldable<'tcx>;
35 }
36
37 impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
38     fn type_is_copy_modulo_regions(
39         &self,
40         param_env: ty::ParamEnv<'tcx>,
41         ty: Ty<'tcx>,
42         span: Span,
43     ) -> bool {
44         let ty = self.resolve_vars_if_possible(&ty);
45
46         if !(param_env, ty).needs_infer() {
47             return ty.is_copy_modulo_regions(self.tcx, param_env, span);
48         }
49
50         let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None);
51
52         // This can get called from typeck (by euv), and `moves_by_default`
53         // rightly refuses to work with inference variables, but
54         // moves_by_default has a cache, which we want to use in other
55         // cases.
56         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
57     }
58
59     /// Normalizes associated types in `value`, potentially returning
60     /// new obligations that must further be processed.
61     fn partially_normalize_associated_types_in<T>(
62         &self,
63         span: Span,
64         body_id: hir::HirId,
65         param_env: ty::ParamEnv<'tcx>,
66         value: &T,
67     ) -> InferOk<'tcx, T>
68     where
69         T: TypeFoldable<'tcx>,
70     {
71         debug!("partially_normalize_associated_types_in(value={:?})", value);
72         let mut selcx = traits::SelectionContext::new(self);
73         let cause = ObligationCause::misc(span, body_id);
74         let traits::Normalized { value, obligations } =
75             traits::normalize(&mut selcx, param_env, cause, value);
76         debug!(
77             "partially_normalize_associated_types_in: result={:?} predicates={:?}",
78             value, obligations
79         );
80         InferOk { value, obligations }
81     }
82 }
83
84 pub trait InferCtxtBuilderExt<'tcx> {
85     fn enter_canonical_trait_query<K, R>(
86         &mut self,
87         canonical_key: &Canonical<'tcx, K>,
88         operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
89     ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
90     where
91         K: TypeFoldable<'tcx>,
92         R: Debug + TypeFoldable<'tcx>,
93         Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>;
94 }
95
96 impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
97     /// The "main method" for a canonicalized trait query. Given the
98     /// canonical key `canonical_key`, this method will create a new
99     /// inference context, instantiate the key, and run your operation
100     /// `op`. The operation should yield up a result (of type `R`) as
101     /// well as a set of trait obligations that must be fully
102     /// satisfied. These obligations will be processed and the
103     /// canonical result created.
104     ///
105     /// Returns `NoSolution` in the event of any error.
106     ///
107     /// (It might be mildly nicer to implement this on `TyCtxt`, and
108     /// not `InferCtxtBuilder`, but that is a bit tricky right now.
109     /// In part because we would need a `for<'tcx>` sort of
110     /// bound for the closure and in part because it is convenient to
111     /// have `'tcx` be free on this function so that we can talk about
112     /// `K: TypeFoldable<'tcx>`.)
113     fn enter_canonical_trait_query<K, R>(
114         &mut self,
115         canonical_key: &Canonical<'tcx, K>,
116         operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
117     ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
118     where
119         K: TypeFoldable<'tcx>,
120         R: Debug + TypeFoldable<'tcx>,
121         Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
122     {
123         self.enter_with_canonical(
124             DUMMY_SP,
125             canonical_key,
126             |ref infcx, key, canonical_inference_vars| {
127                 let mut fulfill_cx = TraitEngine::new(infcx.tcx);
128                 let value = operation(infcx, &mut *fulfill_cx, key)?;
129                 infcx.make_canonicalized_query_response(
130                     canonical_inference_vars,
131                     value,
132                     &mut *fulfill_cx,
133                 )
134             },
135         )
136     }
137 }
138
139 pub trait OutlivesEnvironmentExt<'tcx> {
140     fn add_implied_bounds(
141         &mut self,
142         infcx: &InferCtxt<'a, 'tcx>,
143         fn_sig_tys: &[Ty<'tcx>],
144         body_id: hir::HirId,
145         span: Span,
146     );
147 }
148
149 impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
150     /// This method adds "implied bounds" into the outlives environment.
151     /// Implied bounds are outlives relationships that we can deduce
152     /// on the basis that certain types must be well-formed -- these are
153     /// either the types that appear in the function signature or else
154     /// the input types to an impl. For example, if you have a function
155     /// like
156     ///
157     /// ```
158     /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { }
159     /// ```
160     ///
161     /// we can assume in the caller's body that `'b: 'a` and that `T:
162     /// 'b` (and hence, transitively, that `T: 'a`). This method would
163     /// add those assumptions into the outlives-environment.
164     ///
165     /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
166     fn add_implied_bounds(
167         &mut self,
168         infcx: &InferCtxt<'a, 'tcx>,
169         fn_sig_tys: &[Ty<'tcx>],
170         body_id: hir::HirId,
171         span: Span,
172     ) {
173         debug!("add_implied_bounds()");
174
175         for &ty in fn_sig_tys {
176             let ty = infcx.resolve_vars_if_possible(&ty);
177             debug!("add_implied_bounds: ty = {}", ty);
178             let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
179             self.add_outlives_bounds(Some(infcx), implied_bounds)
180         }
181     }
182 }