Refactor some coherence/method trans code, add an impls map to tcx.

Rewrite method_with_name_or_default to use the new impls map.
Get rid of ProvidedMethodsMap.
This commit is contained in:
Michael Sullivan 2013-07-15 14:19:36 -07:00
parent 37702216eb
commit f0a69b1a43
3 changed files with 70 additions and 213 deletions

View file

@ -177,9 +177,7 @@ pub fn trans_method_callee(bcx: block,
// Now that we know the impl ID, we can look up the method
// ID from its name
origin = typeck::method_static(
method_with_name_or_default(bcx.ccx(),
impl_id,
method_name));
method_with_name(bcx.ccx(), impl_id, method_name));
}
typeck::method_self(*) |
typeck::method_static(*) | typeck::method_param(*) |
@ -308,12 +306,10 @@ pub fn trans_static_method_callee(bcx: block,
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t)));
let mth_id = method_with_name_or_default(bcx.ccx(),
impl_did,
mname);
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
bcx, mth_id, impl_did, callee_id,
bcx, mth_id, callee_id,
*rcvr_substs, rcvr_origins);
let FnData {llfn: lval} =
@ -334,58 +330,22 @@ pub fn trans_static_method_callee(bcx: block,
}
}
pub fn method_from_methods(ms: &[@ast::method], name: ast::ident)
-> Option<ast::def_id> {
ms.iter().find_(|m| m.ident == name).map(|m| ast_util::local_def(m.id))
}
pub fn method_with_name_or_default(ccx: &mut CrateContext,
impl_id: ast::def_id,
name: ast::ident) -> ast::def_id {
let imp = ccx.impl_method_cache.find_copy(&(impl_id, name));
match imp {
pub fn method_with_name(ccx: &mut CrateContext,
impl_id: ast::def_id,
name: ast::ident) -> ast::def_id {
let meth_id_opt = ccx.impl_method_cache.find_copy(&(impl_id, name));
match meth_id_opt {
Some(m) => return m,
None => {}
}
// None of this feels like it should be the best way to do this.
let mut did = if impl_id.crate == ast::local_crate {
match ccx.tcx.items.get_copy(&impl_id.node) {
ast_map::node_item(@ast::item {
node: ast::item_impl(_, _, _, ref ms), _
}, _) => { method_from_methods(*ms, name) },
_ => fail!("method_with_name")
}
} else {
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
};
let imp = ccx.tcx.impls.find(&impl_id)
.expect("could not find impl while translating");
let meth = imp.methods.iter().find_(|m| m.ident == name)
.expect("could not find method while translating");
if did.is_none() {
// Look for a default method
let pmm = ccx.tcx.provided_methods;
match pmm.find(&impl_id) {
Some(pmis) => {
for pmis.iter().advance |pmi| {
if pmi.method_info.ident == name {
debug!("pmi.method_info.did = %?",
pmi.method_info.did);
did = Some(pmi.method_info.did);
}
}
}
None => {}
}
}
let imp = did.expect("could not find method while translating");
ccx.impl_method_cache.insert((impl_id, name), imp);
imp
}
pub fn method_ty_param_count(ccx: &CrateContext, m_id: ast::def_id,
i_id: ast::def_id) -> uint {
debug!("method_ty_param_count: m_id: %?, i_id: %?", m_id, i_id);
ty::method(ccx.tcx, m_id).generics.type_param_defs.len()
ccx.impl_method_cache.insert((impl_id, name), meth.did);
meth.did
}
pub fn trans_monomorphized_callee(bcx: block,
@ -401,8 +361,7 @@ pub fn trans_monomorphized_callee(bcx: block,
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
let ccx = bcx.ccx();
let mname = ty::trait_method(ccx.tcx, trait_id, n_method).ident;
let mth_id = method_with_name_or_default(
bcx.ccx(), impl_did, mname);
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
// obtain the `self` value:
let mut temp_cleanups = ~[];
@ -413,7 +372,7 @@ pub fn trans_monomorphized_callee(bcx: block,
// those from the impl and those from the method:
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
bcx, mth_id, impl_did, callee_id,
bcx, mth_id, callee_id,
*rcvr_substs, rcvr_origins);
// translate the function
@ -452,7 +411,6 @@ pub fn trans_monomorphized_callee(bcx: block,
pub fn combine_impl_and_methods_tps(bcx: block,
mth_did: ast::def_id,
impl_did: ast::def_id,
callee_id: ast::node_id,
rcvr_substs: &[ty::t],
rcvr_origins: typeck::vtable_res)
@ -475,15 +433,16 @@ pub fn combine_impl_and_methods_tps(bcx: block,
* mapped to. */
let ccx = bcx.ccx();
let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did);
let method = ty::method(ccx.tcx, mth_did);
let n_m_tps = method.generics.type_param_defs.len();
let node_substs = node_id_type_params(bcx, callee_id);
debug!("rcvr_substs=%?", rcvr_substs.map(|t| bcx.ty_to_str(*t)));
debug!("rcvr_substs=%?", rcvr_substs.repr(ccx.tcx));
let ty_substs
= vec::append(rcvr_substs.to_owned(),
node_substs.tailn(node_substs.len() - n_m_tps));
debug!("n_m_tps=%?", n_m_tps);
debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(*t)));
debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(*t)));
debug!("node_substs=%?", node_substs.repr(ccx.tcx));
debug!("ty_substs=%?", ty_substs.repr(ccx.tcx));
// Now, do the same work for the vtables. The vtables might not
@ -744,7 +703,7 @@ pub fn make_impl_vtable(bcx: block,
} else {
debug!("(making impl vtable) adding method to vtable: %s",
tcx.sess.str_of(im.ident));
let m_id = method_with_name_or_default(ccx, impl_id, im.ident);
let m_id = method_with_name(ccx, impl_id, im.ident);
trans_fn_ref_with_vtables(bcx, m_id, 0,
substs, Some(vtables)).llfn

View file

@ -214,21 +214,6 @@ pub enum AutoRef {
AutoUnsafe(ast::mutability)
}
// Stores information about provided methods (a.k.a. default methods) in
// implementations.
//
// This is a map from ID of each implementation to the method info and trait
// method ID of each of the default methods belonging to the trait that
// implementation implements.
pub type ProvidedMethodsMap = @mut HashMap<def_id,@mut ~[@ProvidedMethodInfo]>;
// Stores the method info and definition ID of the associated trait method for
// each instantiation of each provided method.
pub struct ProvidedMethodInfo {
method_info: @MethodInfo,
trait_method_def_id: def_id
}
pub struct ProvidedMethodSource {
method_id: ast::def_id,
impl_id: ast::def_id
@ -287,10 +272,7 @@ struct ctxt_ {
adjustments: @mut HashMap<ast::node_id, @AutoAdjustment>,
normalized_cache: @mut HashMap<t, t>,
lang_items: middle::lang_items::LanguageItems,
// A mapping from an implementation ID to the method info and trait
// method ID of the provided (a.k.a. default) methods in the traits that
// that implementation implements.
provided_methods: ProvidedMethodsMap,
// A mapping of fake provided method def_ids to the default implementation
provided_method_sources: @mut HashMap<ast::def_id, ProvidedMethodSource>,
supertraits: @mut HashMap<ast::def_id, @~[@TraitRef]>,
@ -311,6 +293,12 @@ struct ctxt_ {
// Methods in these implementations don't need to be exported.
inherent_impls: @mut HashMap<ast::def_id, @mut ~[@Impl]>,
// Maps a def_id of an impl to an Impl structure.
// Note that this contains all of the impls that we know about,
// including ones in other crates. It's not clear that this is the best
// way to do it.
impls: @mut HashMap<ast::def_id, @Impl>,
// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
// present in this set can be warned about.
used_unsafe: @mut HashSet<ast::node_id>,
@ -904,13 +892,13 @@ pub fn mk_ctxt(s: session::Session,
adjustments: @mut HashMap::new(),
normalized_cache: new_ty_hash(),
lang_items: lang_items,
provided_methods: @mut HashMap::new(),
provided_method_sources: @mut HashMap::new(),
supertraits: @mut HashMap::new(),
destructor_for_type: @mut HashMap::new(),
destructors: @mut HashSet::new(),
trait_impls: @mut HashMap::new(),
inherent_impls: @mut HashMap::new(),
impls: @mut HashMap::new(),
used_unsafe: @mut HashSet::new(),
used_mut_nodes: @mut HashSet::new(),
}

View file

@ -20,7 +20,7 @@ use metadata::csearch;
use metadata::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, get};
use middle::ty::{ProvidedMethodSource, get};
use middle::ty::{lookup_item_type, subst};
use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil};
@ -250,27 +250,16 @@ impl CoherenceChecker {
}
}
// We only want to generate one Impl structure. When we generate one,
// we store it here so that we don't recreate it.
let mut implementation_opt = None;
let implementation = self.create_impl_from_item(item);
for associated_traits.iter().advance |associated_trait| {
let trait_ref =
ty::node_id_to_trait_ref(
self.crate_context.tcx,
associated_trait.ref_id);
let trait_ref = ty::node_id_to_trait_ref(
self.crate_context.tcx, associated_trait.ref_id);
debug!("(checking implementation) adding impl for trait '%s', item '%s'",
trait_ref.repr(self.crate_context.tcx),
self.crate_context.tcx.sess.str_of(item.ident));
self.instantiate_default_methods(local_def(item.id), trait_ref);
let implementation;
if implementation_opt.is_none() {
implementation = self.create_impl_from_item(item);
implementation_opt = Some(implementation);
}
self.add_trait_impl(trait_ref.def_id, implementation_opt.get());
self.add_trait_impl(trait_ref.def_id, implementation);
}
// Add the implementation to the mapping from implementation to base
@ -285,17 +274,6 @@ impl CoherenceChecker {
Some(base_type_def_id) => {
// XXX: Gather up default methods?
if associated_traits.len() == 0 {
let implementation;
match implementation_opt {
None => {
implementation =
self.create_impl_from_item(item);
}
Some(existing_implementation) => {
implementation = existing_implementation;
}
}
self.add_inherent_impl(base_type_def_id, implementation);
}
@ -303,6 +281,8 @@ impl CoherenceChecker {
base_type_def_id);
}
}
tcx.impls.insert(implementation.did, implementation);
}
// Creates default method IDs and performs type substitutions for an impl
@ -310,7 +290,8 @@ impl CoherenceChecker {
// `ProvidedMethodInfo` instance into the `provided_method_sources` map.
pub fn instantiate_default_methods(&self,
impl_id: ast::def_id,
trait_ref: &ty::TraitRef) {
trait_ref: &ty::TraitRef,
all_methods: &mut ~[@MethodInfo]) {
let tcx = self.crate_context.tcx;
debug!("instantiate_default_methods(impl_id=%?, trait_ref=%s)",
impl_id, trait_ref.repr(tcx));
@ -364,39 +345,13 @@ impl CoherenceChecker {
self.crate_context.tcx.provided_method_sources.insert(new_did,
source);
let provided_method_info =
@ProvidedMethodInfo {
method_info: @MethodInfo {
did: new_did,
n_tps: trait_method.generics.type_param_defs.len(),
ident: trait_method.ident,
explicit_self: trait_method.explicit_self
},
trait_method_def_id: trait_method.def_id
};
let pmm = self.crate_context.tcx.provided_methods;
match pmm.find(&impl_id) {
Some(&mis) => {
// If the trait already has an entry in the
// provided_methods_map, we just need to add this
// method to that entry.
debug!("(checking implementation) adding method `%s` \
to entry for existing trait",
self.crate_context.tcx.sess.str_of(
provided_method_info.method_info.ident));
mis.push(provided_method_info);
}
None => {
// If the trait doesn't have an entry yet, create one.
debug!("(checking implementation) creating new entry \
for method `%s`",
self.crate_context.tcx.sess.str_of(
provided_method_info.method_info.ident));
pmm.insert(impl_id,
@mut ~[provided_method_info]);
}
}
let method_info = @MethodInfo {
did: new_did,
n_tps: trait_method.generics.type_param_defs.len(),
ident: trait_method.ident,
explicit_self: trait_method.explicit_self
};
all_methods.push(method_info);
}
}
@ -606,13 +561,11 @@ impl CoherenceChecker {
// This check doesn't really have anything to do with coherence. It's
// here for historical reasons
pub fn please_check_that_trait_methods_are_implemented(&self,
all_methods:
&mut
~[@MethodInfo],
trait_did: def_id,
trait_ref_span:
span) {
pub fn check_trait_methods_are_implemented(
&self,
all_methods: &mut ~[@MethodInfo],
trait_did: def_id,
trait_ref_span: span) {
let tcx = self.crate_context.tcx;
@ -621,12 +574,6 @@ impl CoherenceChecker {
for uint::range(0, all_methods.len()) |i| {
provided_names.insert(all_methods[i].ident);
}
// Default methods
let r = ty::provided_trait_methods(tcx, trait_did);
for r.iter().advance |method| {
debug!("inserting provided method %s", method.ident.repr(tcx));
provided_names.insert(method.ident);
}
let r = ty::trait_methods(tcx, trait_did);
for r.iter().advance |method| {
@ -679,39 +626,6 @@ impl CoherenceChecker {
}
}
fn add_provided_methods_to_impl(
&self,
all_methods: &mut ~[@MethodInfo],
trait_did: &ast::def_id,
impl_id: &ast::def_id) {
match self.crate_context.tcx
.provided_methods
.find(impl_id) {
None => {
debug!("(creating impl) trait with node_id `%d` \
has no provided methods", trait_did.node);
/* fall through */
}
Some(&all_provided_methods) => {
debug!("(creating impl) trait with node_id `%d` \
has provided methods", trait_did.node);
// Add all provided methods.
for all_provided_methods.iter().advance |provided_method| {
debug!(
"(creating impl) adding provided method \
`%s` to impl",
provided_method.method_info
.ident.repr(self.crate_context.tcx));
all_methods.push(provided_method.method_info);
}
}
}
}
// Converts an implementation in the AST to an Impl structure.
pub fn create_impl_from_item(&self, item: @item) -> @Impl {
match item.node {
@ -721,28 +635,23 @@ impl CoherenceChecker {
methods.push(method_to_MethodInfo(*ast_method));
}
// Check that we have implementations of every trait method
for trait_refs.iter().advance |trait_ref| {
let trait_did =
self.trait_ref_to_trait_def_id(trait_ref);
self.please_check_that_trait_methods_are_implemented(
let ty_trait_ref = ty::node_id_to_trait_ref(
self.crate_context.tcx,
trait_ref.ref_id);
let trait_did = ty_trait_ref.def_id;
self.instantiate_default_methods(local_def(item.id),
ty_trait_ref,
&mut methods);
// Check that we have implementations of every trait method
self.check_trait_methods_are_implemented(
&mut methods,
trait_did,
trait_ref.path.span);
}
// For each trait that the impl implements, see which
// methods are provided. For each of those methods,
// if a method of that name is not inherent to the
// impl, use the provided definition in the trait.
for trait_refs.iter().advance |trait_ref| {
let trait_did = self.trait_ref_to_trait_def_id(trait_ref);
self.add_provided_methods_to_impl(
&mut methods,
&trait_did,
&local_def(item.id));
}
return @Impl {
did: local_def(item.id),
ident: item.ident,
@ -813,15 +722,13 @@ impl CoherenceChecker {
// Record all the trait methods.
let mut implementation = @implementation;
for associated_traits.iter().advance |trait_ref| {
self.instantiate_default_methods(implementation.did,
*trait_ref);
// XXX(sully): We could probably avoid this copy if there are no
// default methods.
let mut methods = implementation.methods.clone();
self.add_provided_methods_to_impl(&mut methods,
&trait_ref.def_id,
&implementation.did);
self.instantiate_default_methods(implementation.did,
*trait_ref,
&mut methods);
implementation = @Impl {
methods: methods,
..*implementation
@ -848,6 +755,9 @@ impl CoherenceChecker {
base_type_def_id);
}
}
self.crate_context.tcx.impls.insert(implementation.did,
implementation);
}
// Adds implementations and traits from external crates to the coherence