From 569596573a2f90d52c7f7610d8c7c637dc587f0a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 28 Mar 2013 14:27:54 -0400 Subject: [PATCH] Compute a ty::method for methods that appear in impls as well --- src/librustc/metadata/decoder.rs | 7 ++- src/librustc/metadata/encoder.rs | 63 ++++++++----------- src/librustc/middle/typeck/collect.rs | 89 ++++++++++++++++----------- src/libsyntax/ast.rs | 9 +++ 4 files changed, 89 insertions(+), 79 deletions(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 800df628bc2..598539609e9 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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 } } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 61501d83083..2e3008a0cdc 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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'); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index d89d1c407d7..3ac3766e89d 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -315,7 +315,6 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, ty: ty}); } - fn ty_method_of_trait_method(self: &CrateCtxt, trait_rp: Option, 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, 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, + 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, - 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 diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 31dc476cbe4..4a0e58b09c8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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)]