auto merge of #8875 : alexcrichton/rust/fix-inner-static-library-bug, r=huonw
These commits fix bugs related to identically named statics in functions of implementations in various situations. The commit messages have most of the information about what bugs are being fixed and why. As a bonus, while I was messing around with name mangling, I improved the backtraces we'll get in gdb by removing `__extensions__` for the trait/type being implemented and by adding the method name as well. Yay!
This commit is contained in:
commit
3c3ae1d0e2
@ -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;
|
||||
@ -667,8 +667,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.
|
||||
|
||||
@ -723,7 +722,7 @@ pub fn sanitize(s: &str) -> ~str {
|
||||
'a' .. 'z'
|
||||
| 'A' .. 'Z'
|
||||
| '0' .. '9'
|
||||
| '_' => result.push_char(c),
|
||||
| '_' | '.' => result.push_char(c),
|
||||
|
||||
_ => {
|
||||
let mut tstr = ~"";
|
||||
@ -744,19 +743,65 @@ pub fn sanitize(s: &str) -> ~str {
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn mangle(sess: Session, ss: path) -> ~str {
|
||||
// Follow C++ namespace-mangling style
|
||||
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"; // Begin name-sequence.
|
||||
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 <len, name> pairs.
|
||||
for s in ss.iter() {
|
||||
match *s {
|
||||
path_name(s) | path_mod(s) => {
|
||||
let sani = sanitize(sess.str_of(s));
|
||||
n.push_str(fmt!("%u%s", sani.len(), sani));
|
||||
path_name(s) | path_mod(s) | path_pretty_name(s, _) => {
|
||||
push(sess.str_of(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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";
|
||||
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;
|
||||
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
|
||||
}
|
||||
@ -765,10 +810,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,
|
||||
@ -786,31 +836,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 {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -359,12 +359,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);
|
||||
|
@ -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;
|
||||
@ -2627,8 +2627,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);
|
||||
|
||||
|
@ -948,7 +948,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 {
|
||||
|
@ -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?") }
|
||||
}
|
||||
};
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ 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;
|
||||
@ -28,7 +29,13 @@ 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
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,8 +118,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,
|
||||
@ -131,7 +140,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 {
|
||||
@ -173,7 +182,15 @@ impl Ctx {
|
||||
for a in decl.inputs.iter() {
|
||||
self.map.insert(a.id, node_arg(a.pat));
|
||||
}
|
||||
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) {
|
||||
@ -199,6 +216,28 @@ impl Ctx {
|
||||
|
||||
visit::walk_pat(self, pat, ());
|
||||
}
|
||||
|
||||
fn impl_pretty_name(&self, trait_ref: &Option<trait_ref>,
|
||||
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 {
|
||||
@ -207,20 +246,28 @@ 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) => {
|
||||
// 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)
|
||||
}
|
||||
|
||||
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) => {
|
||||
@ -239,7 +286,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
|
||||
@ -258,7 +307,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) => {
|
||||
@ -279,6 +328,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, ());
|
||||
|
61
src/test/auxiliary/inner_static.rs
Normal file
61
src/test/auxiliary/inner_static.rs
Normal file
@ -0,0 +1,61 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub struct A<T>;
|
||||
pub struct B<T>;
|
||||
|
||||
pub mod test {
|
||||
pub struct A<T>;
|
||||
}
|
||||
|
||||
impl<T> A<T> {
|
||||
pub fn foo(&self) -> int {
|
||||
static a: int = 1;
|
||||
return a
|
||||
}
|
||||
|
||||
pub fn bar(&self) -> int {
|
||||
static a: int = 2;
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> B<T> {
|
||||
pub fn foo(&self) -> int {
|
||||
static a: int = 3;
|
||||
return a
|
||||
}
|
||||
|
||||
pub fn bar(&self) -> int {
|
||||
static a: int = 4;
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> test::A<T> {
|
||||
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::<()>;
|
||||
let b = B::<()>;
|
||||
let c = test::A::<()>;
|
||||
return a.foo() + a.bar() +
|
||||
b.foo() + b.bar() +
|
||||
c.foo() + c.bar();
|
||||
}
|
@ -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`
|
||||
|
@ -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() {
|
||||
|
23
src/test/run-pass/inner-static.rs
Normal file
23
src/test/run-pass/inner-static.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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::<()>;
|
||||
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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user