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
::subst
::{Subst, SubstsRef}
;
14 use crate::ty
::{self, Ty, TyCtxt}
;
16 #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
17 pub enum NormalizationError
<'tcx
> {
19 Const(ty
::Const
<'tcx
>),
20 ConstantKind(mir
::ConstantKind
<'tcx
>),
23 impl<'tcx
> NormalizationError
<'tcx
> {
24 pub fn get_type_for_failure(&self) -> String
{
26 NormalizationError
::Type(t
) => format
!("{}", t
),
27 NormalizationError
::Const(c
) => format
!("{}", c
),
28 NormalizationError
::ConstantKind(ck
) => format
!("{}", ck
),
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.
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
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 pub fn normalize_erasing_late_bound_regions
<T
>(
105 param_env
: ty
::ParamEnv
<'tcx
>,
106 value
: ty
::Binder
<'tcx
, T
>,
109 T
: TypeFoldable
<'tcx
>,
111 let value
= self.erase_late_bound_regions(value
);
112 self.normalize_erasing_regions(param_env
, value
)
115 /// Monomorphizes a type from the AST by first applying the
116 /// in-scope substitutions and then normalizing any associated
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
>(
122 param_substs
: SubstsRef
<'tcx
>,
123 param_env
: ty
::ParamEnv
<'tcx
>,
127 T
: TypeFoldable
<'tcx
>,
130 "subst_and_normalize_erasing_regions(\
134 param_substs
, value
, param_env
,
136 let substituted
= value
.subst(self, param_substs
);
137 self.normalize_erasing_regions(param_env
, substituted
)
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
>(
146 param_substs
: SubstsRef
<'tcx
>,
147 param_env
: ty
::ParamEnv
<'tcx
>,
149 ) -> Result
<T
, NormalizationError
<'tcx
>>
151 T
: TypeFoldable
<'tcx
>,
154 "subst_and_normalize_erasing_regions(\
158 param_substs
, value
, param_env
,
160 let substituted
= value
.subst(self, param_substs
);
161 self.try_normalize_erasing_regions(param_env
, substituted
)
165 struct NormalizeAfterErasingRegionsFolder
<'tcx
> {
167 param_env
: ty
::ParamEnv
<'tcx
>,
170 impl<'tcx
> NormalizeAfterErasingRegionsFolder
<'tcx
> {
171 #[instrument(skip(self), level = "debug")]
172 fn normalize_generic_arg_after_erasing_regions(
174 arg
: ty
::GenericArg
<'tcx
>,
175 ) -> ty
::GenericArg
<'tcx
> {
176 let arg
= self.param_env
.and(arg
);
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",
186 impl<'tcx
> TypeFolder
<'tcx
> for NormalizeAfterErasingRegionsFolder
<'tcx
> {
187 fn tcx(&self) -> TyCtxt
<'tcx
> {
191 fn fold_ty(&mut self, ty
: Ty
<'tcx
>) -> Ty
<'tcx
> {
192 self.normalize_generic_arg_after_erasing_regions(ty
.into()).expect_ty()
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()
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
);
204 .try_normalize_mir_const_after_erasing_regions(arg
)
205 .unwrap_or_else(|_
| bug
!("failed to normalize {:?}", c
))
209 struct TryNormalizeAfterErasingRegionsFolder
<'tcx
> {
211 param_env
: ty
::ParamEnv
<'tcx
>,
214 impl<'tcx
> TryNormalizeAfterErasingRegionsFolder
<'tcx
> {
215 fn new(tcx
: TyCtxt
<'tcx
>, param_env
: ty
::ParamEnv
<'tcx
>) -> Self {
216 TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
219 #[instrument(skip(self), level = "debug")]
220 fn try_normalize_generic_arg_after_erasing_regions(
222 arg
: ty
::GenericArg
<'tcx
>,
223 ) -> Result
<ty
::GenericArg
<'tcx
>, NoSolution
> {
224 let arg
= self.param_env
.and(arg
);
227 self.tcx
.try_normalize_generic_arg_after_erasing_regions(arg
)
231 impl<'tcx
> TypeFolder
<'tcx
> for TryNormalizeAfterErasingRegionsFolder
<'tcx
> {
232 type Error
= NormalizationError
<'tcx
>;
234 fn tcx(&self) -> TyCtxt
<'tcx
> {
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
)),
247 fn try_fold_const(&mut self, c
: ty
::Const
<'tcx
>) -> Result
<ty
::Const
<'tcx
>, Self::Error
> {
248 match self.try_normalize_generic_arg_after_erasing_regions(c
.into()) {
249 Ok(t
) => Ok(t
.expect_const()),
250 Err(_
) => Err(NormalizationError
::Const(c
)),
254 fn try_fold_mir_const(
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
) {
262 Err(_
) => Err(NormalizationError
::ConstantKind(c
)),