mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
make erase_regions
use a query instead of an ad-hoc cache
This commit is contained in:
parent
0ae18a18b4
commit
0e67d17358
@ -609,6 +609,7 @@ define_dep_nodes!( <'tcx>
|
||||
[] PostorderCnums,
|
||||
[] HasCloneClosures(CrateNum),
|
||||
[] HasCopyClosures(CrateNum),
|
||||
[] EraseRegionsTy { ty: Ty<'tcx> },
|
||||
|
||||
[] Freevars(DefId),
|
||||
[] MaybeUnusedTraitImport(DefId),
|
||||
|
@ -892,9 +892,6 @@ pub struct GlobalCtxt<'tcx> {
|
||||
// Internal cache for metadata decoding. No need to track deps on this.
|
||||
pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
|
||||
|
||||
// FIXME dep tracking -- should be harmless enough
|
||||
pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
|
||||
|
||||
/// Caches the results of trait selection. This cache is used
|
||||
/// for things that do not have to do with the parameters in scope.
|
||||
pub selection_cache: traits::SelectionCache<'tcx>,
|
||||
@ -1172,7 +1169,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
maps: maps::Maps::new(providers),
|
||||
mir_passes,
|
||||
rcache: RefCell::new(FxHashMap()),
|
||||
normalized_cache: RefCell::new(FxHashMap()),
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
crate_name: Symbol::intern(crate_name),
|
||||
|
79
src/librustc/ty/erase_regions.rs
Normal file
79
src/librustc/ty/erase_regions.rs
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::fold::{TypeFolder, TypeFoldable};
|
||||
|
||||
pub(super) fn provide(providers: &mut ty::maps::Providers) {
|
||||
*providers = ty::maps::Providers {
|
||||
erase_regions_ty,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
||||
fn erase_regions_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// NB: use `super_fold_with` here. If we used `fold_with`, it
|
||||
// could invoke the `erase_regions_ty` query recursively.
|
||||
ty.super_fold_with(&mut RegionEraserVisitor { tcx })
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// Returns an equivalent value with all free regions removed (note
|
||||
/// that late-bound regions remain, because they are important for
|
||||
/// subtyping, but they are anonymized and normalized as well)..
|
||||
pub fn erase_regions<T>(self, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
|
||||
debug!("erase_regions({:?}) = {:?}", value, value1);
|
||||
value1
|
||||
}
|
||||
}
|
||||
|
||||
struct RegionEraserVisitor<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if let Some(ty_lifted) = self.tcx.lift_to_global(&ty) {
|
||||
self.tcx.erase_regions_ty(ty_lifted)
|
||||
} else {
|
||||
ty.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
let u = self.tcx.anonymize_late_bound_regions(t);
|
||||
u.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
// because late-bound regions affect subtyping, we can't
|
||||
// erase the bound/free distinction, but we can replace
|
||||
// all free regions with 'erased.
|
||||
//
|
||||
// Note that we *CAN* replace early-bound regions -- the
|
||||
// type system never "sees" those, they get substituted
|
||||
// away. In trans, they will always be erased to 'erased
|
||||
// whenever a substitution occurs.
|
||||
match *r {
|
||||
ty::ReLateBound(..) => r,
|
||||
_ => self.tcx.types.re_erased
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -444,67 +444,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Region eraser
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// Returns an equivalent value with all free regions removed (note
|
||||
/// that late-bound regions remain, because they are important for
|
||||
/// subtyping, but they are anonymized and normalized as well)..
|
||||
pub fn erase_regions<T>(self, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
let value1 = value.fold_with(&mut RegionEraser(self));
|
||||
debug!("erase_regions({:?}) = {:?}",
|
||||
value, value1);
|
||||
return value1;
|
||||
|
||||
struct RegionEraser<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(TyCtxt<'a, 'gcx, 'tcx>);
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraser<'a, 'gcx, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.0 }
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if let Some(u) = self.tcx().normalized_cache.borrow().get(&ty).cloned() {
|
||||
return u;
|
||||
}
|
||||
|
||||
// FIXME(eddyb) should local contexts have a cache too?
|
||||
if let Some(ty_lifted) = self.tcx().lift_to_global(&ty) {
|
||||
let tcx = self.tcx().global_tcx();
|
||||
let t_norm = ty_lifted.super_fold_with(&mut RegionEraser(tcx));
|
||||
tcx.normalized_cache.borrow_mut().insert(ty_lifted, t_norm);
|
||||
t_norm
|
||||
} else {
|
||||
ty.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
let u = self.tcx().anonymize_late_bound_regions(t);
|
||||
u.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
// because late-bound regions affect subtyping, we can't
|
||||
// erase the bound/free distinction, but we can replace
|
||||
// all free regions with 'erased.
|
||||
//
|
||||
// Note that we *CAN* replace early-bound regions -- the
|
||||
// type system never "sees" those, they get substituted
|
||||
// away. In trans, they will always be erased to 'erased
|
||||
// whenever a substitution occurs.
|
||||
match *r {
|
||||
ty::ReLateBound(..) => r,
|
||||
_ => self.tcx().types.re_erased
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Region shifter
|
||||
//
|
||||
|
@ -75,6 +75,12 @@ impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription for queries::erase_regions_ty<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
|
||||
format!("erasing regions from `{:?}`", ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> {
|
||||
fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String {
|
||||
let id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||
|
@ -341,12 +341,21 @@ define_maps! { <'tcx>
|
||||
|
||||
[] fn has_copy_closures: HasCopyClosures(CrateNum) -> bool,
|
||||
[] fn has_clone_closures: HasCloneClosures(CrateNum) -> bool,
|
||||
|
||||
// Erases regions from `ty` to yield a new type.
|
||||
// Normally you would just use `tcx.erase_regions(&value)`,
|
||||
// however, which uses this query as a kind of cache.
|
||||
[] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>,
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// These functions are little shims used to find the dep-node for a
|
||||
// given query when there is not a *direct* mapping:
|
||||
|
||||
fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
|
||||
DepConstructor::EraseRegionsTy { ty }
|
||||
}
|
||||
|
||||
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
|
||||
DepConstructor::TypeParamPredicates {
|
||||
item_id,
|
||||
|
@ -701,6 +701,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||
DepKind::CompileCodegenUnit |
|
||||
DepKind::FulfillObligation |
|
||||
DepKind::VtableMethods |
|
||||
DepKind::EraseRegionsTy |
|
||||
|
||||
// These are just odd
|
||||
DepKind::Null |
|
||||
@ -773,6 +774,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||
DepKind::ConstIsRvaluePromotableToStatic => {
|
||||
force!(const_is_rvalue_promotable_to_static, def_id!());
|
||||
}
|
||||
DepKind::RvaluePromotableMap => { force!(rvalue_promotable_map, def_id!()); }
|
||||
DepKind::ImplParent => { force!(impl_parent, def_id!()); }
|
||||
DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); }
|
||||
DepKind::IsExportedSymbol => { force!(is_exported_symbol, def_id!()); }
|
||||
|
@ -90,6 +90,7 @@ pub mod adjustment;
|
||||
pub mod binding;
|
||||
pub mod cast;
|
||||
pub mod error;
|
||||
mod erase_regions;
|
||||
pub mod fast_reject;
|
||||
pub mod fold;
|
||||
pub mod inhabitedness;
|
||||
@ -2575,6 +2576,7 @@ fn original_crate_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pub fn provide(providers: &mut ty::maps::Providers) {
|
||||
util::provide(providers);
|
||||
context::provide(providers);
|
||||
erase_regions::provide(providers);
|
||||
*providers = ty::maps::Providers {
|
||||
associated_item,
|
||||
associated_item_def_ids,
|
||||
|
Loading…
Reference in New Issue
Block a user