Skip to content

Commit

Permalink
Front-end support for default impls in traits.
Browse files Browse the repository at this point in the history
  • Loading branch information
lkuper committed Jul 13, 2012
1 parent d5563d7 commit fc9c4c3
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 68 deletions.
11 changes: 10 additions & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,15 @@ type ty_field = spanned<ty_field_>;
type ty_method = {ident: ident, attrs: ~[attribute],
decl: fn_decl, tps: ~[ty_param], span: span};

#[auto_serialize]
// A trait method is either required (meaning it doesn't have an
// implementation, just a signature) or provided (meaning it has a default
// implementation).
enum trait_method {
required(ty_method),
provided(@method),
}

#[auto_serialize]
enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, }

Expand Down Expand Up @@ -695,7 +704,7 @@ enum item_ {
/* dtor is optional */
option<class_dtor>
),
item_trait(~[ty_param], ~[ty_method]),
item_trait(~[ty_param], ~[trait_method]),
item_impl(~[ty_param], option<@trait_ref> /* trait */,
@ty /* self */, ~[@method]),
item_mac(mac),
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/ast_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,9 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
visit_ty_method: fn@(_ty_m: ty_method) {
},

visit_trait_method: fn@(_ty_m: trait_method) {
},

visit_class_item: fn@(c: @class_member) {
alt c.node {
instance_var(_, _, _, id,_) {
Expand Down
56 changes: 43 additions & 13 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
mtc_rep, mtc_tok, mul, mutability, neg, noreturn, not, pat,
pat_box, pat_enum, pat_ident, pat_lit, pat_range, pat_rec,
pat_tup, pat_uniq, pat_wild, path, private, proto, proto_any,
proto_bare, proto_block, proto_box, proto_uniq, public, pure_fn,
purity, re_anon, re_named, region, rem, ret_style,
return_val, shl, shr, stmt, stmt_decl,
stmt_expr, stmt_semi, subtract, token_tree, trait_ref, tt_delim,
tt_dotdotdot, tt_flat, tt_interpolate, ty, ty_, ty_bot, ty_box,
ty_constr, ty_constr_, ty_constr_arg, ty_field, ty_fn, ty_infer,
ty_mac, ty_method, ty_nil, ty_param, ty_path, ty_ptr, ty_rec,
ty_rptr, ty_tup, ty_u32, ty_uniq, ty_vec, ty_vstore,
proto_bare, proto_block, proto_box, proto_uniq, provided, public,
pure_fn, purity, re_anon, re_named, region, rem, required,
ret_style, return_val, shl, shr, stmt, stmt_decl, stmt_expr,
stmt_semi, subtract, token_tree, trait_method, trait_ref,
tt_delim, tt_dotdotdot, tt_flat, tt_interpolate, ty, ty_, ty_bot,
ty_box, ty_constr, ty_constr_, ty_constr_arg, ty_field, ty_fn,
ty_infer, ty_mac, ty_method, ty_nil, ty_param, ty_path, ty_ptr,
ty_rec, ty_rptr, ty_tup, ty_u32, ty_uniq, ty_vec, ty_vstore,
unchecked_blk, uniq, unsafe_blk, unsafe_fn, variant, view_item,
view_item_, view_item_export, view_item_import, view_item_use,
view_path, view_path_glob, view_path_list, view_path_simple,
Expand Down Expand Up @@ -275,7 +275,7 @@ class parser {
constraints: constrs};
}

fn parse_ty_methods() -> ~[ty_method] {
fn parse_trait_methods() -> ~[trait_method] {
do self.parse_unspanned_seq(token::LBRACE, token::RBRACE,
seq_sep_none()) |p| {
let attrs = p.parse_outer_attributes();
Expand All @@ -284,12 +284,42 @@ class parser {
let ident = p.parse_method_name();
let tps = p.parse_ty_params();
let d = p.parse_ty_fn_decl(pur), fhi = p.last_span.hi;
self.expect(token::SEMI);
{ident: ident, attrs: attrs, decl: {purity: pur with d}, tps: tps,
span: mk_sp(flo, fhi)}
#debug["parse_trait_methods(): trait method ends in %s",
token_to_str(self.reader, self.token)];
alt self.token {
token::SEMI {
self.bump();
required({ident: ident, attrs: attrs,
decl: {purity: pur with d}, tps: tps,
span: mk_sp(flo, fhi)})
}
token::LBRACE {
self.bump();
let (inner_attrs, body) =
self.parse_inner_attrs_and_block(true);
let attrs = vec::append(attrs, inner_attrs);
self.eat(token::RBRACE);
provided(@{ident: ident,
attrs: attrs,
tps: tps,
decl: d,
body: body,
id: self.get_id(),
span: mk_sp(flo, fhi),
self_id: self.get_id(),
// Provided traits methods always public for now
vis: public})
}

_ { self.fatal("expected ';' or '}` \
but found `"
+ token_to_str(self.reader, self.token) + "`");
}
}
}
}


fn parse_mt() -> mt {
let mutbl = self.parse_mutability();
let t = self.parse_ty(false);
Expand Down Expand Up @@ -2127,7 +2157,7 @@ class parser {
let ident = self.parse_ident();
self.parse_region_param();
let tps = self.parse_ty_params();
let meths = self.parse_ty_methods();
let meths = self.parse_trait_methods();
(ident, item_trait(tps, meths), none)
}

Expand Down
10 changes: 9 additions & 1 deletion src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import pp::{break_offset, word, printer,
space, zerobreak, hardbreak, breaks, consistent,
inconsistent, eof};
import diagnostic;
import ast::{required, provided};
import ast_util::operator_prec;
import dvec::{dvec, extensions};
import parse::classify::*;
Expand Down Expand Up @@ -593,7 +594,7 @@ fn print_item(s: ps, &&item: @ast::item) {
print_type_params(s, tps);
word(s.s, " ");
bopen(s);
for methods.each |meth| { print_ty_method(s, meth); }
for methods.each |meth| { print_trait_method(s, meth); }
bclose(s, item.span);
}
ast::item_mac({node: ast::mac_invoc_tt(pth, tts), _}) {
Expand Down Expand Up @@ -647,6 +648,13 @@ fn print_ty_method(s: ps, m: ast::ty_method) {
word(s.s, ";");
}

fn print_trait_method(s: ps, m: ast::trait_method) {
alt m {
required(ty_m) { print_ty_method(s, ty_m) }
provided(m) { print_method(s, m) }
}
}

fn print_method(s: ps, meth: @ast::method) {
hardbreak_if_not_bol(s);
maybe_print_comment(s, meth.span.lo);
Expand Down
24 changes: 23 additions & 1 deletion src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type visitor<E> =
visit_constr: fn@(@path, span, node_id, E, vt<E>),
visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>),
visit_ty_method: fn@(ty_method, E, vt<E>),
visit_trait_method: fn@(trait_method, E, vt<E>),
visit_class_item: fn@(@class_member, E, vt<E>)};

fn default_visitor<E>() -> visitor<E> {
Expand All @@ -81,6 +82,7 @@ fn default_visitor<E>() -> visitor<E> {
visit_constr: |a,b,c,d,e|visit_constr::<E>(a, b, c, d, e),
visit_fn: |a,b,c,d,e,f,g|visit_fn::<E>(a, b, c, d, e, f, g),
visit_ty_method: |a,b,c|visit_ty_method::<E>(a, b, c),
visit_trait_method: |a,b,c|visit_trait_method::<E>(a, b, c),
visit_class_item: |a,b,c|visit_class_item::<E>(a, b, c)};
}

Expand Down Expand Up @@ -160,7 +162,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
item_trait(tps, methods) {
v.visit_ty_params(tps, e, v);
for methods.each |m| {
v.visit_ty_method(m, e, v);
v.visit_trait_method(m, e, v);
}
}
item_mac(m) { visit_mac(m, e, v) }
Expand Down Expand Up @@ -317,6 +319,17 @@ fn visit_ty_method<E>(m: ty_method, e: E, v: vt<E>) {
v.visit_ty(m.decl.output, e, v);
}

fn visit_trait_method<E>(m: trait_method, e: E, v: vt<E>) {
alt m {
required(ty_m) {
v.visit_ty_method(ty_m, e, v)
}
provided(m) {
visit_method_helper(m, e, v)
}
}
}

fn visit_block<E>(b: ast::blk, e: E, v: vt<E>) {
for b.node.view_items.each |vi| { v.visit_view_item(vi, e, v); }
for b.node.stmts.each |s| { v.visit_stmt(s, e, v); }
Expand Down Expand Up @@ -465,6 +478,7 @@ type simple_visitor =
visit_constr: fn@(@path, span, node_id),
visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id),
visit_ty_method: fn@(ty_method),
visit_trait_method: fn@(trait_method),
visit_class_item: fn@(@class_member)};

fn simple_ignore_ty(_t: @ty) {}
Expand All @@ -487,6 +501,7 @@ fn default_simple_visitor() -> simple_visitor {
visit_fn: fn@(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span,
_id: node_id) { },
visit_ty_method: fn@(_m: ty_method) { },
visit_trait_method: fn@(_m: trait_method) { },
visit_class_item: fn@(_c: @class_member) {}
};
}
Expand Down Expand Up @@ -546,6 +561,11 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
f(ty);
visit_ty_method(ty, e, v);
}
fn v_trait_method(f: fn@(trait_method), m: trait_method, &&e: (),
v: vt<()>) {
f(m);
visit_trait_method(m, e, v);
}
fn v_ty_params(f: fn@(~[ty_param]),
ps: ~[ty_param],
&&e: (), v: vt<()>) {
Expand Down Expand Up @@ -596,6 +616,8 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
v_fn(v.visit_fn, a, b, c, d, e, f, g),
visit_ty_method: |a,b,c|
v_ty_method(v.visit_ty_method, a, b, c),
visit_trait_method: |a,b,c|
v_trait_method(v.visit_trait_method, a, b, c),
visit_class_item: |a,b,c|
v_class_item(v.visit_class_item, a, b, c)
});
Expand Down
21 changes: 15 additions & 6 deletions src/rustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -744,12 +744,21 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
encode_name(ebml_w, item.ident);
let mut i = 0u;
for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| {
ebml_w.start_tag(tag_item_trait_method);
encode_name(ebml_w, mty.ident);
encode_type_param_bounds(ebml_w, ecx, ms[i].tps);
encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
encode_family(ebml_w, purity_fn_family(mty.purity));
ebml_w.end_tag();
alt ms[i] {
required(ty_m) {
ebml_w.start_tag(tag_item_trait_method);
encode_name(ebml_w, mty.ident);
encode_type_param_bounds(ebml_w, ecx, ty_m.tps);
encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
encode_family(ebml_w, purity_fn_family(mty.purity));
ebml_w.end_tag();
}
provided(m) {
encode_info_for_method(ecx, ebml_w, path,
should_inline(m.attrs), item.id,
m, m.tps);
}
}
i += 1u;
}
encode_path(ebml_w, path, ast_map::path_name(item.ident));
Expand Down
39 changes: 33 additions & 6 deletions src/rustc/middle/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import syntax::{ast, ast_util, codemap, ast_map};
import syntax::ast::*;
import ast::{ident, fn_ident, def, def_id, node_id};
import ast::{required, provided};
import syntax::ast_util::{local_def, def_id_of_def, new_def_hash,
class_item_ident, path_to_ident};
import pat_util::*;
Expand Down Expand Up @@ -566,12 +567,8 @@ fn visit_item_with_scope(e: @env, i: @ast::item,
}
ast::item_trait(tps, methods) {
v.visit_ty_params(tps, sc, v);
let isc = @cons(scope_method(i.id, tps), sc);
for methods.each |m| {
v.visit_ty_params(m.tps, isc, v);
let msc = @cons(scope_method(i.id, vec::append(tps, m.tps)), sc);
for m.decl.inputs.each |a| { v.visit_ty(a.ty, msc, v); }
v.visit_ty(m.decl.output, msc, v);
visit_trait_method(m, i, tps, sc, v);
}
}
ast::item_class(tps, traits, members, ctor, m_dtor) {
Expand Down Expand Up @@ -618,6 +615,27 @@ fn visit_item_with_scope(e: @env, i: @ast::item,
e.resolve_unexported = old_resolve_unexported;
}

fn visit_trait_method(m: trait_method, i: @ast::item,
tps: ~[ast::ty_param], sc: scopes,
v: vt<scopes>) {
alt m {
required(ty_m) {
let isc = @cons(scope_method(i.id, tps), sc);
v.visit_ty_params(ty_m.tps, isc, v);
let msc = @cons(scope_method(i.id, vec::append(tps, ty_m.tps)), sc);
for ty_m.decl.inputs.each |a| { v.visit_ty(a.ty, msc, v); }
v.visit_ty(ty_m.decl.output, msc, v);
}
provided(m) {
v.visit_ty_params(m.tps, sc, v);
let msc = @cons(scope_method(m.self_id, vec::append(tps, m.tps)),
sc);
v.visit_fn(visit::fk_method(m.ident, ~[], m),
m.decl, m.body, m.span, m.id, msc, v);
}
}
}

fn visit_foreign_item_with_scope(ni: @ast::foreign_item, &&sc: scopes,
v: vt<scopes>) {
visit::visit_foreign_item(ni, @cons(scope_foreign_item(ni), sc), v);
Expand Down Expand Up @@ -1785,7 +1803,16 @@ fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) {
"type parameter");
}
ast::item_trait(_, methods) {
ensure_unique(*e, i.span, methods, |m| m.ident,
ensure_unique(*e, i.span, methods, |m| {
alt m {
required(ty_m) {
ty_m.ident
}
provided(m) {
m.ident
}
}
},
"method");
}
ast::item_impl(_, _, _, methods) {
Expand Down
Loading

0 comments on commit fc9c4c3

Please sign in to comment.