Skip to content

Commit

Permalink
Properly track and export information about vtables for impls in meta…
Browse files Browse the repository at this point in the history
…data.

Partially rework how vtables are handled in default method calls.
Closes #7460.
  • Loading branch information
msullivan committed Jul 24, 2013
1 parent 304a5f0 commit 79f8a7f
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 80 deletions.
1 change: 1 addition & 0 deletions src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ pub static tag_misc_info: uint = 0x7f;
pub static tag_misc_info_crate_items: uint = 0x80;

pub static tag_item_method_provided_source: uint = 0x81;
pub static tag_item_impl_vtables: uint = 0x82;

pub struct LinkMeta {
name: @str,
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use metadata::cstore;
use metadata::decoder;
use metadata;
use middle::ty;
use middle::typeck;

use std::vec;
use reader = extra::ebml::reader;
Expand Down Expand Up @@ -216,6 +217,14 @@ pub fn get_impl_trait(tcx: ty::ctxt,
decoder::get_impl_trait(cdata, def.node, tcx)
}

// Given a def_id for an impl, return information about its vtables
pub fn get_impl_vtables(tcx: ty::ctxt,
def: ast::def_id) -> typeck::impl_res {
let cstore = tcx.cstore;
let cdata = cstore::get_crate_data(cstore, def.crate);
decoder::get_impl_vtables(cdata, def.node, tcx)
}

pub fn get_impl_method(cstore: @mut cstore::CStore,
def: ast::def_id,
mname: ast::ident)
Expand Down
18 changes: 18 additions & 0 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ 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;
use middle::typeck;
use middle::astencode::vtable_decoder_helpers;


use std::hash::HashUtil;
use std::int;
Expand Down Expand Up @@ -410,6 +413,21 @@ pub fn get_impl_trait(cdata: cmd,
}
}

pub fn get_impl_vtables(cdata: cmd,
id: ast::node_id,
tcx: ty::ctxt) -> typeck::impl_res
{
let item_doc = lookup_item(id, cdata.data);
let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables);
let mut decoder = reader::Decoder(vtables_doc);

typeck::impl_res {
trait_vtables: decoder.read_vtable_res(tcx, cdata),
self_vtables: decoder.read_vtable_param_res(tcx, cdata)
}
}


pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
name: ast::ident) -> Option<ast::def_id> {
let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
Expand Down
13 changes: 13 additions & 0 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use metadata::decoder;
use metadata::tyencode;
use middle::ty::{node_id_to_type, lookup_item_type};
use middle::ty;
use middle::typeck;
use middle::astencode;
use middle;

use std::hash::HashUtil;
Expand Down Expand Up @@ -162,6 +164,15 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder,
ebml_w.end_tag();
}

fn encode_impl_vtables(ebml_w: &mut writer::Encoder,
ecx: &EncodeContext,
vtables: &typeck::impl_res) {
ebml_w.start_tag(tag_item_impl_vtables);
astencode::encode_vtable_res(ecx, ebml_w, vtables.trait_vtables);
astencode::encode_vtable_param_res(ecx, ebml_w, vtables.self_vtables);
ebml_w.end_tag();
}

// Item info table encoding
fn encode_family(ebml_w: &mut writer::Encoder, c: char) {
ebml_w.start_tag(tag_items_data_item_family);
Expand Down Expand Up @@ -1009,6 +1020,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
let trait_ref = ty::node_id_to_trait_ref(
tcx, ast_trait_ref.ref_id);
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref);
let impl_vtables = ty::lookup_impl_vtables(tcx, def_id);
encode_impl_vtables(ebml_w, ecx, &impl_vtables);
}
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
ebml_w.end_tag();
Expand Down
91 changes: 73 additions & 18 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,13 +250,21 @@ impl<S:serialize::Encoder> def_id_encoder_helpers for S {

trait def_id_decoder_helpers {
fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id;
fn read_def_id_noxcx(&mut self,
cdata: @cstore::crate_metadata) -> ast::def_id;
}

impl<D:serialize::Decoder> def_id_decoder_helpers for D {
fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id {
let did: ast::def_id = Decodable::decode(self);
did.tr(xcx)
}

fn read_def_id_noxcx(&mut self,
cdata: @cstore::crate_metadata) -> ast::def_id {
let did: ast::def_id = Decodable::decode(self);
decoder::translate_def_id(cdata, did)
}
}

// ______________________________________________________________________
Expand Down Expand Up @@ -595,21 +603,28 @@ impl tr for method_origin {
// ______________________________________________________________________
// Encoding and decoding vtable_res

fn encode_vtable_res(ecx: &e::EncodeContext,
pub fn encode_vtable_res(ecx: &e::EncodeContext,
ebml_w: &mut writer::Encoder,
dr: typeck::vtable_res) {
// can't autogenerate this code because automatic code of
// ty::t doesn't work, and there is no way (atm) to have
// hand-written encoding routines combine with auto-generated
// ones. perhaps we should fix this.
do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| {
do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| {
encode_vtable_origin(ecx, ebml_w, vtable_origin)
}
encode_vtable_param_res(ecx, ebml_w, *param_tables);
}
}

fn encode_vtable_origin(ecx: &e::EncodeContext,
pub fn encode_vtable_param_res(ecx: &e::EncodeContext,
ebml_w: &mut writer::Encoder,
param_tables: typeck::vtable_param_res) {
do ebml_w.emit_from_vec(*param_tables) |ebml_w, vtable_origin| {
encode_vtable_origin(ecx, ebml_w, vtable_origin)
}
}


pub fn encode_vtable_origin(ecx: &e::EncodeContext,
ebml_w: &mut writer::Encoder,
vtable_origin: &typeck::vtable_origin) {
do ebml_w.emit_enum("vtable_origin") |ebml_w| {
Expand Down Expand Up @@ -648,22 +663,35 @@ fn encode_vtable_origin(ecx: &e::EncodeContext,
}
}

trait vtable_decoder_helpers {
fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext)
pub trait vtable_decoder_helpers {
fn read_vtable_res(&mut self,
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
-> typeck::vtable_res;
fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
fn read_vtable_param_res(&mut self,
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
-> typeck::vtable_param_res;
fn read_vtable_origin(&mut self,
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
-> typeck::vtable_origin;
}

impl vtable_decoder_helpers for reader::Decoder {
fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext)
fn read_vtable_res(&mut self,
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
-> typeck::vtable_res {
@self.read_to_vec(|this|
@this.read_to_vec(|this|
this.read_vtable_origin(xcx)))
this.read_vtable_param_res(tcx, cdata))
}

fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
fn read_vtable_param_res(&mut self,
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
-> typeck::vtable_param_res {
@self.read_to_vec(|this|
this.read_vtable_origin(tcx, cdata))
}

fn read_vtable_origin(&mut self,
tcx: ty::ctxt, cdata: @cstore::crate_metadata)
-> typeck::vtable_origin {
do self.read_enum("vtable_origin") |this| {
do this.read_enum_variant(["vtable_static",
Expand All @@ -674,13 +702,13 @@ impl vtable_decoder_helpers for reader::Decoder {
0 => {
typeck::vtable_static(
do this.read_enum_variant_arg(0u) |this| {
this.read_def_id(xcx)
this.read_def_id_noxcx(cdata)
},
do this.read_enum_variant_arg(1u) |this| {
this.read_tys(xcx)
this.read_tys_noxcx(tcx, cdata)
},
do this.read_enum_variant_arg(2u) |this| {
this.read_vtable_res(xcx)
this.read_vtable_res(tcx, cdata)
}
)
}
Expand All @@ -697,7 +725,7 @@ impl vtable_decoder_helpers for reader::Decoder {
2 => {
typeck::vtable_self(
do this.read_enum_variant_arg(0u) |this| {
this.read_def_id(xcx)
this.read_def_id_noxcx(cdata)
}
)
}
Expand Down Expand Up @@ -995,9 +1023,35 @@ trait ebml_decoder_decoder_helpers {
source: DefIdSource,
did: ast::def_id)
-> ast::def_id;

// Versions of the type reading functions that don't need the full
// ExtendedDecodeContext.
fn read_ty_noxcx(&mut self,
tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t;
fn read_tys_noxcx(&mut self,
tcx: ty::ctxt,
cdata: @cstore::crate_metadata) -> ~[ty::t];
}

impl ebml_decoder_decoder_helpers for reader::Decoder {
fn read_ty_noxcx(&mut self,
tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t {
do self.read_opaque |_, doc| {
tydecode::parse_ty_data(
*doc.data,
cdata.cnum,
doc.start,
tcx,
|_, id| decoder::translate_def_id(cdata, id))
}
}

fn read_tys_noxcx(&mut self,
tcx: ty::ctxt,
cdata: @cstore::crate_metadata) -> ~[ty::t] {
self.read_to_vec(|this| this.read_ty_noxcx(tcx, cdata) )
}

fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t {
// Note: regions types embed local node ids. In principle, we
// should translate these node ids into the new decode
Expand Down Expand Up @@ -1160,8 +1214,9 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
val_dsr.read_method_map_entry(xcx));
}
c::tag_table_vtable_map => {
dcx.maps.vtable_map.insert(id,
val_dsr.read_vtable_res(xcx));
dcx.maps.vtable_map.insert(
id,
val_dsr.read_vtable_res(xcx.dcx.tcx, xcx.dcx.cdata));
}
c::tag_table_adjustments => {
let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr);
Expand Down
58 changes: 18 additions & 40 deletions src/librustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,42 +193,27 @@ pub fn trans_fn_ref_with_vtables_to_callee(
type_params, vtables))}
}

fn get_impl_resolutions(bcx: @mut Block,
impl_id: ast::def_id)
-> typeck::vtable_res {
if impl_id.crate == ast::local_crate {
bcx.ccx().maps.vtable_map.get_copy(&impl_id.node)
} else {
// XXX: This is a temporary hack to work around not properly
// exporting information about resolutions for impls.
// This doesn't actually work if the trait has param bounds,
// but it does allow us to survive the case when it does not.
let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get();
@vec::from_elem(trait_ref.substs.tps.len(), @~[])
}
}

fn resolve_default_method_vtables(bcx: @mut Block,
impl_id: ast::def_id,
method: &ty::Method,
substs: &ty::substs,
impl_vtables: Option<typeck::vtable_res>)
-> typeck::vtable_res {
-> (typeck::vtable_res, typeck::vtable_param_res) {

// Get the vtables that the impl implements the trait at
let trait_vtables = get_impl_resolutions(bcx, impl_id);
let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id);

// Build up a param_substs that we are going to resolve the
// trait_vtables under.
let param_substs = Some(@param_substs {
tys: substs.tps.clone(),
self_ty: substs.self_ty,
vtables: impl_vtables,
self_vtable: None
self_vtables: None
});

let trait_vtables_fixed = resolve_vtables_under_param_substs(
bcx.tcx(), param_substs, trait_vtables);
bcx.tcx(), param_substs, impl_res.trait_vtables);

// Now we pull any vtables for parameters on the actual method.
let num_method_vtables = method.generics.type_param_defs.len();
Expand All @@ -241,7 +226,12 @@ fn resolve_default_method_vtables(bcx: @mut Block,
None => vec::from_elem(num_method_vtables, @~[])
};

@(*trait_vtables_fixed + method_vtables)
let param_vtables = @(*trait_vtables_fixed + method_vtables);

let self_vtables = resolve_param_vtables_under_param_substs(
bcx.tcx(), param_substs, impl_res.self_vtables);

(param_vtables, self_vtables)
}


Expand Down Expand Up @@ -296,7 +286,7 @@ pub fn trans_fn_ref_with_vtables(
// 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.
let (is_default, def_id, substs, self_vtable, vtables) =
let (is_default, def_id, substs, self_vtables, vtables) =
match ty::provided_source(tcx, def_id) {
None => (false, def_id, substs, None, vtables),
Some(source_id) => {
Expand All @@ -319,20 +309,6 @@ pub fn trans_fn_ref_with_vtables(
.expect("could not find trait_ref for impl with \
default methods");

// Get all of the type params for the receiver
let param_defs = method.generics.type_param_defs;
let receiver_substs =
type_params.initn(param_defs.len()).to_owned();
let receiver_vtables = match vtables {
None => @~[],
Some(call_vtables) => {
@call_vtables.initn(param_defs.len()).to_owned()
}
};

let self_vtable =
typeck::vtable_static(impl_id, receiver_substs,
receiver_vtables);
// Compute the first substitution
let first_subst = make_substs_for_receiver_types(
tcx, impl_id, trait_ref, method);
Expand All @@ -341,20 +317,22 @@ pub fn trans_fn_ref_with_vtables(
let new_substs = first_subst.subst(tcx, &substs);


let vtables =
let (param_vtables, self_vtables) =
resolve_default_method_vtables(bcx, impl_id,
method, &substs, vtables);

debug!("trans_fn_with_vtables - default method: \
substs = %s, trait_subst = %s, \
first_subst = %s, new_subst = %s, \
self_vtable = %s, vtables = %s",
vtables = %s, \
self_vtable = %s, param_vtables = %s",
substs.repr(tcx), trait_ref.substs.repr(tcx),
first_subst.repr(tcx), new_substs.repr(tcx),
self_vtable.repr(tcx), vtables.repr(tcx));
vtables.repr(tcx),
self_vtables.repr(tcx), param_vtables.repr(tcx));

(true, source_id,
new_substs, Some(self_vtable), Some(vtables))
new_substs, Some(self_vtables), Some(param_vtables))
}
};

Expand Down Expand Up @@ -400,7 +378,7 @@ pub fn trans_fn_ref_with_vtables(

let (val, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs,
vtables, self_vtable,
vtables, self_vtables,
Some(ref_id));
let mut val = val;
if must_cast && ref_id != 0 {
Expand Down
Loading

0 comments on commit 79f8a7f

Please sign in to comment.