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:
parent
37702216eb
commit
f0a69b1a43
3 changed files with 70 additions and 213 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue