diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e3da15d181b76..707b6fbe5c971 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -7,34 +7,6 @@ use std::serialization::{Serializable, use codemap::{span, filename}; use parse::token; -#[cfg(stage0)] -impl span: Serializable { - /* Note #1972 -- spans are serialized but not deserialized */ - fn serialize(&self, _s: &S) { } -} - -#[cfg(stage0)] -impl span: Deserializable { - static fn deserialize(_d: &D) -> span { - ast_util::dummy_sp() - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -impl span: Serializable { - /* Note #1972 -- spans are serialized but not deserialized */ - fn serialize(&self, _s: &S) { } -} - -#[cfg(stage1)] -#[cfg(stage2)] -impl span: Deserializable { - static fn deserialize(_d: &D) -> span { - ast_util::dummy_sp() - } -} - #[auto_serialize] #[auto_deserialize] type spanned = {node: T, span: span}; @@ -168,7 +140,7 @@ type ty_param = {ident: ident, id: node_id, bounds: @~[ty_param_bound]}; enum def { def_fn(def_id, purity), def_static_method(/* method */ def_id, - /* trait */ def_id, + /* trait */ Option, purity), def_self(node_id), def_mod(def_id), diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 0cb8b425c942e..69a80d0bac13a 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -1,4 +1,8 @@ use dvec::DVec; +use std::serialization::{Serializable, + Deserializable, + Serializer, + Deserializer}; export filename; export filemap; @@ -178,6 +182,34 @@ impl span : cmp::Eq { pure fn ne(other: &span) -> bool { !self.eq(other) } } +#[cfg(stage0)] +impl span: Serializable { + /* Note #1972 -- spans are serialized but not deserialized */ + fn serialize(&self, _s: &S) { } +} + +#[cfg(stage0)] +impl span: Deserializable { + static fn deserialize(_d: &D) -> span { + ast_util::dummy_sp() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +impl span: Serializable { + /* Note #1972 -- spans are serialized but not deserialized */ + fn serialize(&self, _s: &S) { } +} + +#[cfg(stage1)] +#[cfg(stage2)] +impl span: Deserializable { + static fn deserialize(_d: &D) -> span { + ast_util::dummy_sp() + } +} + fn span_to_str_no_adj(sp: span, cm: CodeMap) -> ~str { let lo = lookup_char_pos(cm, sp.lo); let hi = lookup_char_pos(cm, sp.hi); diff --git a/src/rustc/metadata/common.rs b/src/rustc/metadata/common.rs index 972d48a613531..06f1dfdab1aa5 100644 --- a/src/rustc/metadata/common.rs +++ b/src/rustc/metadata/common.rs @@ -126,5 +126,7 @@ enum astencode_tag { // Reserves 0x50 -- 0x6f const tag_item_trait_method_sort: uint = 0x70; +const tag_item_impl_type_basename: uint = 0x71; + type link_meta = {name: ~str, vers: ~str, extras_hash: ~str}; diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs index d9fccb16de02e..141613c2240d8 100644 --- a/src/rustc/metadata/csearch.rs +++ b/src/rustc/metadata/csearch.rs @@ -25,6 +25,8 @@ export get_impls_for_mod; export get_trait_methods; export get_provided_trait_methods; export get_method_names_if_trait; +export get_type_name_if_impl; +export get_static_methods_if_impl; export get_item_attrs; export each_path; export get_type; @@ -33,12 +35,19 @@ export get_impl_method; export get_item_path; export maybe_get_item_ast, found_ast, found, found_parent, not_found; export ProvidedTraitMethodInfo; +export StaticMethodInfo; struct ProvidedTraitMethodInfo { ty: ty::method, def_id: ast::def_id } +struct StaticMethodInfo { + ident: ast::ident, + def_id: ast::def_id, + purity: ast::purity +} + fn get_symbol(cstore: cstore::CStore, def: ast::def_id) -> ~str { let cdata = cstore::get_crate_data(cstore, def.crate).data; return decoder::get_symbol(cdata, def.node); @@ -120,6 +129,18 @@ fn get_method_names_if_trait(cstore: cstore::CStore, def: ast::def_id) return decoder::get_method_names_if_trait(cstore.intr, cdata, def.node); } +fn get_type_name_if_impl(cstore: cstore::CStore, def: ast::def_id) -> + Option { + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_type_name_if_impl(cstore.intr, cdata, def.node) +} + +fn get_static_methods_if_impl(cstore: cstore::CStore, def: ast::def_id) -> + Option<~[StaticMethodInfo]> { + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_static_methods_if_impl(cstore.intr, cdata, def.node) +} + fn get_item_attrs(cstore: cstore::CStore, def_id: ast::def_id, f: fn(~[@ast::meta_item])) { diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index f0911bd1aa27a..ea892191fe02b 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -19,7 +19,7 @@ use syntax::diagnostic::span_handler; use common::*; use syntax::parse::token::ident_interner; use hash::{Hash, HashUtil}; -use csearch::ProvidedTraitMethodInfo; +use csearch::{ProvidedTraitMethodInfo, StaticMethodInfo}; export class_dtor; export get_class_fields; @@ -31,6 +31,7 @@ export get_type_param_count; export get_impl_traits; export get_class_method; export get_impl_method; +export get_static_methods_if_impl; export lookup_def; export resolve_path; export get_crate_attributes; @@ -43,6 +44,7 @@ export get_impls_for_mod; export get_trait_methods; export get_provided_trait_methods; export get_method_names_if_trait; +export get_type_name_if_impl; export get_item_attrs; export get_crate_module_paths; export def_like; @@ -185,6 +187,12 @@ fn item_parent_item(d: ebml::Doc) -> Option { None } +fn translated_parent_item_opt(cnum: ast::crate_num, d: ebml::Doc) -> + Option { + let trait_did_opt = item_parent_item(d); + trait_did_opt.map(|trait_did| {crate: cnum, node: trait_did.node}) +} + fn item_reqd_and_translated_parent_item(cnum: ast::crate_num, d: ebml::Doc) -> ast::def_id { let trait_did = item_parent_item(d).expect(~"item without parent"); @@ -321,16 +329,16 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num) PureFn => dl_def(ast::def_fn(did, ast::pure_fn)), ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)), UnsafeStaticMethod => { - let trait_did = item_reqd_and_translated_parent_item(cnum, item); - dl_def(ast::def_static_method(did, trait_did, ast::unsafe_fn)) + let trait_did_opt = translated_parent_item_opt(cnum, item); + dl_def(ast::def_static_method(did, trait_did_opt, ast::unsafe_fn)) } StaticMethod => { - let trait_did = item_reqd_and_translated_parent_item(cnum, item); - dl_def(ast::def_static_method(did, trait_did, ast::impure_fn)) + let trait_did_opt = translated_parent_item_opt(cnum, item); + dl_def(ast::def_static_method(did, trait_did_opt, ast::impure_fn)) } PureStaticMethod => { - let trait_did = item_reqd_and_translated_parent_item(cnum, item); - dl_def(ast::def_static_method(did, trait_did, ast::pure_fn)) + let trait_did_opt = translated_parent_item_opt(cnum, item); + dl_def(ast::def_static_method(did, trait_did_opt, ast::pure_fn)) } Type | ForeignType => dl_def(ast::def_ty(did)), Mod => dl_def(ast::def_mod(did)), @@ -784,6 +792,67 @@ fn get_method_names_if_trait(intr: @ident_interner, cdata: cmd, return Some(resulting_methods); } +fn get_type_name_if_impl(intr: @ident_interner, + cdata: cmd, + node_id: ast::node_id) -> Option { + let item = lookup_item(node_id, cdata.data); + if item_family(item) != Impl { + return None; + } + + for ebml::tagged_docs(item, tag_item_impl_type_basename) |doc| { + return Some(intr.intern(@str::from_bytes(ebml::doc_data(doc)))); + } + + return None; +} + +fn get_static_methods_if_impl(intr: @ident_interner, + cdata: cmd, + node_id: ast::node_id) -> + Option<~[StaticMethodInfo]> { + let item = lookup_item(node_id, cdata.data); + if item_family(item) != Impl { + return None; + } + + // If this impl has a trait ref, don't consider it. + for ebml::tagged_docs(item, tag_impl_trait) |_doc| { + return None; + } + + let impl_method_ids = DVec(); + for ebml::tagged_docs(item, tag_item_impl_method) |impl_method_doc| { + impl_method_ids.push(parse_def_id(ebml::doc_data(impl_method_doc))); + } + + let static_impl_methods = DVec(); + for impl_method_ids.each |impl_method_id| { + let impl_method_doc = lookup_item(impl_method_id.node, cdata.data); + let family = item_family(impl_method_doc); + match family { + StaticMethod | UnsafeStaticMethod | PureStaticMethod => { + let purity; + match item_family(impl_method_doc) { + StaticMethod => purity = ast::impure_fn, + UnsafeStaticMethod => purity = ast::unsafe_fn, + PureStaticMethod => purity = ast::pure_fn, + _ => fail + } + + static_impl_methods.push(StaticMethodInfo { + ident: item_name(intr, impl_method_doc), + def_id: item_def_id(impl_method_doc, cdata), + purity: purity + }); + } + _ => {} + } + } + + return Some(dvec::unwrap(move static_impl_methods)); +} + fn get_item_attrs(cdata: cmd, node_id: ast::node_id, f: fn(~[@ast::meta_item])) { diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index 0b25f0670b427..68e139f6f9bd7 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -90,6 +90,12 @@ fn encode_name(ecx: @encode_ctxt, ebml_w: ebml::Serializer, name: ident) { ebml_w.wr_tagged_str(tag_paths_data_name, ecx.tcx.sess.str_of(name)); } +fn encode_impl_type_basename(ecx: @encode_ctxt, ebml_w: ebml::Serializer, + name: ident) { + ebml_w.wr_tagged_str(tag_item_impl_type_basename, + ecx.tcx.sess.str_of(name)); +} + fn encode_def_id(ebml_w: ebml::Serializer, id: def_id) { ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); } @@ -484,7 +490,12 @@ fn encode_info_for_method(ecx: @encode_ctxt, ebml_w: ebml::Serializer, ecx.tcx.sess.str_of(m.ident), all_tps.len()); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(m.id)); - encode_family(ebml_w, purity_fn_family(m.purity)); + match m.self_ty.node { + ast::sty_static => { + encode_family(ebml_w, purity_static_method_family(m.purity)); + } + _ => encode_family(ebml_w, purity_fn_family(m.purity)) + } encode_type_param_bounds(ebml_w, ecx, all_tps); encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); encode_name(ecx, ebml_w, m.ident); @@ -701,7 +712,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer, encode_index(ebml_w, bkts, write_int); ebml_w.end_tag(); } - item_impl(tps, opt_trait, _, methods) => { + item_impl(tps, opt_trait, ty, methods) => { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); @@ -711,6 +722,13 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer, encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); + match ty.node { + ast::ty_path(path, _) if path.idents.len() == 1 => { + encode_impl_type_basename(ecx, ebml_w, + ast_util::path_to_ident(path)); + } + _ => {} + } for methods.each |m| { ebml_w.start_tag(tag_item_impl_method); ebml_w.writer.write(str::to_bytes(def_to_str(local_def(m.id)))); diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index b47e6d3b151c3..d264188e65d34 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -326,8 +326,10 @@ impl ast::def: tr { fn tr(xcx: extended_decode_ctxt) -> ast::def { match self { ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) } - ast::def_static_method(did, did2, p) => { - ast::def_static_method(did.tr(xcx), did2.tr(xcx), p) + ast::def_static_method(did, did2_opt, p) => { + ast::def_static_method(did.tr(xcx), + did2_opt.map(|did2| did2.tr(xcx)), + p) } ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) } ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) } diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index f522cca7a9957..33b56d7fabe0d 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -1,5 +1,6 @@ use driver::session::Session; use metadata::csearch::{each_path, get_method_names_if_trait}; +use metadata::csearch::{get_static_methods_if_impl, get_type_name_if_impl}; use metadata::cstore::find_use_stmt_cnum; use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; use middle::lang_items::LanguageItems; @@ -1082,7 +1083,6 @@ impl Resolver { fn build_reduced_graph_for_item(item: @item, parent: ReducedGraphParent, &&visitor: vt) { - let ident = item.ident; let sp = item.span; let legacy = match parent { @@ -1276,7 +1276,7 @@ impl Resolver { self.add_child(ident, new_parent, ForbidDuplicateValues, ty_m.span); let def = def_static_method(local_def(ty_m.id), - local_def(item.id), + Some(local_def(item.id)), ty_m.purity); (*method_name_bindings).define_value (Public, def, ty_m.span); @@ -1734,27 +1734,105 @@ impl Resolver { current_module = (*child_name_bindings).get_module(); } - // Add the new child item. - let (child_name_bindings, new_parent) = - self.add_child(final_ident, - ModuleReducedGraphParent(current_module), - OverwriteDuplicates, - dummy_sp()); - match path_entry.def_like { dl_def(def) => { + // Add the new child item. + let (child_name_bindings, new_parent) = + self.add_child(final_ident, + ModuleReducedGraphParent( + current_module), + OverwriteDuplicates, + dummy_sp()); + self.handle_external_def(def, modules, child_name_bindings, self.session.str_of(final_ident), final_ident, new_parent); } - dl_impl(_) => { + dl_impl(def) => { // We only process static methods of impls here. debug!("(building reduced graph for external crate) \ processing impl %s", final_ident_str); - // FIXME (#3786): Cross-crate static methods in anonymous - // traits. + match get_type_name_if_impl(self.session.cstore, def) { + None => {} + Some(final_ident) => { + let static_methods_opt = + get_static_methods_if_impl( + self.session.cstore, def); + match static_methods_opt { + Some(static_methods) if + static_methods.len() >= 1 => { + debug!("(building reduced graph for \ + external crate) processing \ + static methods for type name %s", + self.session.str_of(final_ident)); + + let (child_name_bindings, new_parent) = + self.add_child(final_ident, + ModuleReducedGraphParent( + current_module), + OverwriteDuplicates, + dummy_sp()); + + // Process the static methods. First, + // create the module. + let type_module; + match copy child_name_bindings.type_def { + Some(TypeNsDef { + module_def: Some(copy module_def), + _ + }) => { + // We already have a module. This + // is OK. + type_module = module_def; + } + Some(_) | None => { + let parent_link = + self.get_parent_link( + new_parent, final_ident); + child_name_bindings.define_module( + Public, + parent_link, + Some(def), + false, + dummy_sp()); + type_module = + child_name_bindings. + get_module(); + } + } + + // Add each static method to the module. + let new_parent = ModuleReducedGraphParent( + type_module); + for static_methods.each + |static_method_info| { + let ident = static_method_info.ident; + debug!("(building reduced graph for \ + external crate) creating \ + static method '%s'", + self.session.str_of(ident)); + + let (method_name_bindings, _) = + self.add_child( + ident, + new_parent, + OverwriteDuplicates, + dummy_sp()); + let def = def_fn( + static_method_info.def_id, + static_method_info.purity); + method_name_bindings.define_value( + Public, def, dummy_sp()); + } + } + + // Otherwise, do nothing. + Some(_) | None => {} + } + } + } } dl_field => { debug!("(building reduced graph for external crate) \ @@ -1770,7 +1848,6 @@ impl Resolver { module_path: @DVec, subclass: @ImportDirectiveSubclass, span: span) { - let directive = @ImportDirective(privacy, module_path, subclass, span); module_.imports.push(directive); @@ -2453,7 +2530,6 @@ impl Resolver { xray: XrayFlag, span: span) -> ResolveResult<@Module> { - let mut search_module = module_; let mut index = index; let module_path_len = (*module_path).len(); @@ -2648,7 +2724,6 @@ impl Resolver { fn resolve_module_in_lexical_scope(module_: @Module, name: ident) -> ResolveResult<@Module> { - match self.resolve_item_in_lexical_scope(module_, name, TypeNS) { Success(target) => { match target.bindings.type_def { @@ -4035,9 +4110,10 @@ impl Resolver { match self.resolve_path(path, TypeNS, true, visitor) { Some(def) => { debug!("(resolving type) resolved `%s` to \ - type", + type %?", self.session.str_of( - path.idents.last())); + path.idents.last()), + def); result_def = Some(def); } None => { diff --git a/src/rustc/middle/trans/callee.rs b/src/rustc/middle/trans/callee.rs index 133f4647e683e..175381a7bd1ee 100644 --- a/src/rustc/middle/trans/callee.rs +++ b/src/rustc/middle/trans/callee.rs @@ -75,10 +75,10 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee { fn trans_def(bcx: block, def: ast::def, ref_expr: @ast::expr) -> Callee { match def { - ast::def_fn(did, _) => { + ast::def_fn(did, _) | ast::def_static_method(did, None, _) => { fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id)) } - ast::def_static_method(impl_did, trait_did, _) => { + ast::def_static_method(impl_did, Some(trait_did), _) => { fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did, trait_did, ref_expr.id)) diff --git a/src/rustc/middle/trans/expr.rs b/src/rustc/middle/trans/expr.rs index 08abe986be6ff..30bea1376c000 100644 --- a/src/rustc/middle/trans/expr.rs +++ b/src/rustc/middle/trans/expr.rs @@ -637,11 +637,11 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, }; match def { - ast::def_fn(did, _) => { + ast::def_fn(did, _) | ast::def_static_method(did, None, _) => { let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id); return fn_data_to_datum(bcx, did, fn_data, lldest); } - ast::def_static_method(impl_did, trait_did, _) => { + ast::def_static_method(impl_did, Some(trait_did), _) => { let fn_data = meth::trans_static_method_callee(bcx, impl_did, trait_did, ref_expr.id); diff --git a/src/test/auxiliary/anon_trait_static_method_lib.rs b/src/test/auxiliary/anon_trait_static_method_lib.rs new file mode 100644 index 0000000000000..ec9398dea15ec --- /dev/null +++ b/src/test/auxiliary/anon_trait_static_method_lib.rs @@ -0,0 +1,10 @@ +pub struct Foo { + x: int +} + +pub impl Foo { + static fn new() -> Foo { + Foo { x: 3 } + } +} + diff --git a/src/test/run-pass/anon_trait_static_method_exe.rs b/src/test/run-pass/anon_trait_static_method_exe.rs new file mode 100644 index 0000000000000..052f95ed3b544 --- /dev/null +++ b/src/test/run-pass/anon_trait_static_method_exe.rs @@ -0,0 +1,13 @@ +// xfail-fast - check-fast doesn't understand aux-build +// aux-build:anon_trait_static_method_lib.rs + +extern mod anon_trait_static_method_lib; +use anon_trait_static_method_lib::Foo; + +fn main() { + let x = Foo::new(); + io::println(x.x.to_str()); +} + + +