]>
Commit | Line | Data |
---|---|---|
ba9703b0 XL |
1 | use crate::traits::query::outlives_bounds::InferCtxtExt as _; |
2 | use crate::traits::{self, TraitEngine, TraitEngineExt}; | |
3 | ||
4 | use rustc_hir as hir; | |
3dfed10e | 5 | use rustc_hir::lang_items::LangItem; |
ba9703b0 XL |
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>, | |
fc512014 | 31 | value: T, |
ba9703b0 XL |
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 { | |
fc512014 | 44 | let ty = self.resolve_vars_if_possible(ty); |
ba9703b0 XL |
45 | |
46 | if !(param_env, ty).needs_infer() { | |
f035d41b | 47 | return ty.is_copy_modulo_regions(self.tcx.at(span), param_env); |
ba9703b0 XL |
48 | } |
49 | ||
3dfed10e | 50 | let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None); |
ba9703b0 XL |
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>, | |
fc512014 | 66 | value: T, |
ba9703b0 XL |
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>, | |
f035d41b | 93 | Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>; |
ba9703b0 XL |
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>, | |
f035d41b | 121 | Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, |
ba9703b0 XL |
122 | { |
123 | self.enter_with_canonical( | |
124 | DUMMY_SP, | |
125 | canonical_key, | |
126 | |ref infcx, key, canonical_inference_vars| { | |
6a06907d | 127 | let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); |
ba9703b0 XL |
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 | /// | |
5869c6ff | 165 | /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs` |
ba9703b0 XL |
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 { | |
fc512014 | 176 | let ty = infcx.resolve_vars_if_possible(ty); |
ba9703b0 XL |
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 | } |