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