From 8f26d0b9b8725fa74dc36fcf4abf45dc1ca8c56a Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 1 Jan 2014 16:30:21 +1100 Subject: [PATCH] syntax: expand impl_pretty_name to handle more cases. The resulting symbol names aren't very pretty at all: trait Trait { fn method(&self); } impl<'a> Trait for ~[(&'a int, fn())] { fn method(&self) {} } gives Trait$$UP$$VEC$$TUP_2$$BP$int$$FN$$::method::...hash...::v0.0 However, at least it contain some reference to the Self type, unlike `Trait$__extensions__::method:...`, which is what the symbol name used to be for anything other than `impl Trait for foo::bar::Baz` (which became, and still becomes, `Trait$Baz::method`). --- src/librustc/metadata/encoder.rs | 2 +- src/libsyntax/ast_map.rs | 85 +++++++++++++++++------ src/test/compile-fail/ambig_impl_unify.rs | 4 +- 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 73b0ac46cbd..5312805366a 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1140,7 +1140,7 @@ fn encode_info_for_item(ecx: &EncodeContext, let impl_vtables = ty::lookup_impl_vtables(tcx, def_id); encode_impl_vtables(ebml_w, ecx, &impl_vtables); } - let elt = ast_map::impl_pretty_name(opt_trait, ty, item.ident); + let elt = ast_map::impl_pretty_name(opt_trait, ty); encode_path(ecx, ebml_w, path, elt); ebml_w.end_tag(); diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 63e8251b22c..817cf24eec6 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -82,26 +82,71 @@ pub fn path_elt_to_str(pe: path_elt, itr: @ident_interner) -> ~str { } } -pub fn impl_pretty_name(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 = format!("{}${}", - itr.get(trait_ref.path.segments.last().identifier.name), - itr.get(ty_ident.name)); - path_pretty_name(Ident::new(itr.gensym(s)), hash) +/// write a "pretty" version of `ty` to `out`. This is designed so +/// that symbols of `impl`'d methods give some hint of where they came +/// from, even if it's hard to read (previously they would all just be +/// listed as `__extensions__::method_name::hash`, with no indication +/// of the type). +// XXX: these dollar signs and the names in general are 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. +fn pretty_ty(ty: &Ty, itr: @ident_interner, out: &mut ~str) { + let (prefix, subty) = match ty.node { + ty_uniq(ty) => ("$UP$", &*ty), + ty_box(mt { ty, .. }) => ("$SP$", &*ty), + ty_ptr(mt { ty, mutbl }) => (if mutbl == MutMutable {"$RPmut$"} else {"$RP$"}, + &*ty), + ty_rptr(_, mt { ty, mutbl }) => (if mutbl == MutMutable {"$BPmut$"} else {"$BP$"}, + &*ty), + + ty_vec(ty) => ("$VEC$", &*ty), + ty_fixed_length_vec(ty, _) => ("$FIXEDVEC$", &*ty), + + // these can't be represented as , so + // need custom handling. + ty_nil => { out.push_str("$NIL$"); return } + ty_path(ref path, _, _) => { + out.push_str(itr.get(path.segments.last().identifier.name)); + return + } + ty_tup(ref tys) => { + out.push_str(format!("$TUP_{}$", tys.len())); + for subty in tys.iter() { + pretty_ty(*subty, itr, out); + out.push_char('$'); + } + return } - } + + // meh, better than nothing. + ty_bot => { out.push_str("$BOT$"); return } + ty_closure(..) => { out.push_str("$CLOSURE$"); return } + ty_bare_fn(..) => { out.push_str("$FN$"); return } + ty_typeof(..) => { out.push_str("$TYPEOF$"); return } + ty_infer(..) => { out.push_str("$INFER$"); return } + + }; + + out.push_str(prefix); + pretty_ty(subty, itr, out); +} + +pub fn impl_pretty_name(trait_ref: &Option, ty: &Ty) -> path_elt { + let itr = get_ident_interner(); + + let hash = (trait_ref, ty).hash(); + let mut pretty; + match *trait_ref { + None => pretty = ~"", + Some(ref trait_ref) => { + pretty = itr.get(trait_ref.path.segments.last().identifier.name).to_owned(); + pretty.push_char('$'); + } + }; + pretty_ty(ty, itr, &mut pretty); + + path_pretty_name(Ident::new(itr.gensym(pretty)), hash) } #[deriving(Clone)] @@ -265,7 +310,7 @@ impl Visitor<()> for Ctx { // 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 = impl_pretty_name(maybe_trait, ty, i.ident); + let elt = impl_pretty_name(maybe_trait, ty); let impl_did = ast_util::local_def(i.id); for m in ms.iter() { diff --git a/src/test/compile-fail/ambig_impl_unify.rs b/src/test/compile-fail/ambig_impl_unify.rs index df88ff1f0d0..c758a173f38 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 `foo$__extensions__::foo` + fn foo(&self) -> int {1} //~ NOTE candidate #1 is `foo$$UP$$VEC$uint::foo` } impl foo for ~[int] { - fn foo(&self) -> int {2} //~ NOTE candidate #2 is `foo$__extensions__::foo` + fn foo(&self) -> int {2} //~ NOTE candidate #2 is `foo$$UP$$VEC$int::foo` } fn main() {