rustc_middle/ty/
erase_regions.rs

1use tracing::debug;
2
3use crate::query::Providers;
4use crate::ty::{
5    self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
6};
7
8pub(super) fn provide(providers: &mut Providers) {
9    *providers = Providers { erase_regions_ty, ..*providers };
10}
11
12fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
13    // N.B., use `super_fold_with` here. If we used `fold_with`, it
14    // could invoke the `erase_regions_ty` query recursively.
15    ty.super_fold_with(&mut RegionEraserVisitor { tcx })
16}
17
18impl<'tcx> TyCtxt<'tcx> {
19    /// Returns an equivalent value with all free regions removed (note
20    /// that late-bound regions remain, because they are important for
21    /// subtyping, but they are anonymized and normalized as well)..
22    pub fn erase_regions<T>(self, value: T) -> T
23    where
24        T: TypeFoldable<TyCtxt<'tcx>>,
25    {
26        // If there's nothing to erase or anonymize, avoid performing the query at all
27        if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) {
28            return value;
29        }
30        debug!("erase_regions({:?})", value);
31        let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
32        debug!("erase_regions = {:?}", value1);
33        value1
34    }
35}
36
37struct RegionEraserVisitor<'tcx> {
38    tcx: TyCtxt<'tcx>,
39}
40
41impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
42    fn cx(&self) -> TyCtxt<'tcx> {
43        self.tcx
44    }
45
46    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
47        if ty.has_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
48    }
49
50    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
51    where
52        T: TypeFoldable<TyCtxt<'tcx>>,
53    {
54        let u = self.tcx.anonymize_bound_vars(t);
55        u.super_fold_with(self)
56    }
57
58    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
59        // We must not erase bound regions. `for<'a> fn(&'a ())` and
60        // `fn(&'free ())` are different types: they may implement different
61        // traits and have a different `TypeId`.
62        match *r {
63            ty::ReBound(..) => r,
64            _ => self.tcx.lifetimes.re_erased,
65        }
66    }
67}