]>
Commit | Line | Data |
---|---|---|
0531ce1d XL |
1 | //! Methods for normalizing when you don't care about regions (and |
2 | //! aren't doing type inference). If either of those things don't | |
3 | //! apply to you, use `infcx.normalize(...)`. | |
4 | //! | |
5 | //! The methods in this file use a `TypeFolder` to recursively process | |
6 | //! contents, invoking the underlying | |
ba9703b0 XL |
7 | //! `normalize_generic_arg_after_erasing_regions` query for each type |
8 | //! or constant found within. (This underlying query is what is cached.) | |
0531ce1d | 9 | |
cdc7bbd5 | 10 | use crate::mir; |
a2a8927a XL |
11 | use crate::traits::query::NoSolution; |
12 | use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder}; | |
dfeec247 XL |
13 | use crate::ty::subst::{Subst, SubstsRef}; |
14 | use crate::ty::{self, Ty, TyCtxt}; | |
0531ce1d | 15 | |
a2a8927a XL |
16 | #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)] |
17 | pub enum NormalizationError<'tcx> { | |
18 | Type(Ty<'tcx>), | |
19 | Const(ty::Const<'tcx>), | |
20 | ConstantKind(mir::ConstantKind<'tcx>), | |
21 | } | |
22 | ||
23 | impl<'tcx> NormalizationError<'tcx> { | |
24 | pub fn get_type_for_failure(&self) -> String { | |
25 | match self { | |
26 | NormalizationError::Type(t) => format!("{}", t), | |
27 | NormalizationError::Const(c) => format!("{}", c), | |
28 | NormalizationError::ConstantKind(ck) => format!("{}", ck), | |
29 | } | |
30 | } | |
31 | } | |
32 | ||
dc9dc135 | 33 | impl<'tcx> TyCtxt<'tcx> { |
0531ce1d XL |
34 | /// Erase the regions in `value` and then fully normalize all the |
35 | /// types found within. The result will also have regions erased. | |
36 | /// | |
5099ac24 FG |
37 | /// This should only be used outside of type inference. For example, |
38 | /// it assumes that normalization will succeed. | |
0531ce1d XL |
39 | pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T |
40 | where | |
41 | T: TypeFoldable<'tcx>, | |
42 | { | |
43 | debug!( | |
44 | "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})", | |
29967ef6 | 45 | std::any::type_name::<T>(), |
0531ce1d XL |
46 | value, |
47 | param_env, | |
48 | ); | |
49 | ||
50 | // Erase first before we do the real query -- this keeps the | |
51 | // cache from being too polluted. | |
fc512014 | 52 | let value = self.erase_regions(value); |
a2a8927a XL |
53 | debug!(?value); |
54 | ||
0531ce1d XL |
55 | if !value.has_projections() { |
56 | value | |
57 | } else { | |
74b04a01 | 58 | value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env }) |
0531ce1d XL |
59 | } |
60 | } | |
61 | ||
a2a8927a XL |
62 | /// Tries to erase the regions in `value` and then fully normalize all the |
63 | /// types found within. The result will also have regions erased. | |
64 | /// | |
65 | /// Contrary to `normalize_erasing_regions` this function does not assume that normalization | |
66 | /// succeeds. | |
67 | pub fn try_normalize_erasing_regions<T>( | |
68 | self, | |
69 | param_env: ty::ParamEnv<'tcx>, | |
70 | value: T, | |
71 | ) -> Result<T, NormalizationError<'tcx>> | |
72 | where | |
73 | T: TypeFoldable<'tcx>, | |
74 | { | |
75 | debug!( | |
76 | "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})", | |
77 | std::any::type_name::<T>(), | |
78 | value, | |
79 | param_env, | |
80 | ); | |
81 | ||
82 | // Erase first before we do the real query -- this keeps the | |
83 | // cache from being too polluted. | |
84 | let value = self.erase_regions(value); | |
85 | debug!(?value); | |
86 | ||
87 | if !value.has_projections() { | |
88 | Ok(value) | |
89 | } else { | |
90 | let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env); | |
91 | value.try_fold_with(&mut folder) | |
92 | } | |
93 | } | |
94 | ||
cdc7bbd5 | 95 | /// If you have a `Binder<'tcx, T>`, you can do this to strip out the |
0531ce1d XL |
96 | /// late-bound regions and then normalize the result, yielding up |
97 | /// a `T` (with regions erased). This is appropriate when the | |
98 | /// binder is being instantiated at the call site. | |
99 | /// | |
9fa01778 | 100 | /// N.B., currently, higher-ranked type bounds inhibit |
0531ce1d | 101 | /// normalization. Therefore, each time we erase them in |
94b46f34 | 102 | /// codegen, we need to normalize the contents. |
0531ce1d XL |
103 | pub fn normalize_erasing_late_bound_regions<T>( |
104 | self, | |
105 | param_env: ty::ParamEnv<'tcx>, | |
cdc7bbd5 | 106 | value: ty::Binder<'tcx, T>, |
0531ce1d XL |
107 | ) -> T |
108 | where | |
109 | T: TypeFoldable<'tcx>, | |
110 | { | |
0531ce1d XL |
111 | let value = self.erase_late_bound_regions(value); |
112 | self.normalize_erasing_regions(param_env, value) | |
113 | } | |
dfeec247 XL |
114 | |
115 | /// Monomorphizes a type from the AST by first applying the | |
116 | /// in-scope substitutions and then normalizing any associated | |
117 | /// types. | |
a2a8927a XL |
118 | /// Panics if normalization fails. In case normalization might fail |
119 | /// use `try_subst_and_normalize_erasing_regions` instead. | |
dfeec247 XL |
120 | pub fn subst_and_normalize_erasing_regions<T>( |
121 | self, | |
122 | param_substs: SubstsRef<'tcx>, | |
123 | param_env: ty::ParamEnv<'tcx>, | |
fc512014 | 124 | value: T, |
dfeec247 XL |
125 | ) -> T |
126 | where | |
127 | T: TypeFoldable<'tcx>, | |
128 | { | |
129 | debug!( | |
130 | "subst_and_normalize_erasing_regions(\ | |
131 | param_substs={:?}, \ | |
132 | value={:?}, \ | |
133 | param_env={:?})", | |
134 | param_substs, value, param_env, | |
135 | ); | |
136 | let substituted = value.subst(self, param_substs); | |
137 | self.normalize_erasing_regions(param_env, substituted) | |
138 | } | |
a2a8927a XL |
139 | |
140 | /// Monomorphizes a type from the AST by first applying the | |
141 | /// in-scope substitutions and then trying to normalize any associated | |
142 | /// types. Contrary to `subst_and_normalize_erasing_regions` this does | |
143 | /// not assume that normalization succeeds. | |
144 | pub fn try_subst_and_normalize_erasing_regions<T>( | |
145 | self, | |
146 | param_substs: SubstsRef<'tcx>, | |
147 | param_env: ty::ParamEnv<'tcx>, | |
148 | value: T, | |
149 | ) -> Result<T, NormalizationError<'tcx>> | |
150 | where | |
151 | T: TypeFoldable<'tcx>, | |
152 | { | |
153 | debug!( | |
154 | "subst_and_normalize_erasing_regions(\ | |
155 | param_substs={:?}, \ | |
156 | value={:?}, \ | |
157 | param_env={:?})", | |
158 | param_substs, value, param_env, | |
159 | ); | |
160 | let substituted = value.subst(self, param_substs); | |
161 | self.try_normalize_erasing_regions(param_env, substituted) | |
162 | } | |
0531ce1d XL |
163 | } |
164 | ||
dc9dc135 XL |
165 | struct NormalizeAfterErasingRegionsFolder<'tcx> { |
166 | tcx: TyCtxt<'tcx>, | |
0531ce1d XL |
167 | param_env: ty::ParamEnv<'tcx>, |
168 | } | |
169 | ||
136023e0 | 170 | impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { |
a2a8927a | 171 | #[instrument(skip(self), level = "debug")] |
136023e0 XL |
172 | fn normalize_generic_arg_after_erasing_regions( |
173 | &self, | |
174 | arg: ty::GenericArg<'tcx>, | |
175 | ) -> ty::GenericArg<'tcx> { | |
176 | let arg = self.param_env.and(arg); | |
a2a8927a XL |
177 | debug!(?arg); |
178 | ||
179 | self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!( | |
180 | "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", | |
181 | arg.value | |
182 | )) | |
136023e0 XL |
183 | } |
184 | } | |
185 | ||
a2a8927a | 186 | impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> { |
dc9dc135 | 187 | fn tcx(&self) -> TyCtxt<'tcx> { |
0531ce1d XL |
188 | self.tcx |
189 | } | |
190 | ||
191 | fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { | |
136023e0 | 192 | self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty() |
ba9703b0 XL |
193 | } |
194 | ||
5099ac24 | 195 | fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { |
136023e0 | 196 | self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const() |
0531ce1d | 197 | } |
cdc7bbd5 XL |
198 | |
199 | #[inline] | |
200 | fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { | |
136023e0 | 201 | // FIXME: This *probably* needs canonicalization too! |
cdc7bbd5 | 202 | let arg = self.param_env.and(c); |
a2a8927a XL |
203 | self.tcx |
204 | .try_normalize_mir_const_after_erasing_regions(arg) | |
205 | .unwrap_or_else(|_| bug!("failed to normalize {:?}", c)) | |
206 | } | |
207 | } | |
208 | ||
209 | struct TryNormalizeAfterErasingRegionsFolder<'tcx> { | |
210 | tcx: TyCtxt<'tcx>, | |
211 | param_env: ty::ParamEnv<'tcx>, | |
212 | } | |
213 | ||
214 | impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> { | |
215 | fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { | |
216 | TryNormalizeAfterErasingRegionsFolder { tcx, param_env } | |
217 | } | |
218 | ||
219 | #[instrument(skip(self), level = "debug")] | |
220 | fn try_normalize_generic_arg_after_erasing_regions( | |
221 | &self, | |
222 | arg: ty::GenericArg<'tcx>, | |
223 | ) -> Result<ty::GenericArg<'tcx>, NoSolution> { | |
224 | let arg = self.param_env.and(arg); | |
225 | debug!(?arg); | |
226 | ||
227 | self.tcx.try_normalize_generic_arg_after_erasing_regions(arg) | |
228 | } | |
229 | } | |
230 | ||
231 | impl<'tcx> TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> { | |
232 | type Error = NormalizationError<'tcx>; | |
233 | ||
234 | fn tcx(&self) -> TyCtxt<'tcx> { | |
235 | self.tcx | |
236 | } | |
237 | } | |
238 | ||
239 | impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> { | |
240 | fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { | |
241 | match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) { | |
242 | Ok(t) => Ok(t.expect_ty()), | |
243 | Err(_) => Err(NormalizationError::Type(ty)), | |
244 | } | |
245 | } | |
246 | ||
5099ac24 | 247 | fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { |
a2a8927a XL |
248 | match self.try_normalize_generic_arg_after_erasing_regions(c.into()) { |
249 | Ok(t) => Ok(t.expect_const()), | |
5099ac24 | 250 | Err(_) => Err(NormalizationError::Const(c)), |
a2a8927a XL |
251 | } |
252 | } | |
253 | ||
254 | fn try_fold_mir_const( | |
255 | &mut self, | |
256 | c: mir::ConstantKind<'tcx>, | |
257 | ) -> Result<mir::ConstantKind<'tcx>, Self::Error> { | |
258 | // FIXME: This *probably* needs canonicalization too! | |
259 | let arg = self.param_env.and(c); | |
260 | match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) { | |
261 | Ok(c) => Ok(c), | |
262 | Err(_) => Err(NormalizationError::ConstantKind(c)), | |
263 | } | |
cdc7bbd5 | 264 | } |
0531ce1d | 265 | } |