From 4600212a385b41f0c718b6b07dbb6c2c4531314a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 29 Aug 2013 22:29:26 -0700 Subject: [PATCH 1/3] Fix inner statics having the same symbol name Before, the path name for all items defined in methods of traits and impls never took into account the name of the method. This meant that if you had two statics of the same name in two different methods the statics would end up having the same symbol named (even after mangling) because the path components leading to the symbol were exactly the same (just __extensions__ and the static name). It turns out that if you add the symbol "A" twice to LLVM, it automatically makes the second one "A1" instead of "A". What this meant is that in local crate compilations we never found this bug. Even across crates, this was never a problem. The problem arises when you have generic methods that don't get generated at compile-time of a library. If the statics were re-added to LLVM by a client crate of a library in a different order, you would reference different constants (the integer suffixes wouldn't be guaranteed to be the same). This fixes the problem by adding the method name to symbol path when building the ast_map. In doing so, two symbols in two different methods are disambiguated against. --- src/libsyntax/ast_map.rs | 8 ++++++++ src/test/auxiliary/inner_static.rs | 28 ++++++++++++++++++++++++++++ src/test/run-pass/inner-static.rs | 19 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/test/auxiliary/inner_static.rs create mode 100644 src/test/run-pass/inner-static.rs diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 6e022e9804b41..5da94bebf1659 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -153,7 +153,15 @@ impl Ctx { for a in decl.inputs.iter() { self.map.insert(a.id, node_arg); } + match *fk { + visit::fk_method(name, _, _) => { self.path.push(path_name(name)) } + _ => {} + } visit::walk_fn(self, fk, decl, body, sp, id, ()); + match *fk { + visit::fk_method(*) => { self.path.pop(); } + _ => {} + } } fn map_stmt(&mut self, stmt: @stmt) { diff --git a/src/test/auxiliary/inner_static.rs b/src/test/auxiliary/inner_static.rs new file mode 100644 index 0000000000000..706586684ec0a --- /dev/null +++ b/src/test/auxiliary/inner_static.rs @@ -0,0 +1,28 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct A; + +impl A { + pub fn foo(&self) -> int { + static a: int = 5; + return a + } + + pub fn bar(&self) -> int { + static a: int = 3; + return a; + } +} + +pub fn foo() -> int { + let a = A::<()>; + return a.foo() + a.bar(); +} diff --git a/src/test/run-pass/inner-static.rs b/src/test/run-pass/inner-static.rs new file mode 100644 index 0000000000000..969dc607b8014 --- /dev/null +++ b/src/test/run-pass/inner-static.rs @@ -0,0 +1,19 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:inner_static.rs +// xfail-fast + +extern mod inner_static; + +pub fn main() { + let a = inner_static::A::<()>; + assert_eq!(a.bar(), 3); +} From 36a4af49e0d66026e8ee7d156b2631208c4de2e5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 30 Aug 2013 00:47:10 -0700 Subject: [PATCH 2/3] Remove __extensions__ in names for a "pretty name" As with the previous commit, this is targeted at removing the possibility of collisions between statics. The main use case here is when there's a type-parametric function with an inner static that's compiled as a library. Before this commit, any impl would generate a path item of "__extensions__". This changes this identifier to be a "pretty name", which is either the last element of the path of the trait implemented or the last element of the type's path that's being implemented. That doesn't quite cut it though, so the (trait, type) pair is hashed and again used to append information to the symbol. Essentially, __extensions__ was removed for something nicer for debugging, and then some more information was added to symbol name by including a hash of the trait being implemented and type it's being implemented for. This should prevent colliding names for inner statics in regular functions with similar names. --- src/librustc/back/link.rs | 29 +++++++++++++++++--- src/librustc/metadata/common.rs | 4 +++ src/librustc/metadata/decoder.rs | 9 +++++++ src/librustc/metadata/encoder.rs | 21 ++++++++++----- src/librustc/middle/trans/common.rs | 3 ++- src/librustc/middle/trans/meth.rs | 4 +-- src/librustc/util/ppaux.rs | 3 ++- src/libsyntax/ast_map.rs | 41 +++++++++++++++++++++++++---- src/test/auxiliary/inner_static.rs | 37 ++++++++++++++++++++++++-- src/test/run-pass/inner-static.rs | 6 ++++- 10 files changed, 135 insertions(+), 22 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 64fa25fde2095..170f38f334289 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -35,7 +35,7 @@ use std::run; use std::str; use std::vec; use syntax::ast; -use syntax::ast_map::{path, path_mod, path_name}; +use syntax::ast_map::{path, path_mod, path_name, path_pretty_name}; use syntax::attr; use syntax::attr::{AttrMetaMethods}; use syntax::print::pprust; @@ -741,19 +741,40 @@ pub fn sanitize(s: &str) -> ~str { } pub fn mangle(sess: Session, ss: path) -> ~str { - // Follow C++ namespace-mangling style + // Follow C++ namespace-mangling style, see + // http://en.wikipedia.org/wiki/Name_mangling for more info. - let mut n = ~"_ZN"; // Begin name-sequence. + let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested + // First, connect each component with pairs. for s in ss.iter() { match *s { - path_name(s) | path_mod(s) => { + path_name(s) | path_mod(s) | path_pretty_name(s, _) => { let sani = sanitize(sess.str_of(s)); n.push_str(fmt!("%u%s", sani.len(), sani)); } } } n.push_char('E'); // End name-sequence. + + // next, if any identifiers are "pretty" and need extra information tacked + // on, then use the hash to generate two unique characters. For now + // hopefully 2 characters is enough to avoid collisions. + static EXTRA_CHARS: &'static str = + "abcdefghijklmnopqrstuvwxyz\ + ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + 0123456789"; + for s in ss.iter() { + match *s { + path_pretty_name(_, extra) => { + let hi = (extra >> 32) as u32 as uint; + let lo = extra as u32 as uint; + n.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char); + n.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char); + } + _ => {} + } + } n } diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 8af535865941f..c3bc3e0fe25c1 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -188,6 +188,10 @@ pub static tag_impls_impl: uint = 0x84; pub static tag_items_data_item_inherent_impl: uint = 0x85; pub static tag_items_data_item_extension_impl: uint = 0x86; +pub static tag_path_elt_pretty_name: uint = 0x87; +pub static tag_path_elt_pretty_name_ident: uint = 0x88; +pub static tag_path_elt_pretty_name_extra: uint = 0x89; + pub struct LinkMeta { name: @str, vers: @str, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 0200ca49bad9a..f7f8a17e0a9b8 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -303,6 +303,15 @@ fn item_path(item_doc: ebml::Doc) -> ast_map::path { } else if tag == tag_path_elt_name { let str = elt_doc.as_str_slice(); result.push(ast_map::path_name(token::str_to_ident(str))); + } else if tag == tag_path_elt_pretty_name { + let name_doc = reader::get_doc(elt_doc, + tag_path_elt_pretty_name_ident); + let extra_doc = reader::get_doc(elt_doc, + tag_path_elt_pretty_name_extra); + let str = name_doc.as_str_slice(); + let extra = reader::doc_as_u64(extra_doc); + result.push(ast_map::path_pretty_name(token::str_to_ident(str), + extra)); } else { // ignore tag_path_len element } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index d2ad788964994..82f744930c022 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -358,12 +358,21 @@ fn encode_path(ecx: &EncodeContext, fn encode_path_elt(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, elt: ast_map::path_elt) { - let (tag, name) = match elt { - ast_map::path_mod(name) => (tag_path_elt_mod, name), - ast_map::path_name(name) => (tag_path_elt_name, name) - }; - - ebml_w.wr_tagged_str(tag, ecx.tcx.sess.str_of(name)); + match elt { + ast_map::path_mod(n) => { + ebml_w.wr_tagged_str(tag_path_elt_mod, ecx.tcx.sess.str_of(n)); + } + ast_map::path_name(n) => { + ebml_w.wr_tagged_str(tag_path_elt_name, ecx.tcx.sess.str_of(n)); + } + ast_map::path_pretty_name(n, extra) => { + ebml_w.start_tag(tag_path_elt_pretty_name); + ebml_w.wr_tagged_str(tag_path_elt_pretty_name_ident, + ecx.tcx.sess.str_of(n)); + ebml_w.wr_tagged_u64(tag_path_elt_pretty_name_extra, extra); + ebml_w.end_tag(); + } + } } ebml_w.start_tag(tag_path); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 9b608d1266950..2080554001f09 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -947,7 +947,8 @@ pub fn path_str(sess: session::Session, p: &[path_elt]) -> ~str { let mut first = true; for e in p.iter() { match *e { - ast_map::path_name(s) | ast_map::path_mod(s) => { + ast_map::path_name(s) | ast_map::path_mod(s) | + ast_map::path_pretty_name(s, _) => { if first { first = false } else { diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index fa10b8a8e4493..3719562739f9b 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -34,7 +34,7 @@ use middle::trans::type_::Type; use std::c_str::ToCStr; use std::vec; -use syntax::ast_map::{path, path_mod, path_name}; +use syntax::ast_map::{path, path_mod, path_name, path_pretty_name}; use syntax::ast_util; use syntax::{ast, ast_map}; use syntax::visit; @@ -254,7 +254,7 @@ pub fn trans_static_method_callee(bcx: @mut Block, } else { let path = csearch::get_item_path(bcx.tcx(), method_id); match path[path.len()-1] { - path_name(s) => { s } + path_pretty_name(s, _) | path_name(s) => { s } path_mod(_) => { fail!("path doesn't have a name?") } } }; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index fe33205171430..cf7eea31a61ef 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -799,7 +799,8 @@ impl Repr for ast_map::path_elt { fn repr(&self, tcx: ctxt) -> ~str { match *self { ast_map::path_mod(id) => id.repr(tcx), - ast_map::path_name(id) => id.repr(tcx) + ast_map::path_name(id) => id.repr(tcx), + ast_map::path_pretty_name(id, _) => id.repr(tcx), } } } diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 5da94bebf1659..cb1c0eab72004 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -22,6 +22,7 @@ use print::pprust; use visit::{Visitor, fn_kind}; use visit; +use std::hash; use std::hashmap::HashMap; use std::vec; @@ -29,6 +30,12 @@ use std::vec; pub enum path_elt { path_mod(Ident), path_name(Ident) + + // A pretty name can come from an `impl` block. We attempt to select a + // reasonable name for debuggers to see, but to guarantee uniqueness with + // other paths the hash should also be taken into account during symbol + // generation. + path_pretty_name(Ident, u64), } pub type path = ~[path_elt]; @@ -37,8 +44,9 @@ pub fn path_to_str_with_sep(p: &[path_elt], sep: &str, itr: @ident_interner) -> ~str { let strs = do p.map |e| { match *e { - path_mod(s) => itr.get(s.name), - path_name(s) => itr.get(s.name) + path_mod(s) | path_name(s) | path_pretty_name(s, _) => { + itr.get(s.name) + } } }; strs.connect(sep) @@ -58,8 +66,9 @@ pub fn path_to_str(p: &[path_elt], itr: @ident_interner) -> ~str { pub fn path_elt_to_str(pe: path_elt, itr: @ident_interner) -> ~str { match pe { - path_mod(s) => itr.get(s.name).to_owned(), - path_name(s) => itr.get(s.name).to_owned() + path_mod(s) | path_name(s) | path_pretty_name(s, _) => { + itr.get(s.name).to_owned() + } } } @@ -195,12 +204,33 @@ impl Visitor<()> for Ctx { let item_path = @self.path.clone(); self.map.insert(i.id, node_item(i, item_path)); match i.node { - item_impl(_, _, _, ref ms) => { + item_impl(_, ref maybe_trait, ref ty, ref ms) => { let impl_did = ast_util::local_def(i.id); for m in ms.iter() { let extended = { self.extend(i.ident) }; self.map_method(impl_did, extended, *m, false) } + + // Right now the ident on impls is __extensions__ which isn't + // very pretty when debugging, so attempt to select a better + // name to use. + let name = match *maybe_trait { + Some(ref trait_ref) => { + trait_ref.path.segments.last().identifier + } + None => { + match ty.node { + ty_path(ref p, _, _) => { + p.segments.last().identifier + } + // oh well, just give up for now + _ => { i.ident } + } + } + }; + + let hash = hash::hash_keyed_2(maybe_trait, ty, 0, 0); + self.path.push(path_pretty_name(name, hash)); } item_enum(ref enum_definition, _) => { for v in (*enum_definition).variants.iter() { @@ -267,6 +297,7 @@ impl Visitor<()> for Ctx { item_mod(_) | item_foreign_mod(_) => { self.path.push(path_mod(i.ident)); } + item_impl(*) => {} // this was guessed above. _ => self.path.push(path_name(i.ident)) } visit::walk_item(self, i, ()); diff --git a/src/test/auxiliary/inner_static.rs b/src/test/auxiliary/inner_static.rs index 706586684ec0a..841da21c5e845 100644 --- a/src/test/auxiliary/inner_static.rs +++ b/src/test/auxiliary/inner_static.rs @@ -9,20 +9,53 @@ // except according to those terms. pub struct A; +pub struct B; + +pub mod test { + pub struct A; +} impl A { pub fn foo(&self) -> int { - static a: int = 5; + static a: int = 1; return a } pub fn bar(&self) -> int { + static a: int = 2; + return a; + } +} + +impl B { + pub fn foo(&self) -> int { static a: int = 3; + return a + } + + pub fn bar(&self) -> int { + static a: int = 4; + return a; + } +} + +impl test::A { + pub fn foo(&self) -> int { + static a: int = 5; + return a + } + + pub fn bar(&self) -> int { + static a: int = 6; return a; } } pub fn foo() -> int { let a = A::<()>; - return a.foo() + a.bar(); + let b = B::<()>; + let c = test::A::<()>; + return a.foo() + a.bar() + + b.foo() + b.bar() + + c.foo() + c.bar(); } diff --git a/src/test/run-pass/inner-static.rs b/src/test/run-pass/inner-static.rs index 969dc607b8014..3bd806aeef3e5 100644 --- a/src/test/run-pass/inner-static.rs +++ b/src/test/run-pass/inner-static.rs @@ -15,5 +15,9 @@ extern mod inner_static; pub fn main() { let a = inner_static::A::<()>; - assert_eq!(a.bar(), 3); + let b = inner_static::B::<()>; + let c = inner_static::test::A::<()>; + assert_eq!(a.bar(), 2); + assert_eq!(b.bar(), 4); + assert_eq!(c.bar(), 6); } From 7baff57f268eff79cd8ed6a8d7fd48d4b3f81878 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 2 Sep 2013 22:34:37 -0700 Subject: [PATCH 3/3] Improve name mangling for gdb Remove __extensions__ from method symbols as well as the meth_XXX. The XXX is now used to append a few characters at the end of the name of the symbol. Closes #6602 --- src/librustc/back/link.rs | 77 ++++++++++++++++------- src/librustc/middle/trans/base.rs | 5 +- src/libsyntax/ast_map.rs | 69 +++++++++++--------- src/test/compile-fail/ambig_impl_2_exe.rs | 2 +- src/test/compile-fail/ambig_impl_unify.rs | 4 +- 5 files changed, 99 insertions(+), 58 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 170f38f334289..fe2d59a0ba7c4 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -663,8 +663,7 @@ pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str { pub fn symbol_hash(tcx: ty::ctxt, symbol_hasher: &mut hash::State, t: ty::t, - link_meta: LinkMeta) - -> @str { + link_meta: LinkMeta) -> @str { // NB: do *not* use abbrevs here as we want the symbol names // to be independent of one another in the crate. @@ -719,7 +718,7 @@ pub fn sanitize(s: &str) -> ~str { 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' - | '_' => result.push_char(c), + | '_' | '.' => result.push_char(c), _ => { let mut tstr = ~""; @@ -740,22 +739,37 @@ pub fn sanitize(s: &str) -> ~str { return result; } -pub fn mangle(sess: Session, ss: path) -> ~str { +pub fn mangle(sess: Session, ss: path, + hash: Option<&str>, vers: Option<&str>) -> ~str { // Follow C++ namespace-mangling style, see // http://en.wikipedia.org/wiki/Name_mangling for more info. + // + // It turns out that on OSX you can actually have arbitrary symbols in + // function names (at least when given to LLVM), but this is not possible + // when using unix's linker. Perhaps one day when we just a linker from LLVM + // we won't need to do this name mangling. The problem with name mangling is + // that it seriously limits the available characters. For example we can't + // have things like @T or ~[T] in symbol names when one would theoretically + // want them for things like impls of traits on that type. + // + // To be able to work on all platforms and get *some* reasonable output, we + // use C++ name-mangling. let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested + let push = |s: &str| { + let sani = sanitize(s); + n.push_str(fmt!("%u%s", sani.len(), sani)); + }; + // First, connect each component with pairs. for s in ss.iter() { match *s { path_name(s) | path_mod(s) | path_pretty_name(s, _) => { - let sani = sanitize(sess.str_of(s)); - n.push_str(fmt!("%u%s", sani.len(), sani)); + push(sess.str_of(s)) } } } - n.push_char('E'); // End name-sequence. // next, if any identifiers are "pretty" and need extra information tacked // on, then use the hash to generate two unique characters. For now @@ -764,17 +778,27 @@ pub fn mangle(sess: Session, ss: path) -> ~str { "abcdefghijklmnopqrstuvwxyz\ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 0123456789"; + let mut hash = match hash { Some(s) => s.to_owned(), None => ~"" }; for s in ss.iter() { match *s { path_pretty_name(_, extra) => { let hi = (extra >> 32) as u32 as uint; let lo = extra as u32 as uint; - n.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char); - n.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char); + hash.push_char(EXTRA_CHARS[hi % EXTRA_CHARS.len()] as char); + hash.push_char(EXTRA_CHARS[lo % EXTRA_CHARS.len()] as char); } _ => {} } } + if hash.len() > 0 { + push(hash); + } + match vers { + Some(s) => push(s), + None => {} + } + + n.push_char('E'); // End name-sequence. n } @@ -782,10 +806,15 @@ pub fn exported_name(sess: Session, path: path, hash: &str, vers: &str) -> ~str { - mangle(sess, - vec::append_one( - vec::append_one(path, path_name(sess.ident_of(hash))), - path_name(sess.ident_of(vers)))) + // The version will get mangled to have a leading '_', but it makes more + // sense to lead with a 'v' b/c this is a version... + let vers = if vers.len() > 0 && !char::is_XID_start(vers.char_at(0)) { + "v" + vers + } else { + vers.to_owned() + }; + + mangle(sess, path, Some(hash), Some(vers.as_slice())) } pub fn mangle_exported_name(ccx: &mut CrateContext, @@ -803,31 +832,33 @@ pub fn mangle_internal_name_by_type_only(ccx: &mut CrateContext, let s = ppaux::ty_to_short_str(ccx.tcx, t); let hash = get_symbol_hash(ccx, t); return mangle(ccx.sess, - ~[path_name(ccx.sess.ident_of(name)), - path_name(ccx.sess.ident_of(s)), - path_name(ccx.sess.ident_of(hash))]); + ~[path_name(ccx.sess.ident_of(name)), + path_name(ccx.sess.ident_of(s))], + Some(hash.as_slice()), + None); } pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext, - t: ty::t, - name: &str) -> ~str { + t: ty::t, + name: &str) -> ~str { let s = ppaux::ty_to_str(ccx.tcx, t); let hash = get_symbol_hash(ccx, t); return mangle(ccx.sess, - ~[path_name(ccx.sess.ident_of(s)), - path_name(ccx.sess.ident_of(hash)), - path_name(gensym_name(name))]); + ~[path_name(ccx.sess.ident_of(s)), + path_name(gensym_name(name))], + Some(hash.as_slice()), + None); } pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext, mut path: path, flav: &str) -> ~str { path.push(path_name(gensym_name(flav))); - mangle(ccx.sess, path) + mangle(ccx.sess, path, None, None) } pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str { - mangle(ccx.sess, path) + mangle(ccx.sess, path, None, None) } pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 79440b03d761f..16afc6f36caa2 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -77,7 +77,7 @@ use std::local_data; use extra::time; use extra::sort; use syntax::ast::Ident; -use syntax::ast_map::{path, path_elt_to_str, path_name}; +use syntax::ast_map::{path, path_elt_to_str, path_name, path_pretty_name}; use syntax::ast_util::{local_def}; use syntax::attr; use syntax::attr::AttrMetaMethods; @@ -2646,8 +2646,7 @@ pub fn register_method(ccx: @mut CrateContext, let mty = ty::node_id_to_type(ccx.tcx, id); let mut path = (*path).clone(); - path.push(path_name(gensym_name("meth"))); - path.push(path_name(m.ident)); + path.push(path_pretty_name(m.ident, token::gensym("meth") as u64)); let sym = exported_name(ccx, path, mty, m.attrs); diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index cb1c0eab72004..1165ca0c68f21 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -16,20 +16,20 @@ use ast_util; use codemap::Span; use codemap; use diagnostic::span_handler; +use parse::token::get_ident_interner; use parse::token::ident_interner; use parse::token::special_idents; use print::pprust; use visit::{Visitor, fn_kind}; use visit; -use std::hash; use std::hashmap::HashMap; use std::vec; #[deriving(Clone, Eq)] pub enum path_elt { path_mod(Ident), - path_name(Ident) + path_name(Ident), // A pretty name can come from an `impl` block. We attempt to select a // reasonable name for debuggers to see, but to guarantee uniqueness with @@ -98,8 +98,8 @@ pub struct Ctx { } impl Ctx { - fn extend(&self, elt: Ident) -> @path { - @vec::append(self.path.clone(), [path_name(elt)]) + fn extend(&self, elt: path_elt) -> @path { + @vec::append(self.path.clone(), [elt]) } fn map_method(&mut self, @@ -120,7 +120,7 @@ impl Ctx { struct_def: @ast::struct_def, parent_node: ast_node, ident: ast::Ident) { - let p = self.extend(ident); + let p = self.extend(path_name(ident)); // If this is a tuple-like struct, register the constructor. match struct_def.ctor_id { @@ -196,6 +196,28 @@ impl Ctx { visit::walk_pat(self, pat, ()); } + + fn impl_pretty_name(&self, trait_ref: &Option, + ty: &Ty, default: Ident) -> path_elt { + let itr = get_ident_interner(); + let ty_ident = match ty.node { + ty_path(ref path, _, _) => path.segments.last().identifier, + _ => default + }; + let hash = (trait_ref, ty).hash(); + match *trait_ref { + None => path_pretty_name(ty_ident, hash), + Some(ref trait_ref) => { + // XXX: this dollar sign is actually a relic of being one of the + // very few valid symbol names on unix. These kinds of + // details shouldn't be exposed way up here in the ast. + let s = fmt!("%s$%s", + itr.get(trait_ref.path.segments.last().identifier.name), + itr.get(ty_ident.name)); + path_pretty_name(Ident::new(itr.gensym(s)), hash) + } + } + } } impl Visitor<()> for Ctx { @@ -205,40 +227,27 @@ impl Visitor<()> for Ctx { self.map.insert(i.id, node_item(i, item_path)); match i.node { item_impl(_, ref maybe_trait, ref ty, ref ms) => { + // Right now the ident on impls is __extensions__ which isn't + // very pretty when debugging, so attempt to select a better + // name to use. + let elt = self.impl_pretty_name(maybe_trait, ty, i.ident); + let impl_did = ast_util::local_def(i.id); for m in ms.iter() { - let extended = { self.extend(i.ident) }; + let extended = { self.extend(elt) }; self.map_method(impl_did, extended, *m, false) } - // Right now the ident on impls is __extensions__ which isn't - // very pretty when debugging, so attempt to select a better - // name to use. - let name = match *maybe_trait { - Some(ref trait_ref) => { - trait_ref.path.segments.last().identifier - } - None => { - match ty.node { - ty_path(ref p, _, _) => { - p.segments.last().identifier - } - // oh well, just give up for now - _ => { i.ident } - } - } - }; - - let hash = hash::hash_keyed_2(maybe_trait, ty, 0, 0); - self.path.push(path_pretty_name(name, hash)); + self.path.push(elt); } item_enum(ref enum_definition, _) => { for v in (*enum_definition).variants.iter() { + let elt = path_name(i.ident); // FIXME #2543: bad clone self.map.insert(v.node.id, node_variant((*v).clone(), i, - self.extend(i.ident))); + self.extend(elt))); } } item_foreign_mod(ref nm) => { @@ -257,7 +266,9 @@ impl Visitor<()> for Ctx { // FIXME (#2543) if nm.sort == ast::named { - self.extend(i.ident) + let e = path_name( + i.ident); + self.extend(e) } else { // Anonymous extern // mods go in the @@ -276,7 +287,7 @@ impl Visitor<()> for Ctx { self.map.insert(p.ref_id, node_item(i, item_path)); } for tm in methods.iter() { - let ext = { self.extend(i.ident) }; + let ext = { self.extend(path_name(i.ident)) }; let d_id = ast_util::local_def(i.id); match *tm { required(ref m) => { diff --git a/src/test/compile-fail/ambig_impl_2_exe.rs b/src/test/compile-fail/ambig_impl_2_exe.rs index 1cf08b7f5036f..0f5bac795e768 100644 --- a/src/test/compile-fail/ambig_impl_2_exe.rs +++ b/src/test/compile-fail/ambig_impl_2_exe.rs @@ -15,6 +15,6 @@ use ambig_impl_2_lib::me; trait me { fn me(&self) -> uint; } -impl me for uint { fn me(&self) -> uint { *self } } //~ NOTE is `__extensions__::me` +impl me for uint { fn me(&self) -> uint { *self } } //~ NOTE is `me$uint::me` fn main() { 1u.me(); } //~ ERROR multiple applicable methods in scope //~^ NOTE is `ambig_impl_2_lib::__extensions__::me` diff --git a/src/test/compile-fail/ambig_impl_unify.rs b/src/test/compile-fail/ambig_impl_unify.rs index ce8c2a29544db..df88ff1f0d02e 100644 --- a/src/test/compile-fail/ambig_impl_unify.rs +++ b/src/test/compile-fail/ambig_impl_unify.rs @@ -13,11 +13,11 @@ trait foo { } impl foo for ~[uint] { - fn foo(&self) -> int {1} //~ NOTE candidate #1 is `__extensions__::foo` + fn foo(&self) -> int {1} //~ NOTE candidate #1 is `foo$__extensions__::foo` } impl foo for ~[int] { - fn foo(&self) -> int {2} //~ NOTE candidate #2 is `__extensions__::foo` + fn foo(&self) -> int {2} //~ NOTE candidate #2 is `foo$__extensions__::foo` } fn main() {