about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTom Lee <github@tomlee.co>2013-06-01 02:54:39 -0700
committerTom Lee <github@tomlee.co>2013-06-01 04:14:58 -0700
commitf6fa5b91e25fb24397d1e2eaf26e476b4041c65c (patch)
treeafa7b0e3aba21d0e78418834193a25d58adb7214
parent2bf053c0a349a5968820780314c942ef4555b47e (diff)
downloadrust-f6fa5b91e25fb24397d1e2eaf26e476b4041c65c.tar.gz
rust-f6fa5b91e25fb24397d1e2eaf26e476b4041c65c.zip
Reexport static methods on structs & enums.
-rw-r--r--src/librustc/metadata/encoder.rs100
-rw-r--r--src/librustc/middle/ty.rs19
-rw-r--r--src/librustc/middle/typeck/coherence.rs5
-rw-r--r--src/test/auxiliary/reexported_static_methods.rs (renamed from src/test/auxiliary/mod_trait_with_static_methods_lib.rs)22
-rw-r--r--src/test/run-pass/reexported-static-methods-cross-crate.rs (renamed from src/test/run-pass/trait_with_static_methods_cross_crate.rs)12
5 files changed, 123 insertions, 35 deletions
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index a488d39d187..eb9d0d0f937 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -374,50 +374,90 @@ fn encode_path(ecx: @EncodeContext,
 fn encode_reexported_static_method(ecx: @EncodeContext,
                                    ebml_w: &mut writer::Encoder,
                                    exp: &middle::resolve::Export2,
-                                   m: @ty::Method) {
-    debug!("(encode static trait method) reexport '%s::%s'",
-            *exp.name, *ecx.tcx.sess.str_of(m.ident));
+                                   method_def_id: def_id,
+                                   method_ident: ident) {
+    debug!("(encode reexported static method) %s::%s",
+            *exp.name, *ecx.tcx.sess.str_of(method_ident));
     ebml_w.start_tag(tag_items_data_item_reexport);
     ebml_w.start_tag(tag_items_data_item_reexport_def_id);
-    ebml_w.wr_str(def_to_str(m.def_id));
+    ebml_w.wr_str(def_to_str(method_def_id));
     ebml_w.end_tag();
     ebml_w.start_tag(tag_items_data_item_reexport_name);
-    ebml_w.wr_str(*exp.name + "::" + *ecx.tcx.sess.str_of(m.ident));
+    ebml_w.wr_str(*exp.name + "::" + *ecx.tcx.sess.str_of(method_ident));
     ebml_w.end_tag();
     ebml_w.end_tag();
 }
 
+fn encode_reexported_static_base_methods(ecx: @EncodeContext,
+                                         ebml_w: &mut writer::Encoder,
+                                         exp: &middle::resolve::Export2)
+                                         -> bool {
+    match ecx.tcx.base_impls.find(&exp.def_id) {
+        Some(implementations) => {
+            for implementations.each |&base_impl| {
+                for base_impl.methods.each |&m| {
+                    if m.explicit_self == ast::sty_static {
+                        encode_reexported_static_method(ecx, ebml_w, exp,
+                                                        m.did, m.ident);
+                    }
+                }
+            }
+
+            true
+        }
+        None => { false }
+    }
+}
+
+fn encode_reexported_static_trait_methods(ecx: @EncodeContext,
+                                          ebml_w: &mut writer::Encoder,
+                                          exp: &middle::resolve::Export2)
+                                          -> bool {
+    match ecx.tcx.trait_methods_cache.find(&exp.def_id) {
+        Some(methods) => {
+            for methods.each |&m| {
+                if m.explicit_self == ast::sty_static {
+                    encode_reexported_static_method(ecx, ebml_w, exp,
+                                                    m.def_id, m.ident);
+                }
+            }
+
+            true
+        }
+        None => { false }
+    }
+}
+
 fn encode_reexported_static_methods(ecx: @EncodeContext,
                                     ebml_w: &mut writer::Encoder,
                                     mod_path: &[ast_map::path_elt],
                                     exp: &middle::resolve::Export2) {
-    match ecx.tcx.trait_methods_cache.find(&exp.def_id) {
-        Some(methods) => {
-            match ecx.tcx.items.find(&exp.def_id.node) {
-                Some(&ast_map::node_item(item, path)) => {
-                    let original_name = ecx.tcx.sess.str_of(item.ident);
-
-                    //
-                    // We don't need to reexport static methods on traits
-                    // declared in the same module as our `pub use ...` since
-                    // that's done when we encode the trait item.
-                    //
-                    // The only exception is when the reexport *changes* the
-                    // name e.g. `pub use Foo = self::Bar` -- we have
-                    // encoded metadata for static methods relative to Bar,
-                    // but not yet for Foo.
-                    //
-                    if mod_path != *path || *exp.name != *original_name {
-                        for methods.each |&m| {
-                            if m.explicit_self == ast::sty_static {
-                                encode_reexported_static_method(ecx,
-                                                                ebml_w,
-                                                                exp, m);
-                            }
-                        }
+    match ecx.tcx.items.find(&exp.def_id.node) {
+        Some(&ast_map::node_item(item, path)) => {
+            let original_name = ecx.tcx.sess.str_of(item.ident);
+
+            //
+            // We don't need to reexport static methods on items
+            // declared in the same module as our `pub use ...` since
+            // that's done when we encode the trait item.
+            //
+            // The only exception is when the reexport *changes* the
+            // name e.g. `pub use Foo = self::Bar` -- we have
+            // encoded metadata for static methods relative to Bar,
+            // but not yet for Foo.
+            //
+            if mod_path != *path || *exp.name != *original_name {
+                if !encode_reexported_static_base_methods(ecx, ebml_w, exp) {
+                    if encode_reexported_static_trait_methods(ecx, ebml_w, exp) {
+                        debug!(fmt!("(encode reexported static methods) %s \
+                                    [trait]",
+                                    *original_name));
                     }
                 }
-                _ => {}
+                else {
+                    debug!(fmt!("(encode reexported static methods) %s [base]",
+                                *original_name));
+                }
             }
         }
         _ => {}
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 0d180223fef..e46a19d88c6 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -306,6 +306,9 @@ struct ctxt_ {
     // Maps a trait onto a mapping from self-ty to impl
     trait_impls: @mut HashMap<ast::def_id, @mut HashMap<t, @Impl>>,
 
+    // Maps a base type to its impl
+    base_impls: @mut HashMap<ast::def_id, @mut ~[@Impl]>,
+
     // Set of used unsafe nodes (functions or blocks). Unsafe nodes not
     // present in this set can be warned about.
     used_unsafe: @mut HashSet<ast::node_id>,
@@ -971,6 +974,7 @@ pub fn mk_ctxt(s: session::Session,
         destructor_for_type: @mut HashMap::new(),
         destructors: @mut HashSet::new(),
         trait_impls: @mut HashMap::new(),
+        base_impls:  @mut HashMap::new(),
         used_unsafe: @mut HashSet::new(),
         used_mut_nodes: @mut HashSet::new(),
      }
@@ -3699,6 +3703,21 @@ pub fn trait_method(cx: ctxt, trait_did: ast::def_id, idx: uint) -> @Method {
     ty::method(cx, method_def_id)
 }
 
+
+pub fn add_base_impl(cx: ctxt, base_def_id: def_id, implementation: @Impl) {
+    let implementations;
+    match cx.base_impls.find(&base_def_id) {
+        None => {
+            implementations = @mut ~[];
+            cx.base_impls.insert(base_def_id, implementations);
+        }
+        Some(&existing) => {
+            implementations = existing;
+        }
+    }
+    implementations.push(implementation);
+}
+
 pub fn trait_methods(cx: ctxt, trait_did: ast::def_id) -> @~[@Method] {
     match cx.trait_methods_cache.find(&trait_did) {
         Some(&methods) => methods,
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index 3cb028b811e..01260a097d7 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -146,7 +146,7 @@ pub fn get_base_type_def_id(inference_context: @mut InferCtxt,
                 }
                 _ => {
                     fail!("get_base_type() returned a type that wasn't an \
-                           enum, class, or trait");
+                           enum, struct, or trait");
                 }
             }
         }
@@ -312,6 +312,7 @@ pub impl CoherenceChecker {
                             implementation = existing_implementation;
                         }
                     }
+
                     self.add_inherent_method(base_type_def_id,
                                              implementation);
                 }
@@ -432,6 +433,8 @@ pub impl CoherenceChecker {
         }
 
         implementation_list.push(implementation);
+
+        ty::add_base_impl(self.crate_context.tcx, base_def_id, implementation);
     }
 
     fn add_trait_method(&self, trait_id: def_id, implementation: @Impl) {
diff --git a/src/test/auxiliary/mod_trait_with_static_methods_lib.rs b/src/test/auxiliary/reexported_static_methods.rs
index 3591ff79318..88e746585c9 100644
--- a/src/test/auxiliary/mod_trait_with_static_methods_lib.rs
+++ b/src/test/auxiliary/reexported_static_methods.rs
@@ -10,6 +10,8 @@
 
 pub use sub_foo::Foo;
 pub use Baz = self::Bar;
+pub use sub_foo::Boz;
+pub use sub_foo::Bort;
 
 pub trait Bar {
     pub fn bar() -> Self;
@@ -28,4 +30,24 @@ pub mod sub_foo {
         pub fn foo() -> int { 42 }
     }
 
+    pub struct Boz {
+        unused_str: ~str
+    }
+
+    pub impl Boz {
+        pub fn boz(i: int) -> bool {
+            i > 0
+        }
+    }
+
+    pub enum Bort {
+        Bort1,
+        Bort2
+    }
+
+    pub impl Bort {
+        pub fn bort() -> ~str {
+            ~"bort()"
+        }
+    }
 }
diff --git a/src/test/run-pass/trait_with_static_methods_cross_crate.rs b/src/test/run-pass/reexported-static-methods-cross-crate.rs
index 4402881c43d..e8e58d78e95 100644
--- a/src/test/run-pass/trait_with_static_methods_cross_crate.rs
+++ b/src/test/run-pass/reexported-static-methods-cross-crate.rs
@@ -9,13 +9,17 @@
 // except according to those terms.
 
 // xfail-fast
-// aux-build:mod_trait_with_static_methods_lib.rs
-extern mod mod_trait_with_static_methods_lib;
+// aux-build:reexported_static_methods.rs
+extern mod reexported_static_methods;
 
-use mod_trait_with_static_methods_lib::Foo;
-use mod_trait_with_static_methods_lib::Baz;
+use reexported_static_methods::Foo;
+use reexported_static_methods::Baz;
+use reexported_static_methods::Boz;
+use reexported_static_methods::Bort;
 
 pub fn main() {
     assert_eq!(42, Foo::foo());
     assert_eq!(84, Baz::bar());
+    assert!(Boz::boz(1));
+    assert_eq!(~"bort()", Bort::bort());
 }