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