rustc_middle/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
10use 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    /// Erase the regions in `value` and then fully normalize all the
34    /// types found within. The result will also have regions erased.
35    ///
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, 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        // 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_aliases() {
56            value
57        } else {
58            value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, typing_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        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        // 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_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    /// 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    // FIXME(@lcnr): This method should not be necessary, we now normalize
104    // inside of binders. We should be able to only use
105    // `tcx.instantiate_bound_regions_with_erased`.
106    #[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    /// Monomorphizes a type from the AST by first applying the
120    /// in-scope instantiations and then normalizing any associated
121    /// types.
122    /// Panics if normalization fails. In case normalization might fail
123    /// use `try_instantiate_and_normalize_erasing_regions` instead.
124    #[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    /// Monomorphizes a type from the AST by first applying the
139    /// in-scope instantiations and then trying to normalize any associated
140    /// types. Contrary to `instantiate_and_normalize_erasing_regions` this does
141    /// not assume that normalization succeeds.
142    #[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}