Skip to content

Commit

Permalink
Reexport static methods on structs & enums.
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaslee committed Jun 1, 2013
1 parent 2bf053c commit f6fa5b9
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 35 deletions.
100 changes: 70 additions & 30 deletions src/librustc/metadata/encoder.rs
Expand Up @@ -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));
}
}
}
_ => {}
Expand Down
19 changes: 19 additions & 0 deletions src/librustc/middle/ty.rs
Expand Up @@ -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>,
Expand Down Expand Up @@ -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(),
}
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/middle/typeck/coherence.rs
Expand Up @@ -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");
}
}
}
Expand Down Expand Up @@ -312,6 +312,7 @@ pub impl CoherenceChecker {
implementation = existing_implementation;
}
}

self.add_inherent_method(base_type_def_id,
implementation);
}
Expand Down Expand Up @@ -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) {
Expand Down
Expand Up @@ -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;
Expand All @@ -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()"
}
}
}
Expand Up @@ -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());
}

0 comments on commit f6fa5b9

Please sign in to comment.