| use tracing::debug; |
| |
| use crate::query::Providers; |
| use crate::ty::{ |
| self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, |
| }; |
| |
| pub(super) fn provide(providers: &mut Providers) { |
| *providers = Providers { erase_and_anonymize_regions_ty, ..*providers }; |
| } |
| |
| fn erase_and_anonymize_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { |
| // N.B., use `super_fold_with` here. If we used `fold_with`, it |
| // could invoke the `erase_and_anonymize_regions_ty` query recursively. |
| ty.super_fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx }) |
| } |
| |
| impl<'tcx> TyCtxt<'tcx> { |
| /// Returns an equivalent value with all free regions removed and |
| /// bound regions anonymized. (note that bound regions are important |
| /// for subtyping and generally type equality so *cannot* be removed) |
| pub fn erase_and_anonymize_regions<T>(self, value: T) -> T |
| where |
| T: TypeFoldable<TyCtxt<'tcx>>, |
| { |
| // If there's nothing to erase or anonymize, avoid performing the query at all |
| if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { |
| return value; |
| } |
| debug!("erase_and_anonymize_regions({:?})", value); |
| let value1 = value.fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx: self }); |
| debug!("erase_and_anonymize_regions = {:?}", value1); |
| value1 |
| } |
| } |
| |
| struct RegionEraserAndAnonymizerVisitor<'tcx> { |
| tcx: TyCtxt<'tcx>, |
| } |
| |
| impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserAndAnonymizerVisitor<'tcx> { |
| fn cx(&self) -> TyCtxt<'tcx> { |
| self.tcx |
| } |
| |
| fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { |
| if !ty.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { |
| ty |
| } else if ty.has_infer() { |
| ty.super_fold_with(self) |
| } else { |
| self.tcx.erase_and_anonymize_regions_ty(ty) |
| } |
| } |
| |
| fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> |
| where |
| T: TypeFoldable<TyCtxt<'tcx>>, |
| { |
| let u = self.tcx.anonymize_bound_vars(t); |
| u.super_fold_with(self) |
| } |
| |
| fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { |
| // We must not erase bound regions. `for<'a> fn(&'a ())` and |
| // `fn(&'free ())` are different types: they may implement different |
| // traits and have a different `TypeId`. |
| match r.kind() { |
| ty::ReBound(..) => r, |
| _ => self.tcx.lifetimes.re_erased, |
| } |
| } |
| |
| fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { |
| if ct.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { |
| ct.super_fold_with(self) |
| } else { |
| ct |
| } |
| } |
| |
| fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { |
| if p.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { |
| p.super_fold_with(self) |
| } else { |
| p |
| } |
| } |
| |
| fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { |
| if c.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { |
| c.super_fold_with(self) |
| } else { |
| c |
| } |
| } |
| } |