deduplicate erase_regions

there is no need for 3 versions of the function
This commit is contained in:
Ariel Ben-Yehuda 2015-09-15 00:47:14 +03:00
parent 3dc780ed6f
commit 5e4704f6ee
11 changed files with 133 additions and 269 deletions

View file

@ -24,6 +24,7 @@ use session;
use llvm::{self, ValueRef, get_params};
use middle::def;
use middle::def_id::{DefId, LOCAL_CRATE};
use middle::infer::normalize_associated_type;
use middle::subst;
use middle::subst::{Subst, Substs};
use rustc::front::map as hir_map;
@ -260,7 +261,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
let tcx = ccx.tcx();
// Normalize the type for better caching.
let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty);
let bare_fn_ty = tcx.erase_regions(&bare_fn_ty);
// If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
let is_by_ref = match closure_kind {
@ -521,7 +522,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
// Type scheme of the function item (may have type params)
let fn_type_scheme = tcx.lookup_item_type(def_id);
let fn_type = monomorphize::normalize_associated_type(tcx, &fn_type_scheme.ty);
let fn_type = normalize_associated_type(tcx, &fn_type_scheme.ty);
// Find the actual function pointer.
let mut val = {

View file

@ -135,7 +135,7 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-> ValueRef {
// Normalize type so differences in regions and typedefs don't cause
// duplicate declarations
let substs = erase_regions(ccx.tcx(), substs);
let substs = ccx.tcx().erase_regions(substs);
let mono_id = MonoId {
def: closure_id,
params: &substs.func_substs.types

View file

@ -47,7 +47,6 @@ use arena::TypedArena;
use libc::{c_uint, c_char};
use std::ffi::CString;
use std::cell::{Cell, RefCell};
use std::result::Result as StdResult;
use std::vec::Vec;
use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
@ -56,65 +55,6 @@ use syntax::parse::token;
pub use trans::context::CrateContext;
/// 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). This
/// is a stronger, caching version of `ty::fold::erase_regions`.
pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
where T : TypeFoldable<'tcx>
{
let value1 = value.fold_with(&mut RegionEraser(cx));
debug!("erase_regions({:?}) = {:?}",
value, value1);
return value1;
struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.0 }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match self.tcx().normalized_cache.borrow().get(&ty).cloned() {
None => {}
Some(u) => return u
}
let t_norm = ty::fold::super_fold_ty(self, ty);
self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
return t_norm;
}
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);
ty::fold::super_fold_binder(self, &u)
}
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
// because late-bound regions affect subtyping, we can't
// erase the bound/free distinction, but we can replace
// all free regions with 'static.
//
// 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 'static
// whenever a substitution occurs.
match r {
ty::ReLateBound(..) => r,
_ => ty::ReStatic
}
}
fn fold_substs(&mut self,
substs: &subst::Substs<'tcx>)
-> subst::Substs<'tcx> {
subst::Substs { regions: subst::ErasedRegions,
types: substs.types.fold_with(self) }
}
}
}
/// Is the type's representation size known at compile time?
pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
ty.is_sized(&tcx.empty_parameter_environment(), DUMMY_SP)
@ -1043,7 +983,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let tcx = ccx.tcx();
// Remove any references to regions; this helps improve caching.
let trait_ref = erase_regions(tcx, &trait_ref);
let trait_ref = tcx.erase_regions(&trait_ref);
// First check the cache.
match ccx.trait_cache().borrow().get(&trait_ref) {
@ -1098,8 +1038,8 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let vtable = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
let vtable = erase_regions(tcx,
&drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable)
let vtable = infer::drain_fulfillment_cx_or_panic(
span, &infcx, &mut fulfill_cx, &vtable
);
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
@ -1134,59 +1074,8 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let obligation = traits::Obligation::new(cause.clone(), predicate);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
}
pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
infcx: &infer::InferCtxt<'a,'tcx>,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> T
where T : TypeFoldable<'tcx>
{
match drain_fulfillment_cx(infcx, fulfill_cx, result) {
Ok(v) => v,
Err(errors) => {
infcx.tcx.sess.span_bug(
span,
&format!("Encountered errors `{:?}` fulfilling during trans",
errors));
}
}
}
/// Finishes processes any obligations that remain in the fulfillment
/// context, and then "freshens" and returns `result`. This is
/// primarily used during normalization and other cases where
/// processing the obligations in `fulfill_cx` may cause type
/// inference variables that appear in `result` to be unified, and
/// hence we need to process those obligations to get the complete
/// picture of the type.
pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
where T : TypeFoldable<'tcx>
{
debug!("drain_fulfillment_cx(result={:?})",
result);
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
match fulfill_cx.select_all_or_error(infcx) {
Ok(()) => { }
Err(errors) => {
return Err(errors);
}
}
// Use freshen to simultaneously replace all type variables with
// their bindings and replace all regions with 'static. This is
// sort of overkill because we do not expect there to be any
// unbound type variables, hence no `TyFresh` types should ever be
// inserted.
Ok(result.fold_with(&mut infcx.freshener()))
infer::drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
}
// Key used to lookup values supplied for type parameters in an expr.

View file

@ -27,6 +27,7 @@ use llvm::{ModuleRef, ContextRef, ValueRef};
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
DIDescriptor, FlagPrototyped};
use middle::def_id::DefId;
use middle::infer::normalize_associated_type;
use middle::subst::{self, Substs};
use rustc_front;
use rustc_front::hir;
@ -463,7 +464,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-> DIArray
{
let self_type = param_substs.self_ty();
let self_type = monomorphize::normalize_associated_type(cx.tcx(), &self_type);
let self_type = normalize_associated_type(cx.tcx(), &self_type);
// Only true for static default methods:
let has_self_type = self_type.is_some();

View file

@ -26,7 +26,6 @@ use syntax::abi;
use trans::attributes;
use trans::base;
use trans::context::CrateContext;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
@ -104,7 +103,7 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name,
fn_type);
let fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type);
let fn_type = infer::normalize_associated_type(ccx.tcx(), &fn_type);
debug!("declare_rust_fn (after normalised associated types) fn_type={:?}",
fn_type);

View file

@ -13,10 +13,9 @@ use session;
use llvm::ValueRef;
use llvm;
use middle::def_id::DefId;
use middle::infer;
use middle::infer::normalize_associated_type;
use middle::subst;
use middle::subst::{Subst, Substs};
use middle::traits;
use middle::ty::fold::{TypeFolder, TypeFoldable};
use trans::attributes;
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
@ -33,7 +32,6 @@ use rustc_front::attr;
use syntax::abi;
use syntax::ast;
use syntax::codemap::DUMMY_SP;
use std::hash::{Hasher, Hash, SipHasher};
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@ -300,39 +298,3 @@ pub fn field_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
{
normalize_associated_type(tcx, &f.ty(tcx, param_substs))
}
/// Removes associated types, if any. Since this during
/// monomorphization, we know that only concrete types are involved,
/// and hence we can be sure that all associated types will be
/// completely normalized away.
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
where T : TypeFoldable<'tcx> + HasTypeFlags
{
debug!("normalize_associated_type(t={:?})", value);
let value = erase_regions(tcx, value);
if !value.has_projection_types() {
return value;
}
// FIXME(#20304) -- cache
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
let mut selcx = traits::SelectionContext::new(&infcx);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &value);
debug!("normalize_associated_type: result={:?} obligations={:?}",
result,
obligations);
let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
result
}

View file

@ -325,7 +325,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
// Rust types are defined as the same LLVM types. If we don't do
// this then, e.g. `Option<{myfield: bool}>` would be a different
// type than `Option<myrec>`.
let t_norm = erase_regions(cx.tcx(), &t);
let t_norm = cx.tcx().erase_regions(&t);
if t != t_norm {
let llty = in_memory_type_of(cx, t_norm);