diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 5e5185bf7eeac..d795d6c236324 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -296,6 +296,7 @@ tag expr_ { expr_check(@expr, ann); expr_port(ann); expr_chan(@expr, ann); + expr_anon_obj(anon_obj, vec[ty_param], obj_def_ids, ann); } type lit = spanned[lit_]; @@ -371,6 +372,13 @@ type _obj = rec(vec[obj_field] fields, vec[@method] methods, option::t[@method] dtor); +type anon_obj = rec( + // New fields and methods, if they exist. + option::t[vec[obj_field]] fields, + vec[@method] methods, + // with_obj: the original object being extended, if it exists. + option::t[ident] with_obj); + type _mod = rec(vec[@view_item] view_items, vec[@item] items); diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 520090a52c797..767e7e932f179 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -773,6 +773,59 @@ fn parse_bottom_expr(parser p) -> @ast::expr { some(token::COMMA), pf, hi, p); ex = ast::expr_vec(es, mut, p.get_ann()); + } else if (eat_word(p, "obj")) { + // Anonymous object + + // FIXME: Can anonymous objects have ty params? + auto ty_params = parse_ty_params(p); + + // Only make people type () if they're actually adding new fields + let option::t[vec[ast::obj_field]] fields = + none[vec[ast::obj_field]]; + if (p.peek() == token::LPAREN) { + auto pf = parse_obj_field; + hi = p.get_hi_pos(); + expect(p, token::LPAREN); + + + fields = some[vec[ast::obj_field]] + (parse_seq_to_end[ast::obj_field] + (token::RPAREN, + some(token::COMMA), + pf, hi, p)); + } + + let vec[@ast::method] meths = vec(); + let option::t[ast::ident] with_obj = none[ast::ident]; + + expect(p, token::LBRACE); + + while (p.peek() != token::RBRACE) { + if (eat_word(p, "with")) { + with_obj = some[ast::ident](parse_ident(p)); + } else { + _vec::push[@ast::method](meths, + parse_method(p)); + } + } + + hi = p.get_hi_pos(); + expect(p, token::RBRACE); + + // fields and methods may be *additional* or *overriding* fields + // and methods if there's a with_obj, or they may be the *only* + // fields and methods if there's no with_obj. + + // We don't need to pull ".node" out of fields because it's not a + // "spanned". + let ast::anon_obj ob = rec(fields=fields, + methods=meths, + with_obj=with_obj); + + auto odid = rec(ty=p.next_def_id(), ctor=p.next_def_id()); + + ex = ast::expr_anon_obj(ob, ty_params, odid, p.get_ann()); + } else if (eat_word(p, "rec")) { expect(p, token::LPAREN); auto fields = vec(parse_field(p)); @@ -795,7 +848,6 @@ fn parse_bottom_expr(parser p) -> @ast::expr { } else { unexpected(p, p.peek()); } - } ex = ast::expr_rec(fields, base, p.get_ann()); diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs index 5af85f14cbbc3..7a9a67ddfcaef 100644 --- a/src/comp/middle/fold.rs +++ b/src/comp/middle/fold.rs @@ -39,7 +39,8 @@ type ast_fold[ENV] = @rec ( // Path fold: - (fn(&ENV e, &span sp, &ast::path_ p) -> path) fold_path, + (fn(&ENV e, &span sp, &ast::path_ p) + -> path) fold_path, // Type folds. (fn(&ENV e, &span sp) -> @ty) fold_ty_nil, @@ -56,10 +57,10 @@ type ast_fold[ENV] = (fn(&ENV e, &span sp, &vec[mt] elts) -> @ty) fold_ty_tup, (fn(&ENV e, &span sp, - &vec[ast::ty_field] elts) -> @ty) fold_ty_rec, + &vec[ast::ty_field] elts) -> @ty) fold_ty_rec, (fn(&ENV e, &span sp, - &vec[ast::ty_method] meths) -> @ty) fold_ty_obj, + &vec[ast::ty_method] meths) -> @ty) fold_ty_obj, (fn(&ENV e, &span sp, ast::proto proto, @@ -78,7 +79,7 @@ type ast_fold[ENV] = &ann a) -> @expr) fold_expr_vec, (fn(&ENV e, &span sp, - &vec[ast::elt] es, &ann a) -> @expr) fold_expr_tup, + &vec[ast::elt] es, &ann a) -> @expr) fold_expr_tup, (fn(&ENV e, &span sp, &vec[ast::field] fields, @@ -110,7 +111,7 @@ type ast_fold[ENV] = &ann a) -> @expr) fold_expr_unary, (fn(&ENV e, &span sp, - &@ast::lit, &ann a) -> @expr) fold_expr_lit, + &@ast::lit, &ann a) -> @expr) fold_expr_lit, (fn(&ENV e, &span sp, &@ast::expr e, &@ast::ty ty, @@ -186,10 +187,10 @@ type ast_fold[ENV] = (fn(&ENV e, &span sp, &ann a) -> @expr) fold_expr_cont, (fn(&ENV e, &span sp, - &option::t[@expr] rv, &ann a) -> @expr) fold_expr_ret, + &option::t[@expr] rv, &ann a) -> @expr) fold_expr_ret, (fn(&ENV e, &span sp, - &option::t[@expr] rv, &ann a) -> @expr) fold_expr_put, + &option::t[@expr] rv, &ann a) -> @expr) fold_expr_put, (fn(&ENV e, &span sp, &@expr e, &ann a) -> @expr) fold_expr_be, @@ -209,10 +210,15 @@ type ast_fold[ENV] = (fn(&ENV e, &span sp, &@expr e, &ann a) -> @expr) fold_expr_chan, + (fn(&ENV e, &span sp, + &ast::anon_obj ob, + &vec[ast::ty_param] tps, + &ast::obj_def_ids odid, + &ann a) -> @expr) fold_expr_anon_obj, // Decl folds. (fn(&ENV e, &span sp, - &@ast::local local) -> @decl) fold_decl_local, + &@ast::local local) -> @decl) fold_decl_local, (fn(&ENV e, &span sp, &@item item) -> @decl) fold_decl_item, @@ -223,7 +229,7 @@ type ast_fold[ENV] = &ann a) -> @pat) fold_pat_wild, (fn(&ENV e, &span sp, - &@ast::lit lit, &ann a) -> @pat) fold_pat_lit, + &@ast::lit lit, &ann a) -> @pat) fold_pat_lit, (fn(&ENV e, &span sp, &ident i, &def_id did, &ann a) -> @pat) fold_pat_bind, @@ -259,10 +265,11 @@ type ast_fold[ENV] = &def_id id, &ann a) -> @native_item) fold_native_item_fn, (fn(&ENV e, &span sp, &ident ident, - &ast::_mod m, &def_id id) -> @item) fold_item_mod, + &ast::_mod m, &def_id id) -> @item) fold_item_mod, (fn(&ENV e, &span sp, &ident ident, - &ast::native_mod m, &def_id id) -> @item) fold_item_native_mod, + &ast::native_mod m, &def_id id) + -> @item) fold_item_native_mod, (fn(&ENV e, &span sp, &ident ident, &@ty t, &vec[ast::ty_param] ty_params, @@ -279,13 +286,14 @@ type ast_fold[ENV] = (fn(&ENV e, &span sp, &ident ident, &ast::_obj ob, &vec[ast::ty_param] ty_params, - &ast::obj_def_ids odid, &ann a) -> @item) fold_item_obj, + &ast::obj_def_ids odid, &ann a) + -> @item) fold_item_obj, // View Item folds. (fn(&ENV e, &span sp, &ident ident, &vec[@meta_item] meta_items, &def_id id, - &option::t[int]) -> @view_item) fold_view_item_use, + &option::t[int]) -> @view_item) fold_view_item_use, (fn(&ENV e, &span sp, &ident i, &vec[ident] idents, @@ -301,26 +309,33 @@ type ast_fold[ENV] = (fn(&ENV e, &fn_decl decl, ast::proto proto, - &block body) -> ast::_fn) fold_fn, + &block body) -> ast::_fn) fold_fn, (fn(&ENV e, &vec[arg] inputs, &@ty output, - &purity p) -> ast::fn_decl) fold_fn_decl, + &purity p) -> ast::fn_decl) fold_fn_decl, - (fn(&ENV e, &ast::_mod m) -> ast::_mod) fold_mod, + (fn(&ENV e, &ast::_mod m) -> ast::_mod) fold_mod, - (fn(&ENV e, &ast::native_mod m) -> ast::native_mod) fold_native_mod, + (fn(&ENV e, &ast::native_mod m) + -> ast::native_mod) fold_native_mod, (fn(&ENV e, &span sp, &vec[@ast::crate_directive] cdirs, - &ast::_mod m) -> @ast::crate) fold_crate, + &ast::_mod m) -> @ast::crate) fold_crate, (fn(&ENV e, &vec[ast::obj_field] fields, &vec[@ast::method] methods, &option::t[@ast::method] dtor) - -> ast::_obj) fold_obj, + -> ast::_obj) fold_obj, + + (fn(&ENV e, + &option::t[vec[ast::obj_field]] fields, + &vec[@ast::method] methods, + &option::t[ident] with_obj) + -> ast::anon_obj) fold_anon_obj, // Env updates. (fn(&ENV e, &@ast::crate c) -> ENV) update_env_for_crate, @@ -828,6 +843,12 @@ fn fold_expr[ENV](&ENV env, &ast_fold[ENV] fld, &@expr e) -> @expr { auto t2 = fld.fold_ann(env_, t); ret fld.fold_expr_chan(env_, e.span, ee, t2); } + + case (ast::expr_anon_obj(?ob, ?tps, ?odid, ?t)) { + auto ee = fold_anon_obj(env_, fld, ob); + auto t2 = fld.fold_ann(env_, t); + ret fld.fold_expr_anon_obj(env_, e.span, ee, tps, odid, t2); + } } fail; @@ -930,7 +951,6 @@ fn fold_method[ENV](&ENV env, &ast_fold[ENV] fld, ret @rec(node=rec(meth=meth with m.node) with *m); } - fn fold_obj[ENV](&ENV env, &ast_fold[ENV] fld, &ast::_obj ob) -> ast::_obj { let vec[ast::obj_field] fields = vec(); @@ -962,6 +982,49 @@ fn fold_obj[ENV](&ENV env, &ast_fold[ENV] fld, &ast::_obj ob) -> ast::_obj { ret fld.fold_obj(env, fields, meths, dtor); } +fn fold_anon_obj[ENV](&ENV env, &ast_fold[ENV] fld, &ast::anon_obj ob) + -> ast::anon_obj { + + // Fields + let option::t[vec[ast::obj_field]] fields = none[vec[ast::obj_field]]; + alt (ob.fields) { + case (none[vec[ast::obj_field]]) { } + case (some[vec[ast::obj_field]](?v)) { + let vec[ast::obj_field] fields = vec(); + for (ast::obj_field f in v) { + fields += vec(fold_obj_field(env, fld, f)); + } + } + } + + // with_obj + let option::t[ast::ident] with_obj = none[ast::ident]; + alt (ob.with_obj) { + case (none[ast::ident]) { } + case (some[ast::ident](?i)) { + with_obj = some[ast::ident](i); + } + } + + // Methods + let vec[@ast::method] meths = vec(); + let vec[ast::ty_param] tp = vec(); + for (@ast::method m in ob.methods) { + // Fake-up an ast::item for this method. + // FIXME: this is kinda awful. Maybe we should reformulate + // the way we store methods in the AST? + let @ast::item i = @rec(node=ast::item_fn(m.node.ident, + m.node.meth, + tp, + m.node.id, + m.node.ann), + span=m.span); + let ENV _env = fld.update_env_for_item(env, i); + _vec::push[@ast::method](meths, fold_method(_env, fld, m)); + } + ret fld.fold_anon_obj(env, fields, meths, with_obj); +} + fn fold_view_item[ENV](&ENV env, &ast_fold[ENV] fld, &@view_item vi) -> @view_item { @@ -1410,6 +1473,14 @@ fn identity_fold_expr_chan[ENV](&ENV e, &span sp, &@expr x, ret @respan(sp, ast::expr_chan(x, a)); } +fn identity_fold_expr_anon_obj[ENV](&ENV e, &span sp, + &ast::anon_obj ob, + &vec[ast::ty_param] tps, + &ast::obj_def_ids odid, + &ann a) -> @expr { + ret @respan(sp, ast::expr_anon_obj(ob, tps, odid, a)); +} + // Decl identities. fn identity_fold_decl_local[ENV](&ENV e, &span sp, @@ -1584,6 +1655,12 @@ fn identity_fold_obj[ENV](&ENV e, ret rec(fields=fields, methods=methods, dtor=dtor); } +fn identity_fold_anon_obj[ENV](&ENV e, + &option::t[vec[ast::obj_field]] fields, + &vec[@ast::method] methods, + &option::t[ident] with_obj) -> ast::anon_obj { + ret rec(fields=fields, methods=methods, with_obj=with_obj); +} // Env update identities. @@ -1707,6 +1784,9 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] { fold_expr_port = bind identity_fold_expr_port[ENV](_,_,_), fold_expr_chan = bind identity_fold_expr_chan[ENV](_,_,_,_), + fold_expr_anon_obj + = bind identity_fold_expr_anon_obj[ENV](_,_,_,_,_,_), + fold_decl_local = bind identity_fold_decl_local[ENV](_,_,_), fold_decl_item = bind identity_fold_decl_item[ENV](_,_,_), @@ -1746,6 +1826,7 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] { fold_native_mod = bind identity_fold_native_mod[ENV](_,_), fold_crate = bind identity_fold_crate[ENV](_,_,_,_), fold_obj = bind identity_fold_obj[ENV](_,_,_,_), + fold_anon_obj = bind identity_fold_anon_obj[ENV](_,_,_,_), update_env_for_crate = bind identity_update_env_for_crate[ENV](_,_), update_env_for_item = bind identity_update_env_for_item[ENV](_,_), diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 4f1636d4b50ef..fdc32f1108e15 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -2885,10 +2885,14 @@ fn iter_sequence(@block_ctxt cx, auto et = ty::mk_mach(cx.fcx.lcx.ccx.tcx, common::ty_u8); ret iter_sequence_body(cx, v, et, f, true); } - case (_) { fail; } + case (_) { + + cx.fcx.lcx.ccx.sess.bug("unexpected type in " + + "trans::iter_sequence: " + + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, t)); + fail; + } } - cx.fcx.lcx.ccx.sess.bug("bad type in trans::iter_sequence"); - fail; } fn lazily_emit_all_tydesc_glue(&@block_ctxt cx, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 5957c1fdf3683..86b53a9a04bb0 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1710,6 +1710,7 @@ fn expr_ann(&@ast::expr e) -> ast::ann { case (ast::expr_check(_,?a)) { ret a; } case (ast::expr_port(?a)) { ret a; } case (ast::expr_chan(_,?a)) { ret a; } + case (ast::expr_anon_obj(_,_,_,?a)) { ret a; } case (ast::expr_break(?a)) { ret a; } case (ast::expr_cont(?a)) { ret a; } case (ast::expr_self_method(_, ?a)) { ret a; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 4a8f597471642..c94e077d31fb4 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -762,7 +762,18 @@ mod Collect { } } } + + // Anonymous objects are expressions, not items, but they're enough like + // items that we're going to include them in this fold. + fn fold_expr_anon_obj(&@env e, &span sp, + &ast::anon_obj ob, &vec[ast::ty_param] tps, + &ast::obj_def_ids odid, &ast::ann a) -> @ast::expr { + // TODO: Somewhere in here we need to push some stuff onto a vector. + + auto expr_anon_obj = ast::expr_anon_obj(ob, tps, odid, a); + ret @fold::respan[ast::expr_](sp, expr_anon_obj); + } fn fold_item_obj(&@env e, &span sp, &ast::ident i, &ast::_obj ob, &vec[ast::ty_param] ty_params, @@ -895,7 +906,8 @@ mod Collect { bind fold_native_item_fn(_,_,_,_,_,_,_,_), fold_item_obj = bind fold_item_obj(_,_,_,_,_,_,_), fold_item_ty = bind fold_item_ty(_,_,_,_,_,_,_), - fold_item_tag = bind fold_item_tag(_,_,_,_,_,_,_) + fold_item_tag = bind fold_item_tag(_,_,_,_,_,_,_), + fold_expr_anon_obj = bind fold_expr_anon_obj(_,_,_,_,_,_) with *fld_2); auto crate_ = fold::fold_crate[@env](e, fld_2, crate); ret tup(crate_, type_cache, id_to_ty_item, ntt); @@ -2079,7 +2091,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) -> @ast::expr { auto e = ast::expr_path(pth, triv_ann(ast::ann_tag(old_ann), tpt._1)); - write_type_only(fcx.ccx.node_types, ast::ann_tag(old_ann), tpt._1); + write_type_only(fcx.ccx.node_types, + ast::ann_tag(old_ann), tpt._1); ret @fold::respan[ast::expr_](expr.span, e); } @@ -2540,20 +2553,23 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) -> @ast::expr { auto t = ty::mk_nil(fcx.ccx.tcx); let ty::t this_obj_ty; - // Grab the type of the current object auto this_obj_id = fcx.ccx.this_obj; alt (this_obj_id) { + // If we're inside a current object, grab its type. case (some[ast::def_id](?def_id)) { this_obj_ty = ty::lookup_item_type(fcx.ccx.sess, fcx.ccx.tcx, fcx.ccx.type_cache, def_id)._1; } - case (_) { fail; } + // Otherwise, we should be able to look up the object we're + // "with". + case (_) { + // TODO. + + fail; + } } - - // Grab this method's type out of the current object type - - // this_obj_ty is an ty::t + // Grab this method's type out of the current object type. alt (struct(fcx.ccx.tcx, this_obj_ty)) { case (ty::ty_obj(?methods)) { for (ty::method method in methods) { diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 8a3c72f43e431..fbf3060e96801 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -433,6 +433,8 @@ fn walk_expr(&ast_visitor v, @ast::expr e) { case (ast::expr_chan(?x, _)) { walk_expr(v, x); } + + case (ast::expr_anon_obj(_,_,_,_)) { } } v.visit_expr_post(e); } diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 0bdd5c8379fa0..c7c4fba36d3d0 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -690,6 +690,11 @@ fn print_expr(ps s, &@ast::expr expr) { print_expr(s, expr); pclose(s); } + + case (ast::expr_anon_obj(_,_,_,_)) { + wrd(s.s, "obj"); + // TODO + } } end(s.s); } diff --git a/src/test/run-pass/anon-objs.rs b/src/test/run-pass/anon-objs.rs new file mode 100644 index 0000000000000..14279db2e58cd --- /dev/null +++ b/src/test/run-pass/anon-objs.rs @@ -0,0 +1,33 @@ +// xfail-boot +// xfail-stage0 +// xfail-stage1 +use std; + +fn main() { + + obj a() { + fn foo() -> int { + ret 2; + } + fn bar() -> int { + ret self.foo(); + } + } + + auto my_a = a(); + + // Extending an object with a new method + auto my_b = obj { + fn baz() -> int { + ret self.foo(); + } + with my_a + }; + + // Extending an object with a new field + auto my_c = obj(int quux) { with my_a } ; + + // Should this be legal? + auto my_d = obj() { with my_a } ; + +}