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(...)`.
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.)
11 use crate::traits::query::NoSolution;
12 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
13 use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt};
15 #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
16 pub enum NormalizationError<'tcx> {
18 Const(ty::Const<'tcx>),
19 ConstantKind(mir::ConstantKind<'tcx>),
22 impl<'tcx> NormalizationError<'tcx> {
23 pub fn get_type_for_failure(&self) -> String {
25 NormalizationError::Type(t) => format!("{}", t),
26 NormalizationError::Const(c) => format!("{}", c),
27 NormalizationError::ConstantKind(ck) => format!("{}", ck),
32 impl<'tcx> TyCtxt<'tcx> {
33 /// Erase the regions in `value` and then fully normalize all the
34 /// types found within. The result will also have regions erased.
36 /// This should only be used outside of type inference. For example,
37 /// it assumes that normalization will succeed.
38 #[tracing::instrument(level = "debug", skip(self, param_env))]
39 pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
41 T: TypeFoldable<'tcx>,
44 "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
45 std::any::type_name::<T>(),
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);
55 if !value.has_projections() {
58 value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
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.
65 /// Contrary to `normalize_erasing_regions` this function does not assume that normalization
67 pub fn try_normalize_erasing_regions<T>(
69 param_env: ty::ParamEnv<'tcx>,
71 ) -> Result<T, NormalizationError<'tcx>>
73 T: TypeFoldable<'tcx>,
76 "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
77 std::any::type_name::<T>(),
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);
87 if !value.has_projections() {
90 let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
91 value.try_fold_with(&mut folder)
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.
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 #[tracing::instrument(level = "debug", skip(self, param_env))]
104 pub fn normalize_erasing_late_bound_regions<T>(
106 param_env: ty::ParamEnv<'tcx>,
107 value: ty::Binder<'tcx, T>,
110 T: TypeFoldable<'tcx>,
112 let value = self.erase_late_bound_regions(value);
113 self.normalize_erasing_regions(param_env, value)
116 /// If you have a `Binder<'tcx, T>`, you can do this to strip out the
117 /// late-bound regions and then normalize the result, yielding up
118 /// a `T` (with regions erased). This is appropriate when the
119 /// binder is being instantiated at the call site.
121 /// N.B., currently, higher-ranked type bounds inhibit
122 /// normalization. Therefore, each time we erase them in
123 /// codegen, we need to normalize the contents.
124 pub fn try_normalize_erasing_late_bound_regions<T>(
126 param_env: ty::ParamEnv<'tcx>,
127 value: ty::Binder<'tcx, T>,
128 ) -> Result<T, NormalizationError<'tcx>>
130 T: TypeFoldable<'tcx>,
132 let value = self.erase_late_bound_regions(value);
133 self.try_normalize_erasing_regions(param_env, value)
136 /// Monomorphizes a type from the AST by first applying the
137 /// in-scope substitutions and then normalizing any associated
139 /// Panics if normalization fails. In case normalization might fail
140 /// use `try_subst_and_normalize_erasing_regions` instead.
141 pub fn subst_and_normalize_erasing_regions<T>(
143 param_substs: SubstsRef<'tcx>,
144 param_env: ty::ParamEnv<'tcx>,
148 T: TypeFoldable<'tcx>,
151 "subst_and_normalize_erasing_regions(\
155 param_substs, value, param_env,
157 let substituted = EarlyBinder(value).subst(self, param_substs);
158 self.normalize_erasing_regions(param_env, substituted)
161 /// Monomorphizes a type from the AST by first applying the
162 /// in-scope substitutions and then trying to normalize any associated
163 /// types. Contrary to `subst_and_normalize_erasing_regions` this does
164 /// not assume that normalization succeeds.
165 pub fn try_subst_and_normalize_erasing_regions<T>(
167 param_substs: SubstsRef<'tcx>,
168 param_env: ty::ParamEnv<'tcx>,
170 ) -> Result<T, NormalizationError<'tcx>>
172 T: TypeFoldable<'tcx>,
175 "subst_and_normalize_erasing_regions(\
179 param_substs, value, param_env,
181 let substituted = EarlyBinder(value).subst(self, param_substs);
182 self.try_normalize_erasing_regions(param_env, substituted)
186 struct NormalizeAfterErasingRegionsFolder<'tcx> {
188 param_env: ty::ParamEnv<'tcx>,
191 impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
192 fn normalize_generic_arg_after_erasing_regions(
194 arg: ty::GenericArg<'tcx>,
195 ) -> ty::GenericArg<'tcx> {
196 let arg = self.param_env.and(arg);
198 self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
199 "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
205 impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
206 fn tcx(&self) -> TyCtxt<'tcx> {
210 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
211 self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
214 fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
215 self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
219 struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
221 param_env: ty::ParamEnv<'tcx>,
224 impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
225 fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
226 TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
229 #[instrument(skip(self), level = "debug")]
230 fn try_normalize_generic_arg_after_erasing_regions(
232 arg: ty::GenericArg<'tcx>,
233 ) -> Result<ty::GenericArg<'tcx>, NoSolution> {
234 let arg = self.param_env.and(arg);
237 self.tcx.try_normalize_generic_arg_after_erasing_regions(arg)
241 impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
242 type Error = NormalizationError<'tcx>;
244 fn tcx(&self) -> TyCtxt<'tcx> {
248 fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
249 match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
250 Ok(t) => Ok(t.expect_ty()),
251 Err(_) => Err(NormalizationError::Type(ty)),
255 fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
256 match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
257 Ok(t) => Ok(t.expect_const()),
258 Err(_) => Err(NormalizationError::Const(c)),