Skip to content

Commit

Permalink
librustc: Implement basic lazy implementation loading.
Browse files Browse the repository at this point in the history
This is only for implementations defined in the same crate as the trait they
implement.
  • Loading branch information
pcwalton committed Aug 28, 2013
1 parent ff7b8d6 commit 6c37e3b
Show file tree
Hide file tree
Showing 12 changed files with 384 additions and 79 deletions.
3 changes: 3 additions & 0 deletions src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ pub static tag_item_impl_vtables: uint = 0x82;
pub static tag_impls: uint = 0x83;
pub static tag_impls_impl: uint = 0x84;

pub static tag_items_data_item_inherent_impl: uint = 0x85;
pub static tag_items_data_item_extension_impl: uint = 0x86;

pub struct LinkMeta {
name: @str,
vers: @str,
Expand Down
25 changes: 25 additions & 0 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,28 @@ pub fn each_impl(cstore: @mut cstore::CStore,
decoder::each_impl(cdata, callback)
}

pub fn each_implementation_for_type(cstore: @mut cstore::CStore,
def_id: ast::def_id,
callback: &fn(ast::def_id)) {
let cdata = cstore::get_crate_data(cstore, def_id.crate);
decoder::each_implementation_for_type(cdata, def_id.node, callback)
}

pub fn each_implementation_for_trait(cstore: @mut cstore::CStore,
def_id: ast::def_id,
callback: &fn(ast::def_id)) {
let cdata = cstore::get_crate_data(cstore, def_id.crate);
decoder::each_implementation_for_trait(cdata, def_id.node, callback)
}

/// If the given def ID describes a method belonging to a trait (either a
/// default method or an implementation of a trait method), returns the ID of
/// the trait that the method belongs to. Otherwise, returns `None`.
pub fn get_trait_of_method(cstore: @mut cstore::CStore,
def_id: ast::def_id,
tcx: ty::ctxt)
-> Option<ast::def_id> {
let cdata = cstore::get_crate_data(cstore, def_id.crate);
decoder::get_trait_of_method(cdata, def_id.node, tcx)
}

62 changes: 61 additions & 1 deletion src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use metadata::decoder;
use metadata::tydecode::{parse_ty_data, parse_def_id,
parse_type_param_def_data,
parse_bare_fn_ty_data, parse_trait_ref_data};
use middle::ty::{ImplContainer, TraitContainer};
use middle::ty;
use middle::typeck;
use middle::astencode::vtable_decoder_helpers;
Expand Down Expand Up @@ -958,8 +959,15 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
{
let method_doc = lookup_item(id, cdata.data);
let def_id = item_def_id(method_doc, cdata);

let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
method_doc);
let container_doc = lookup_item(container_id.node, cdata.data);
let container = match item_family(container_doc) {
Trait => TraitContainer(container_id),
_ => ImplContainer(container_id),
};

let name = item_name(intr, method_doc);
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
Expand All @@ -980,7 +988,7 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
explicit_self,
vis,
def_id,
container_id,
container,
provided_source
)
}
Expand Down Expand Up @@ -1391,4 +1399,56 @@ pub fn each_impl(cdata: cmd, callback: &fn(ast::def_id)) {
};
}

pub fn each_implementation_for_type(cdata: cmd,
id: ast::NodeId,
callback: &fn(ast::def_id)) {
let item_doc = lookup_item(id, cdata.data);
/*println(fmt!(">>> reading inherent impls from %s",
token::ident_to_str(&item_name(token::get_ident_interner(),
item_doc))));*/
do reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl)
|impl_doc| {
let implementation_def_id = item_def_id(impl_doc, cdata);
/*println(fmt!(">>>>> read inherent impl: %d:%d",
implementation_def_id.crate,
implementation_def_id.node));*/
callback(implementation_def_id);
true
};
}

pub fn each_implementation_for_trait(cdata: cmd,
id: ast::NodeId,
callback: &fn(ast::def_id)) {
let item_doc = lookup_item(id, cdata.data);

let _ = do reader::tagged_docs(item_doc,
tag_items_data_item_extension_impl)
|impl_doc| {
let implementation_def_id = item_def_id(impl_doc, cdata);
callback(implementation_def_id);
true
};
}

pub fn get_trait_of_method(cdata: cmd, id: ast::NodeId, tcx: ty::ctxt)
-> Option<ast::def_id> {
let item_doc = lookup_item(id, cdata.data);
let parent_item_id = match item_parent_item(item_doc) {
None => return None,
Some(item_id) => item_id,
};
let parent_item_id = translate_def_id(cdata, parent_item_id);
let parent_item_doc = lookup_item(parent_item_id.node, cdata.data);
match item_family(parent_item_doc) {
Trait => Some(item_def_id(parent_item_doc, cdata)),
Impl => {
do reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref).map
|_| {
item_trait_ref(parent_item_doc, tcx, cdata).def_id
}
}
_ => None
}
}

73 changes: 69 additions & 4 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,38 @@ fn should_inline(attrs: &[Attribute]) -> bool {
}
}

// Encodes the inherent implementations of a structure, enumeration, or trait.
fn encode_inherent_implementations(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
def_id: def_id) {
match ecx.tcx.inherent_impls.find(&def_id) {
None => {}
Some(&implementations) => {
for implementation in implementations.iter() {
ebml_w.start_tag(tag_items_data_item_inherent_impl);
encode_def_id(ebml_w, implementation.did);
ebml_w.end_tag();
}
}
}
}

// Encodes the implementations of a trait defined in this crate.
fn encode_extension_implementations(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
trait_def_id: def_id) {
match ecx.tcx.trait_impls.find(&trait_def_id) {
None => {}
Some(&implementations) => {
for implementation in implementations.iter() {
ebml_w.start_tag(tag_items_data_item_extension_impl);
encode_def_id(ebml_w, implementation.did);
ebml_w.end_tag();
}
}
}
}

fn encode_info_for_item(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
item: @item,
Expand Down Expand Up @@ -902,6 +934,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_region_param(ecx, ebml_w, item);

// Encode inherent implementations for this enumeration.
encode_inherent_implementations(ecx, ebml_w, def_id);

ebml_w.end_tag();

encode_enum_variant_info(ecx,
Expand Down Expand Up @@ -954,6 +990,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
}
}

// Encode inherent implementations for this structure.
encode_inherent_implementations(ecx, ebml_w, def_id);

/* Each class has its own index -- encode it */
let bkts = create_index(idx);
encode_index(ebml_w, bkts, write_i64);
Expand Down Expand Up @@ -1069,6 +1108,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref);
}

// Encode the implementations of this trait.
encode_extension_implementations(ecx, ebml_w, def_id);

ebml_w.end_tag();

// Now output the method info for each method.
Expand Down Expand Up @@ -1130,6 +1173,9 @@ fn encode_info_for_item(ecx: &EncodeContext,

ebml_w.end_tag();
}

// Encode inherent implementations for this trait.
encode_inherent_implementations(ecx, ebml_w, def_id);
}
item_mac(*) => fail!("item macros unimplemented")
}
Expand Down Expand Up @@ -1523,17 +1569,36 @@ struct ImplVisitor<'self> {
impl<'self> Visitor<()> for ImplVisitor<'self> {
fn visit_item(&mut self, item: @item, _: ()) {
match item.node {
item_impl(*) => {
self.ebml_w.start_tag(tag_impls_impl);
encode_def_id(self.ebml_w, local_def(item.id));
self.ebml_w.end_tag();
item_impl(_, Some(ref trait_ref), _, _) => {
let def_map = self.ecx.tcx.def_map;
let trait_def = def_map.get_copy(&trait_ref.ref_id);
let def_id = ast_util::def_id_of_def(trait_def);

// Load eagerly if this is an implementation of the Drop trait
// or if the trait is not defined in this crate.
if def_id == self.ecx.tcx.lang_items.drop_trait().unwrap() ||
def_id.crate != LOCAL_CRATE {
self.ebml_w.start_tag(tag_impls_impl);
encode_def_id(self.ebml_w, local_def(item.id));
self.ebml_w.end_tag();
}
}
_ => {}
}
visit::walk_item(self, item, ());
}
}

/// Encodes implementations that are eagerly loaded.
///
/// None of this is necessary in theory; we can load all implementations
/// lazily. However, in two cases the optimizations to lazily load
/// implementations are not yet implemented. These two cases, which require us
/// to load implementations eagerly, are:
///
/// * Destructors (implementations of the Drop trait).
///
/// * Implementations of traits not defined in this crate.
fn encode_impls(ecx: &EncodeContext,
crate: &Crate,
ebml_w: &mut writer::Encoder) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/privacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ impl PrivacyVisitor {

if method_id.crate == LOCAL_CRATE {
let is_private = self.method_is_private(span, method_id.node);
let container_id = ty::method(self.tcx, method_id).container_id;
let container_id = ty::method(self.tcx, method_id).container_id();
if is_private &&
(container_id.crate != LOCAL_CRATE ||
!self.privileged_items.iter().any(|x| x == &(container_id.node))) {
Expand Down
10 changes: 9 additions & 1 deletion src/librustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,14 @@ pub fn trans_fn_ref_with_vtables(
self_ty: None,
tps: /*bad*/ type_params.to_owned() };

// Load the info for the appropriate trait if necessary.
match ty::trait_of_method(tcx, def_id) {
None => {}
Some(trait_id) => {
ty::populate_implementations_for_trait_if_necessary(tcx, trait_id)
}
}

// We need to do a bunch of special handling for default methods.
// We need to modify the def_id and our substs in order to monomorphize
// the function.
Expand All @@ -303,7 +311,7 @@ pub fn trans_fn_ref_with_vtables(
// So, what we need to do is find this substitution and
// compose it with the one we already have.

let impl_id = ty::method(tcx, def_id).container_id;
let impl_id = ty::method(tcx, def_id).container_id();
let method = ty::method(tcx, source_id);
let trait_ref = ty::impl_trait_ref(tcx, impl_id)
.expect("could not find trait_ref for impl with \
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ pub fn trans_method_callee(bcx: @mut Block,
}) => {
match bcx.fcx.param_substs {
Some(substs) => {
ty::populate_implementations_for_trait_if_necessary(
bcx.tcx(),
trait_id);

let vtbl = find_vtable(bcx.tcx(), substs,
p, b);
trans_monomorphized_callee(bcx, callee_id, this, mentry,
Expand Down Expand Up @@ -210,6 +214,8 @@ pub fn trans_static_method_callee(bcx: @mut Block,
callee_id);
let _indenter = indenter();

ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id);

// When we translate a static fn defined in a trait like:
//
// trait<T1...Tn> Trait {
Expand Down Expand Up @@ -575,6 +581,8 @@ fn emit_vtable_methods(bcx: @mut Block,
make a vtable for a type impl!")
};

ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trt_id);

let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
do trait_method_def_ids.map |method_def_id| {
let ident = ty::method(tcx, *method_def_id).ident;
Expand Down
Loading

0 comments on commit 6c37e3b

Please sign in to comment.