Compute a ty::method for methods that appear in impls as well

This commit is contained in:
Niko Matsakis 2013-03-28 14:27:54 -04:00
parent 007abe9352
commit 569596573a
4 changed files with 89 additions and 79 deletions

View file

@ -714,18 +714,19 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
tcx: ty::ctxt) -> ty::method
{
let method_doc = lookup_item(id, cdata.data);
let def_id = item_def_id(method_doc, cdata);
let name = item_name(intr, method_doc);
let bounds = item_ty_param_bounds(method_doc, tcx, cdata,
tag_item_method_tps);
let name = item_name(intr, method_doc);
let def_id = item_def_id(method_doc, cdata);
let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc);
let self_ty = get_self_ty(method_doc);
ty::method {
ident: name,
tps: bounds,
fty: fty,
self_ty: self_ty,
vis: ast::public,
vis: vis,
def_id: def_id
}
}

View file

@ -562,13 +562,25 @@ fn encode_info_for_struct_ctor(ecx: @EncodeContext,
ebml_w.end_tag();
}
fn encode_method_ty_fields(ecx: @EncodeContext,
ebml_w: writer::Encoder,
method_ty: &ty::method)
{
encode_def_id(ebml_w, method_ty.def_id);
encode_name(ecx, ebml_w, method_ty.ident);
encode_ty_type_param_bounds(ebml_w, ecx, method_ty.tps,
tag_item_method_tps);
encode_method_fty(ecx, ebml_w, &method_ty.fty);
encode_visibility(ebml_w, method_ty.vis);
encode_self_type(ebml_w, method_ty.self_ty);
}
fn encode_info_for_method(ecx: @EncodeContext,
ebml_w: writer::Encoder,
impl_path: &[ast_map::path_elt],
should_inline: bool,
parent_id: node_id,
m: @method,
parent_visibility: ast::visibility,
owner_generics: &ast::Generics,
method_generics: &ast::Generics) {
debug!("encode_info_for_method: %d %s %u %u", m.id,
@ -576,7 +588,10 @@ fn encode_info_for_method(ecx: @EncodeContext,
owner_generics.ty_params.len(),
method_generics.ty_params.len());
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(m.id));
let method_def_id = local_def(m.id);
let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id);
encode_method_ty_fields(ecx, ebml_w, method_ty);
match m.self_ty.node {
ast::sty_static => {
@ -592,16 +607,7 @@ fn encode_info_for_method(ecx: @EncodeContext,
encode_type_param_bounds(ebml_w, ecx, &combined_ty_params);
encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id));
encode_name(ecx, ebml_w, m.ident);
encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident));
encode_self_type(ebml_w, m.self_ty.node);
// Combine parent visibility and this visibility.
let visibility = match m.vis {
ast::inherited => parent_visibility,
vis => vis,
};
encode_visibility(ebml_w, visibility);
if len > 0u || should_inline {
(ecx.encode_inlined_item)(
@ -610,6 +616,7 @@ fn encode_info_for_method(ecx: @EncodeContext,
} else {
encode_symbol(ecx, ebml_w, m.id);
}
ebml_w.end_tag();
}
@ -863,17 +870,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
let mut impl_path = vec::append(~[], path);
impl_path += ~[ast_map::path_name(item.ident)];
// If there is a trait reference, treat the methods as always public.
// This is to work around some incorrect behavior in privacy checking:
// when the method belongs to a trait, it should acquire the privacy
// from the trait, not the impl. Forcing the visibility to be public
// makes things sorta work.
let parent_visibility = if opt_trait.is_some() {
ast::public
} else {
item.vis
};
for methods.each |m| {
index.push(entry {val: m.id, pos: ebml_w.writer.tell()});
encode_info_for_method(ecx,
@ -882,7 +878,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
should_inline(m.attrs),
item.id,
*m,
parent_visibility,
generics,
&m.generics);
}
@ -909,11 +904,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
ebml_w.end_tag();
// Now output the method info for each method.
//
// Note: for the moment, the data structures here are *slightly*
// different from those expected by `encode_info_for_method()`,
// but I do plan to refactor this later in this patch to avoid the
// duplication.
for ty::trait_method_def_ids(tcx, local_def(item.id)).eachi |i, &method_def_id| {
assert!(method_def_id.crate == ast::local_crate);
@ -923,9 +913,13 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, method_def_id);
encode_method_ty_fields(ecx, ebml_w, method_ty);
encode_parent_item(ebml_w, local_def(item.id));
encode_name(ecx, ebml_w, method_ty.ident);
let mut trait_path = vec::append(~[], path);
trait_path.push(ast_map::path_name(item.ident));
encode_path(ecx, ebml_w, trait_path, ast_map::path_name(method_ty.ident));
match method_ty.self_ty {
sty_static => {
@ -946,15 +940,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
}
}
encode_ty_type_param_bounds(ebml_w, ecx, method_ty.tps,
tag_item_method_tps);
encode_method_fty(ecx, ebml_w, &method_ty.fty);
encode_visibility(ebml_w, method_ty.vis);
encode_self_type(ebml_w, method_ty.self_ty);
let mut trait_path = vec::append(~[], path);
trait_path.push(ast_map::path_name(item.ident));
encode_path(ecx, ebml_w, trait_path, ast_map::path_name(method_ty.ident));
match ms[i] {
required(_) => {
encode_method_sort(ebml_w, 'r');

View file

@ -315,7 +315,6 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
ty: ty});
}
fn ty_method_of_trait_method(self: &CrateCtxt,
trait_rp: Option<ty::region_variance>,
trait_generics: &ast::Generics,
@ -336,8 +335,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
AbiSet::Rust(),
&m_generics.lifetimes,
m_decl),
// assume public, because this is only invoked on trait methods
self_ty: m_self_ty.node,
// assume public, because this is only invoked on trait methods
vis: ast::public,
def_id: local_def(*m_id)
}
@ -599,7 +598,7 @@ pub fn convert_field(ccx: &CrateCtxt,
}
pub struct ConvertedMethod {
mty: ty::method,
mty: @ty::method,
id: ast::node_id,
span: span,
body_id: ast::node_id
@ -609,13 +608,15 @@ pub fn convert_methods(ccx: &CrateCtxt,
ms: &[@ast::method],
rp: Option<ty::region_variance>,
rcvr_bounds: @~[ty::param_bounds],
rcvr_generics: &ast::Generics)
-> ~[ConvertedMethod] {
rcvr_generics: &ast::Generics,
rcvr_visibility: ast::visibility)
-> ~[ConvertedMethod]
{
let tcx = ccx.tcx;
do vec::map(ms) |m| {
return vec::map(ms, |m| {
let bounds = ty_param_bounds(ccx, &m.generics);
let mty = ty_of_method(ccx, *m, rp, rcvr_generics, &m.generics);
let mty = @ty_of_method(ccx, *m, rp, rcvr_generics,
rcvr_visibility, &m.generics);
let fty = ty::mk_bare_fn(tcx, copy mty.fty);
tcx.tcache.insert(
local_def(m.id),
@ -628,8 +629,34 @@ pub fn convert_methods(ccx: &CrateCtxt,
ty: fty
});
write_ty_to_tcx(tcx, m.id, fty);
tcx.methods.insert(mty.def_id, mty);
ConvertedMethod {mty: mty, id: m.id,
span: m.span, body_id: m.body.node.id}
});
fn ty_of_method(ccx: &CrateCtxt,
m: @ast::method,
rp: Option<ty::region_variance>,
rcvr_generics: &ast::Generics,
rcvr_visibility: ast::visibility,
method_generics: &ast::Generics) -> ty::method
{
let rscope = MethodRscope::new(m.self_ty.node,
rp,
rcvr_generics);
ty::method {
ident: m.ident,
tps: ty_param_bounds(ccx, &m.generics),
fty: astconv::ty_of_bare_fn(ccx,
&rscope,
m.purity,
ast::RustAbi,
&method_generics.lifetimes,
&m.decl),
self_ty: m.self_ty.node,
vis: m.vis.inherit_from(rcvr_visibility),
def_id: local_def(m.id)
}
}
}
@ -665,7 +692,7 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) {
generics,
rp);
}
ast::item_impl(ref generics, trait_ref, selfty, ref ms) => {
ast::item_impl(ref generics, opt_trait_ref, selfty, ref ms) => {
let i_bounds = ty_param_bounds(ccx, generics);
let region_parameterization =
RegionParameterization::from_variance_and_generics(rp, generics);
@ -677,9 +704,20 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) {
region_param: rp,
ty: selfty});
// XXX: Bad copy of `ms` below.
let cms = convert_methods(ccx, *ms, rp, i_bounds, generics);
for trait_ref.each |t| {
// If there is a trait reference, treat the methods as always public.
// This is to work around some incorrect behavior in privacy checking:
// when the method belongs to a trait, it should acquire the privacy
// from the trait, not the impl. Forcing the visibility to be public
// makes things sorta work.
let parent_visibility = if opt_trait_ref.is_some() {
ast::public
} else {
it.vis
};
let cms = convert_methods(ccx, *ms, rp, i_bounds, generics,
parent_visibility);
for opt_trait_ref.each |t| {
check_methods_against_trait(ccx, generics, rp, selfty, *t, cms);
}
}
@ -694,7 +732,8 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) {
let (_, provided_methods) =
split_trait_methods(*trait_methods);
let (bounds, _) = mk_substs(ccx, generics, rp);
let _ = convert_methods(ccx, provided_methods, rp, bounds, generics);
let _ = convert_methods(ccx, provided_methods, rp, bounds, generics,
it.vis);
}
ast::item_struct(struct_def, ref generics) => {
ensure_no_ty_param_bounds(ccx, it.span, generics, "structure");
@ -794,30 +833,6 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) {
ccx.tcx.tcache.insert(local_def(i.id), tpt);
}
pub fn ty_of_method(ccx: &CrateCtxt,
m: @ast::method,
rp: Option<ty::region_variance>,
rcvr_generics: &ast::Generics,
method_generics: &ast::Generics)
-> ty::method {
let rscope = MethodRscope::new(m.self_ty.node,
rp,
rcvr_generics);
ty::method {
ident: m.ident,
tps: ty_param_bounds(ccx, &m.generics),
fty: astconv::ty_of_bare_fn(ccx,
&rscope,
m.purity,
AbiSet::Rust(),
&method_generics.lifetimes,
&m.decl),
self_ty: m.self_ty.node,
vis: m.vis,
def_id: local_def(m.id)
}
}
/*
Instantiates the path for the given trait reference, assuming that
it's bound to a valid trait type. Returns the def_id for the defining

View file

@ -1186,6 +1186,15 @@ pub struct trait_ref {
#[deriving(Eq)]
pub enum visibility { public, private, inherited }
impl visibility {
fn inherit_from(&self, parent_visibility: visibility) -> visibility {
match self {
&inherited => parent_visibility,
&public | &private => *self
}
}
}
#[auto_encode]
#[auto_decode]
#[deriving(Eq)]