auto merge of #6880 : thomaslee/rust/issue-6745, r=catamorphism

This fixes #6745, which itself relates to #4202. Slightly ham-fisted -- feel particularly funny about using the typeck phase to gather the base -> impl mapping, and the separate code paths for traits vs. "real" bases feels like it could be avoided -- but it seems to work.

As always, open to suggestions if there's a better way to accomplish what I'm trying to do.

@catamorphism r?
This commit is contained in:
bors 2013-06-01 15:46:40 -07:00
commit 24e85ac82d
5 changed files with 122 additions and 34 deletions

View File

@ -374,50 +374,90 @@ fn encode_path_elt(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);
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);
}
}
//
// 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 item itself.
//
// 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));
}
}
}
_ => {}

View File

@ -307,6 +307,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>,
@ -972,6 +975,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(),
}
@ -3700,6 +3704,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,

View File

@ -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");
}
}
}
@ -313,6 +313,7 @@ pub fn check_implementation(&self,
implementation = existing_implementation;
}
}
self.add_inherent_method(base_type_def_id,
implementation);
}
@ -434,6 +435,8 @@ pub fn add_inherent_method(&self,
}
implementation_list.push(implementation);
ty::add_base_impl(self.crate_context.tcx, base_def_id, implementation);
}
pub fn add_trait_method(&self, trait_id: def_id, implementation: @Impl) {

View File

@ -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 @@ impl Foo for int {
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()"
}
}
}

View File

@ -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());
}