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