syntax: Parse multiple trait refs in a single implementation

This commit is contained in:
Patrick Walton 2012-07-18 09:31:53 -07:00
parent 1528256fdc
commit 3ac5b4a86f
14 changed files with 126 additions and 63 deletions

View File

@ -635,8 +635,10 @@ enum item_ {
option<class_dtor>
),
item_trait(~[ty_param], ~[trait_method]),
item_impl(~[ty_param], option<@trait_ref> /* trait */,
@ty /* self */, ~[@method]),
item_impl(~[ty_param],
~[@trait_ref], /* traits this impl implements */
@ty, /* self */
~[@method]),
item_mac(mac),
}

View File

@ -21,6 +21,7 @@ import ast_builder::append_types;
import ast_builder::ast_builder;
import ast_builder::methods;
import ast_builder::path;
import ast_builder::path_concat;
trait gen_send {
fn gen_send(cx: ext_ctxt) -> @ast::item;

View File

@ -2085,13 +2085,22 @@ class parser {
(some(id), self.parse_ty_params())
}
};
let ifce = if self.eat_keyword(~"of") {
let path = self.parse_path_with_tps(false);
if option::is_none(ident) {
ident = some(vec::last(path.idents));
let traits;
if self.eat_keyword(~"of") {
let for_atom = interner::intern(*self.reader.interner(), @~"for");
traits = self.parse_trait_ref_list(token::IDENT(for_atom, false));
if traits.len() >= 1 && option::is_none(ident) {
ident = some(vec::last(traits[0].path.idents));
}
some(@{path: path, ref_id: self.get_id(), impl_id: self.get_id()})
} else { none };
if traits.len() == 0 {
self.fatal(~"BUG: 'of' but no trait");
}
if traits.len() > 1 {
self.fatal(~"BUG: multiple traits");
}
} else {
traits = ~[];
};
let ident = alt ident {
some(name) { name }
none { self.expect_keyword(~"of"); fail; }
@ -2103,7 +2112,7 @@ class parser {
while !self.eat(token::RBRACE) {
vec::push(meths, self.parse_method(public));
}
(ident, item_impl(tps, ifce, ty, meths), none)
(ident, item_impl(tps, traits, ty, meths), none)
}
// Instantiates ident <i> with references to <typarams> as arguments.
@ -2127,9 +2136,9 @@ class parser {
ref_id: self.get_id(), impl_id: self.get_id()}
}
fn parse_trait_ref_list() -> ~[@trait_ref] {
fn parse_trait_ref_list(ket: token::token) -> ~[@trait_ref] {
self.parse_seq_to_before_end(
token::LBRACE, seq_sep_trailing_disallowed(token::COMMA),
ket, seq_sep_trailing_disallowed(token::COMMA),
|p| p.parse_trait_ref())
}
@ -2139,7 +2148,7 @@ class parser {
let ty_params = self.parse_ty_params();
let class_path = self.ident_to_path_tys(class_name, ty_params);
let traits : ~[@trait_ref] = if self.eat(token::COLON)
{ self.parse_trait_ref_list() }
{ self.parse_trait_ref_list(token::LBRACE) }
else { ~[] };
self.expect(token::LBRACE);
let mut ms: ~[@class_member] = ~[];

View File

@ -558,16 +558,18 @@ fn print_item(s: ps, &&item: @ast::item) {
}
bclose(s, item.span);
}
ast::item_impl(tps, ifce, ty, methods) {
ast::item_impl(tps, traits, ty, methods) {
head(s, ~"impl");
word(s.s, *item.ident);
print_type_params(s, tps);
space(s.s);
option::iter(ifce, |p| {
if vec::len(traits) != 0u {
word_nbsp(s, ~"of");
print_path(s, p.path, false);
do commasep(s, inconsistent, traits) |s, p| {
print_path(s, p.path, false);
}
space(s.s);
});
}
word_nbsp(s, ~"for");
print_type(s, ty);
space(s.s);

View File

@ -135,9 +135,11 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
for vr.node.args.each |va| { v.visit_ty(va.ty, e, v); }
}
}
item_impl(tps, ifce, ty, methods) {
item_impl(tps, traits, ty, methods) {
v.visit_ty_params(tps, e, v);
option::iter(ifce, |p| visit_path(p.path, e, v));
for traits.each |p| {
visit_path(p.path, e, v);
}
v.visit_ty(ty, e, v);
for methods.each |m| {
visit_method_helper(m, e, v)

View File

@ -410,14 +410,7 @@ fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::writer, md: _mod,
ref, we need to map it to its parent class */
ebml_w.wr_str(def_to_str(local_def(it.id)));
}
some(ast_map::node_item(@{node: item_impl(_,
some(ifce),_,_),_},_)) {
ebml_w.wr_str(def_to_str(did));
}
some(_) {
ebml_w.wr_str(def_to_str(did));
}
none {
_ {
// Must be a re-export, then!
// ...or an iface ref
ebml_w.wr_str(def_to_str(did));
@ -715,7 +708,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
encode_index(ebml_w, bkts, write_int);
ebml_w.end_tag();
}
item_impl(tps, ifce, _, methods) {
item_impl(tps, traits, _, methods) {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
@ -729,9 +722,12 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
ebml_w.writer.write(str::bytes(def_to_str(local_def(m.id))));
ebml_w.end_tag();
}
do option::iter(ifce) |t| {
encode_trait_ref(ebml_w, ecx, t)
};
if traits.len() > 1 {
fail ~"multiple traits!!";
}
for traits.each |associated_trait| {
encode_trait_ref(ebml_w, ecx, associated_trait)
}
encode_path(ebml_w, path, ast_map::path_name(item.ident));
ebml_w.end_tag();

View File

@ -2966,16 +2966,20 @@ class Resolver {
}
}
item_impl(type_parameters, interface_reference, self_type,
item_impl(type_parameters, implemented_traits, self_type,
methods) {
self.resolve_implementation(item.id,
item.span,
type_parameters,
interface_reference,
self_type,
methods,
visitor);
// XXX: Should take an array of traits.
let trait_reference;
if implemented_traits.len() == 0 {
trait_reference = none;
} else {
trait_reference = some(implemented_traits[0]);
}
self.resolve_implementation(item.id, item.span,
type_parameters, trait_reference,
self_type, methods, visitor);
}
item_trait(type_parameters, methods) {

View File

@ -2474,13 +2474,16 @@ fn trait_methods(cx: ctxt, id: ast::def_id) -> @~[method] {
result
}
// XXX: Needs to return an array of traits.
fn impl_trait(cx: ctxt, id: ast::def_id) -> option<t> {
if id.crate == ast::local_crate {
#debug("(impl_trait) searching for trait impl %?", id);
alt cx.items.find(id.node) {
some(ast_map::node_item(@{node: ast::item_impl(
_, some(@{ref_id: id, _}), _, _), _}, _)) {
some(node_id_to_type(cx, id))
some(ast_map::node_item(@{
node: ast::item_impl(_, traits, _, _),
_},
_)) if traits.len() >= 1 {
some(node_id_to_type(cx, traits[0].ref_id))
}
some(ast_map::node_item(@{node: ast::item_class(*),
_},_)) {

View File

@ -454,7 +454,7 @@ class lookup {
for (*trait_ids).each |trait_id| {
#debug("(adding inherent and extension candidates) \
trying trait: %s",
node_id_to_str(self.tcx().items, trait_id.node));
self.def_id_to_str(trait_id));
let coherence_info = self.fcx.ccx.coherence_info;
alt coherence_info.extension_methods.find(trait_id) {
@ -463,6 +463,10 @@ class lookup {
}
some(extension_methods) {
for extension_methods.each |implementation| {
#debug("(adding inherent and extension \
candidates) adding impl %s",
self.def_id_to_str
(implementation.did));
self.add_candidates_from_impl
(implementation, use_assignability);
}
@ -473,6 +477,14 @@ class lookup {
}
}
fn def_id_to_str(def_id: ast::def_id) -> ~str {
if def_id.crate == ast::local_crate {
node_id_to_str(self.tcx().items, def_id.node)
} else {
ast_map::path_to_str(csearch::get_item_path(self.tcx(), def_id))
}
}
fn write_mty_from_candidate(cand: candidate) -> method_map_entry {
let tcx = self.fcx.ccx.tcx;

View File

@ -154,9 +154,21 @@ class CoherenceChecker {
visit_crate(*crate, (), mk_simple_visitor(@{
visit_item: |item| {
#debug("(checking coherence) item '%s'", *item.ident);
alt item.node {
item_impl(_, associated_trait, self_type, _) {
self.check_implementation(item, associated_trait);
item_impl(_, associated_traits, self_type, _) {
// XXX: Accept an array of traits.
let optional_associated_trait;
if associated_traits.len() == 0 {
optional_associated_trait = none;
} else {
optional_associated_trait =
some(associated_traits[0]);
}
self.check_implementation(item,
optional_associated_trait);
}
_ {
// Nothing to do.
@ -189,6 +201,10 @@ class CoherenceChecker {
let self_type = self.crate_context.tcx.tcache.get(local_def(item.id));
alt optional_associated_trait {
none {
#debug("(checking implementation) no associated trait for \
item '%s'",
*item.ident);
alt get_base_type_def_id(self.inference_context,
item.span,
self_type.ty) {
@ -207,6 +223,12 @@ class CoherenceChecker {
some(associated_trait) {
let def = self.crate_context.tcx.def_map.get
(associated_trait.ref_id);
#debug("(checking implementation) adding impl for trait \
'%s', item '%s'",
ast_map::node_id_to_str(self.crate_context.tcx.items,
associated_trait.ref_id),
*item.ident);
let implementation = self.create_impl_from_item(item);
self.add_trait_method(def_id_of_def(def), implementation);
}
@ -362,7 +384,15 @@ class CoherenceChecker {
self.privileged_types.remove(privileged_type);
}
}
item_impl(_, optional_trait_ref, _, _) {
item_impl(_, associated_traits, _, _) {
// XXX: Accept an array of traits.
let optional_trait_ref;
if associated_traits.len() == 0 {
optional_trait_ref = none;
} else {
optional_trait_ref = some(associated_traits[0]);
}
alt self.base_type_def_ids.find(local_def(item.id)) {
none {
// Nothing to do.

View File

@ -110,7 +110,7 @@ type methoddoc = {
type impldoc = {
item: itemdoc,
trait_ty: option<~str>,
trait_types: ~[~str],
self_ty: option<~str>,
methods: ~[methoddoc]
};

View File

@ -235,7 +235,7 @@ fn impldoc_from_impl(
) -> doc::impldoc {
{
item: itemdoc,
trait_ty: none,
trait_types: ~[],
self_ty: none,
methods: do vec::map(methods) |method| {
{

View File

@ -224,14 +224,16 @@ fn header_name(doc: doc::itemtag) -> ~str {
doc::impltag(doc) {
assert option::is_some(doc.self_ty);
let self_ty = option::get(doc.self_ty);
alt doc.trait_ty {
some(trait_ty) {
#fmt("%s of %s for %s", doc.name(), trait_ty, self_ty)
}
none {
#fmt("%s for %s", doc.name(), self_ty)
}
let mut trait_part = ~"";
for doc.trait_types.eachi |i, trait_type| {
if i == 0 {
trait_part += ~" of ";
} else {
trait_part += ", ";
}
trait_part += trait_type;
}
#fmt("%s%s for %s", doc.name(), trait_part, self_ty)
}
_ {
doc.name()

View File

@ -230,22 +230,22 @@ fn fold_impl(
let srv = fold.ctxt;
let (trait_ty, self_ty) = do astsrv::exec(srv) |ctxt| {
let (trait_types, self_ty) = do astsrv::exec(srv) |ctxt| {
alt ctxt.ast_map.get(doc.id()) {
ast_map::node_item(@{
node: ast::item_impl(_, trait_ty, self_ty, _), _
node: ast::item_impl(_, trait_types, self_ty, _), _
}, _) {
let trait_ty = option::map(trait_ty, |p| {
let trait_types = vec::map(trait_types, |p| {
pprust::path_to_str(p.path)
});
(trait_ty, some(pprust::ty_to_str(self_ty)))
(trait_types, some(pprust::ty_to_str(self_ty)))
}
_ { fail ~"expected impl" }
}
};
{
trait_ty: trait_ty,
trait_types: trait_types,
self_ty: self_ty,
methods: merge_methods(fold.ctxt, doc.id(), doc.methods)
with doc
@ -253,15 +253,15 @@ fn fold_impl(
}
#[test]
fn should_add_impl_trait_ty() {
fn should_add_impl_trait_types() {
let doc = test::mk_doc(~"impl i of j for int { fn a<T>() { } }");
assert doc.cratemod().impls()[0].trait_ty == some(~"j");
assert doc.cratemod().impls()[0].trait_types[0] == ~"j";
}
#[test]
fn should_not_add_impl_trait_ty_if_none() {
fn should_not_add_impl_trait_types_if_none() {
let doc = test::mk_doc(~"impl i for int { fn a() { } }");
assert doc.cratemod().impls()[0].trait_ty == none;
assert vec::len(doc.cratemod().impls()[0].trait_types) == 0;
}
#[test]