]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
Rollup merge of #98430 - camsteffen:flatten-refactor, r=joshtriplett
[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     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={:?})",
45             std::any::type_name::<T>(),
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.
52         let value = self.erase_regions(value);
53         debug!(?value);
54
55         if !value.has_projections() {
56             value
57         } else {
58             value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
59         }
60     }
61
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
95     /// If you have a `Binder<'tcx, T>`, you can do this to strip out the
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     ///
100     /// N.B., currently, higher-ranked type bounds inhibit
101     /// normalization. Therefore, each time we erase them in
102     /// codegen, we need to normalize the contents.
103     pub fn normalize_erasing_late_bound_regions<T>(
104         self,
105         param_env: ty::ParamEnv<'tcx>,
106         value: ty::Binder<'tcx, T>,
107     ) -> T
108     where
109         T: TypeFoldable<'tcx>,
110     {
111         let value = self.erase_late_bound_regions(value);
112         self.normalize_erasing_regions(param_env, value)
113     }
114
115     /// Monomorphizes a type from the AST by first applying the
116     /// in-scope substitutions and then normalizing any associated
117     /// types.
118     /// Panics if normalization fails. In case normalization might fail
119     /// use `try_subst_and_normalize_erasing_regions` instead.
120     pub fn subst_and_normalize_erasing_regions<T>(
121         self,
122         param_substs: SubstsRef<'tcx>,
123         param_env: ty::ParamEnv<'tcx>,
124         value: T,
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 = EarlyBinder(value).subst(self, param_substs);
137         self.normalize_erasing_regions(param_env, substituted)
138     }
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 = EarlyBinder(value).subst(self, param_substs);
161         self.try_normalize_erasing_regions(param_env, substituted)
162     }
163 }
164
165 struct NormalizeAfterErasingRegionsFolder<'tcx> {
166     tcx: TyCtxt<'tcx>,
167     param_env: ty::ParamEnv<'tcx>,
168 }
169
170 impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
171     #[instrument(skip(self), level = "debug")]
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);
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             ))
183     }
184 }
185
186 impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
187     fn tcx(&self) -> TyCtxt<'tcx> {
188         self.tcx
189     }
190
191     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
192         self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
193     }
194
195     fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
196         self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
197     }
198
199     #[inline]
200     fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
201         // FIXME: This *probably* needs canonicalization too!
202         let arg = self.param_env.and(c);
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> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
232     type Error = NormalizationError<'tcx>;
233
234     fn tcx(&self) -> TyCtxt<'tcx> {
235         self.tcx
236     }
237
238     fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
239         match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
240             Ok(t) => Ok(t.expect_ty()),
241             Err(_) => Err(NormalizationError::Type(ty)),
242         }
243     }
244
245     fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
246         match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
247             Ok(t) => Ok(t.expect_const()),
248             Err(_) => Err(NormalizationError::Const(c)),
249         }
250     }
251
252     fn try_fold_mir_const(
253         &mut self,
254         c: mir::ConstantKind<'tcx>,
255     ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
256         // FIXME: This *probably* needs canonicalization too!
257         let arg = self.param_env.and(c);
258         match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
259             Ok(c) => Ok(c),
260             Err(_) => Err(NormalizationError::ConstantKind(c)),
261         }
262     }
263 }