mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-03 12:13:43 +00:00
syntax: Parse multiple trait refs in a single implementation
This commit is contained in:
parent
1528256fdc
commit
3ac5b4a86f
@ -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),
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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] = ~[];
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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(*),
|
||||
_},_)) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -110,7 +110,7 @@ type methoddoc = {
|
||||
|
||||
type impldoc = {
|
||||
item: itemdoc,
|
||||
trait_ty: option<~str>,
|
||||
trait_types: ~[~str],
|
||||
self_ty: option<~str>,
|
||||
methods: ~[methoddoc]
|
||||
};
|
||||
|
@ -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| {
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user