1use rustc_macros::{HashStable, TyDecodable, TyEncodable};
11use tracing::{debug, instrument};
12
13use crate::traits::query::NoSolution;
14use crate::ty::{
15 self, EarlyBinder, FallibleTypeFolder, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder,
16 TypeVisitableExt,
17};
18
19#[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
20pub enum NormalizationError<'tcx> {
21 Type(Ty<'tcx>),
22 Const(ty::Const<'tcx>),
23}
24
25impl<'tcx> NormalizationError<'tcx> {
26 pub fn get_type_for_failure(&self) -> String {
27 match self {
28 NormalizationError::Type(t) => format!("{t}"),
29 NormalizationError::Const(c) => format!("{c}"),
30 }
31 }
32}
33
34impl<'tcx> TyCtxt<'tcx> {
35 #[tracing::instrument(level = "debug", skip(self, typing_env), ret)]
41 pub fn normalize_erasing_regions<T>(self, typing_env: ty::TypingEnv<'tcx>, value: T) -> T
42 where
43 T: TypeFoldable<TyCtxt<'tcx>>,
44 {
45 debug!(
46 "normalize_erasing_regions::<{}>(value={:?}, typing_env={:?})",
47 std::any::type_name::<T>(),
48 value,
49 typing_env,
50 );
51
52 let value = self.erase_regions(value);
55 debug!(?value);
56
57 if !value.has_aliases() {
58 value
59 } else {
60 value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, typing_env })
61 }
62 }
63
64 pub fn try_normalize_erasing_regions<T>(
70 self,
71 typing_env: ty::TypingEnv<'tcx>,
72 value: T,
73 ) -> Result<T, NormalizationError<'tcx>>
74 where
75 T: TypeFoldable<TyCtxt<'tcx>>,
76 {
77 debug!(
78 "try_normalize_erasing_regions::<{}>(value={:?}, typing_env={:?})",
79 std::any::type_name::<T>(),
80 value,
81 typing_env,
82 );
83
84 let value = self.erase_regions(value);
87 debug!(?value);
88
89 if !value.has_aliases() {
90 Ok(value)
91 } else {
92 let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, typing_env);
93 value.try_fold_with(&mut folder)
94 }
95 }
96
97 #[tracing::instrument(level = "debug", skip(self, typing_env))]
109 pub fn normalize_erasing_late_bound_regions<T>(
110 self,
111 typing_env: ty::TypingEnv<'tcx>,
112 value: ty::Binder<'tcx, T>,
113 ) -> T
114 where
115 T: TypeFoldable<TyCtxt<'tcx>>,
116 {
117 let value = self.instantiate_bound_regions_with_erased(value);
118 self.normalize_erasing_regions(typing_env, value)
119 }
120
121 #[instrument(level = "debug", skip(self))]
127 pub fn instantiate_and_normalize_erasing_regions<T>(
128 self,
129 param_args: GenericArgsRef<'tcx>,
130 typing_env: ty::TypingEnv<'tcx>,
131 value: EarlyBinder<'tcx, T>,
132 ) -> T
133 where
134 T: TypeFoldable<TyCtxt<'tcx>>,
135 {
136 let instantiated = value.instantiate(self, param_args);
137 self.normalize_erasing_regions(typing_env, instantiated)
138 }
139
140 #[instrument(level = "debug", skip(self))]
145 pub fn try_instantiate_and_normalize_erasing_regions<T>(
146 self,
147 param_args: GenericArgsRef<'tcx>,
148 typing_env: ty::TypingEnv<'tcx>,
149 value: EarlyBinder<'tcx, T>,
150 ) -> Result<T, NormalizationError<'tcx>>
151 where
152 T: TypeFoldable<TyCtxt<'tcx>>,
153 {
154 let instantiated = value.instantiate(self, param_args);
155 self.try_normalize_erasing_regions(typing_env, instantiated)
156 }
157}
158
159struct NormalizeAfterErasingRegionsFolder<'tcx> {
160 tcx: TyCtxt<'tcx>,
161 typing_env: ty::TypingEnv<'tcx>,
162}
163
164impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
165 fn normalize_generic_arg_after_erasing_regions(
166 &self,
167 arg: ty::GenericArg<'tcx>,
168 ) -> ty::GenericArg<'tcx> {
169 let arg = self.typing_env.as_query_input(arg);
170 self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| {
171 bug!(
172 "Failed to normalize {:?} in typing_env={:?}, \
173 maybe try to call `try_normalize_erasing_regions` instead",
174 arg.value,
175 self.typing_env,
176 )
177 })
178 }
179}
180
181impl<'tcx> TypeFolder<TyCtxt<'tcx>> for NormalizeAfterErasingRegionsFolder<'tcx> {
182 fn cx(&self) -> TyCtxt<'tcx> {
183 self.tcx
184 }
185
186 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
187 self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
188 }
189
190 fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
191 self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
192 }
193}
194
195struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
196 tcx: TyCtxt<'tcx>,
197 typing_env: ty::TypingEnv<'tcx>,
198}
199
200impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
201 fn new(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Self {
202 TryNormalizeAfterErasingRegionsFolder { tcx, typing_env }
203 }
204
205 #[instrument(skip(self), level = "debug")]
206 fn try_normalize_generic_arg_after_erasing_regions(
207 &self,
208 arg: ty::GenericArg<'tcx>,
209 ) -> Result<ty::GenericArg<'tcx>, NoSolution> {
210 let input = self.typing_env.as_query_input(arg);
211 self.tcx.try_normalize_generic_arg_after_erasing_regions(input)
212 }
213}
214
215impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
216 type Error = NormalizationError<'tcx>;
217
218 fn cx(&self) -> TyCtxt<'tcx> {
219 self.tcx
220 }
221
222 fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
223 match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
224 Ok(t) => Ok(t.expect_ty()),
225 Err(_) => Err(NormalizationError::Type(ty)),
226 }
227 }
228
229 fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
230 match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
231 Ok(t) => Ok(t.expect_const()),
232 Err(_) => Err(NormalizationError::Const(c)),
233 }
234 }
235}