]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Implement intra-crate static methods on anonymous trait implementations. r...
authorPatrick Walton <pcwalton@mimiga.net>
Thu, 18 Oct 2012 20:29:34 +0000 (13:29 -0700)
committerPatrick Walton <pcwalton@mimiga.net>
Thu, 18 Oct 2012 21:29:18 +0000 (14:29 -0700)
12 files changed:
src/libsyntax/ast.rs
src/libsyntax/codemap.rs
src/rustc/metadata/common.rs
src/rustc/metadata/csearch.rs
src/rustc/metadata/decoder.rs
src/rustc/metadata/encoder.rs
src/rustc/middle/astencode.rs
src/rustc/middle/resolve.rs
src/rustc/middle/trans/callee.rs
src/rustc/middle/trans/expr.rs
src/test/auxiliary/anon_trait_static_method_lib.rs [new file with mode: 0644]
src/test/run-pass/anon_trait_static_method_exe.rs [new file with mode: 0644]

index 454a3166898b3f82c763f9dc0b810b3fa6d13777..f494d5648168579148ac029542a1ddf061705f86 100644 (file)
@@ -7,34 +7,6 @@
 use codemap::{span, filename};
 use parse::token;
 
-#[cfg(stage0)]
-impl span: Serializable {
-    /* Note #1972 -- spans are serialized but not deserialized */
-    fn serialize<S: Serializer>(&self, _s: &S) { }
-}
-
-#[cfg(stage0)]
-impl span: Deserializable {
-    static fn deserialize<D: Deserializer>(_d: &D) -> span {
-        ast_util::dummy_sp()
-    }
-}
-
-#[cfg(stage1)]
-#[cfg(stage2)]
-impl<S: Serializer> span: Serializable<S> {
-    /* Note #1972 -- spans are serialized but not deserialized */
-    fn serialize(&self, _s: &S) { }
-}
-
-#[cfg(stage1)]
-#[cfg(stage2)]
-impl<D: Deserializer> span: Deserializable<D> {
-    static fn deserialize(_d: &D) -> span {
-        ast_util::dummy_sp()
-    }
-}
-
 #[auto_serialize]
 #[auto_deserialize]
 type spanned<T> = {node: T, span: span};
@@ -168,7 +140,7 @@ enum ty_param_bound {
 enum def {
     def_fn(def_id, purity),
     def_static_method(/* method */ def_id,
-                      /* trait */  def_id,
+                      /* trait */  Option<def_id>,
                       purity),
     def_self(node_id),
     def_mod(def_id),
index 0cb8b425c942e0305bc449f1849e9adc8e6b14ac..69a80d0bac13a628d609a097357dd3a58f1503f6 100644 (file)
@@ -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<S: Serializer>(&self, _s: &S) { }
+}
+
+#[cfg(stage0)]
+impl span: Deserializable {
+    static fn deserialize<D: Deserializer>(_d: &D) -> span {
+        ast_util::dummy_sp()
+    }
+}
+
+#[cfg(stage1)]
+#[cfg(stage2)]
+impl<S: Serializer> span: Serializable<S> {
+    /* Note #1972 -- spans are serialized but not deserialized */
+    fn serialize(&self, _s: &S) { }
+}
+
+#[cfg(stage1)]
+#[cfg(stage2)]
+impl<D: Deserializer> span: Deserializable<D> {
+    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);
index 972d48a6135313c1f949dfc2efa98b5b4c2f0fd7..06f1dfdab1aa5b1fe9c1a51057d7c18cf38f8e06 100644 (file)
@@ -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};
 
index d9fccb16de02e377975d8e8f2c0bd87bdc7e7522..141613c2240d896dbe466c9dd4dea028abf99a5e 100644 (file)
@@ -25,6 +25,8 @@
 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;
 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<ast::ident> {
+    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])) {
index 1656efbd9668430bdd675309ce0db5fa19c629d0..4e30132b1a73fd342ae214d9cc939e33a43ae8d3 100644 (file)
@@ -19,7 +19,7 @@
 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_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_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<ast::def_id> {
     None
 }
 
+fn translated_parent_item_opt(cnum: ast::crate_num, d: ebml::Doc) ->
+        Option<ast::def_id> {
+    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)),
@@ -783,6 +791,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<ast::ident> {
+    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])) {
index 1579705dd0ecb55f1bff27d0647d819526c5e458..a1d85a63ee1487050902840528177e46e822ea31 100644 (file)
@@ -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 add_to_index_(item: @item, 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 add_to_index_(item: @item, 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))));
index b47e6d3b151c33fd6fe69ab5cfe7b3768ddc154d..d264188e65d34168e3d0b08a92cb34f69f7cabc4 100644 (file)
@@ -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)) }
index f522cca7a9957ec5f712eb1bbae4ae4ecf7ec458..33b56d7fabe0d0de00d3912a24bfceaf550134d4 100644 (file)
@@ -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 @@ fn get_parent_link(parent: ReducedGraphParent,
     fn build_reduced_graph_for_item(item: @item,
                                     parent: ReducedGraphParent,
                                     &&visitor: vt<ReducedGraphParent>) {
-
         let ident = item.ident;
         let sp = item.span;
         let legacy = match parent {
@@ -1276,7 +1276,7 @@ fn build_reduced_graph_for_item(item: @item,
                             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 @@ fn build_reduced_graph_for_external_crate(root: @Module) {
                 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 @@ fn build_import_directive(privacy: Privacy,
                               module_path: @DVec<ident>,
                               subclass: @ImportDirectiveSubclass,
                               span: span) {
-
         let directive = @ImportDirective(privacy, module_path,
                                          subclass, span);
         module_.imports.push(directive);
@@ -2453,7 +2530,6 @@ fn resolve_module_path_from_root(module_: @Module,
                                      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 @@ fn resolve_item_in_lexical_scope(module_: @Module,
 
     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 @@ fn resolve_type(ty: @Ty, visitor: ResolveVisitor) {
                         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 => {
index 133f4647e683ec735891c4fde0ebc338d056728a..175381a7bd1eedc9e370d43c2cedfbecb8ffa66e 100644 (file)
@@ -75,10 +75,10 @@ fn fn_callee(bcx: block, fd: FnData) -> 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))
index 08abe986be6ff8da4a17c3a131335dbd9ed731fb..30bea1376c000212a849b1dbac6431cf29d8cc74 100644 (file)
@@ -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 (file)
index 0000000..ec9398d
--- /dev/null
@@ -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 (file)
index 0000000..052f95e
--- /dev/null
@@ -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());
+}
+
+
+