diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5f2a5b2accb7d3b20a03eeca1c4fe7376a46d925..a356e716a9a9f2286559aa75f1952ad9d9d147f2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -318,6 +318,8 @@ enum expr_ { // easily type this (a function returning nil on the inside but bool on // the outside). expr_loop_body(@expr), + // Like expr_loop_body but for 'do' blocks + expr_do_body(@expr), expr_block(blk), /* diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0d5966db4f57b8edfee8f9e5ffcfcb6d8b529651..7ddbfb52e945ba3018bc892509699f922acbe1fc 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -415,6 +415,7 @@ fn fold_field_(field: field, fld: ast_fold) -> field { } expr_unary(binop, ohs) { expr_unary(binop, fld.fold_expr(ohs)) } expr_loop_body(f) { expr_loop_body(fld.fold_expr(f)) } + expr_do_body(f) { expr_do_body(fld.fold_expr(f)) } expr_lit(_) { copy e } expr_cast(expr, ty) { expr_cast(fld.fold_expr(expr), ty) } expr_addr_of(m, ohs) { expr_addr_of(m, fld.fold_expr(ohs)) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 08eaa7792917bc6ad10b88379873902bb94dbfc6..45badde00169c3cc008aa7e90d03487bd45cf084 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -772,6 +772,8 @@ fn parse_bottom_expr() -> pexpr { ret pexpr(self.parse_if_expr()); } else if self.eat_keyword("for") { ret pexpr(self.parse_for_expr()); + } else if self.eat_keyword("do") { + ret pexpr(self.parse_do_expr()); } else if self.eat_keyword("while") { ret pexpr(self.parse_while_expr()); } else if self.eat_keyword("loop") { @@ -1312,6 +1314,23 @@ fn parse_for_expr() -> @expr { } } + fn parse_do_expr() -> @expr { + let lo = self.last_span; + let call = self.parse_expr_res(RESTRICT_STMT_EXPR); + alt call.node { + expr_call(f, args, true) { + let b_arg = vec::last(args); + let last = self.mk_expr(b_arg.span.lo, b_arg.span.hi, + expr_do_body(b_arg)); + @{node: expr_call(f, vec::init(args) + [last], true) + with *call} + } + _ { + self.span_fatal(lo, "`do` must be followed by a block call"); + } + } + } + fn parse_while_expr() -> @expr { let lo = self.last_span.lo; let cond = self.parse_expr(); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 7fb6165f7f12cc847b6bb84c36c5915f88eda8e9..ec14778dc02de04034937eb418a8f4c9f7c7c911 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -287,7 +287,7 @@ fn restricted_keyword_table() -> hashmap { "assert", "be", "break", "check", "claim", "class", "const", "cont", "copy", "crust", - "drop", + "do", "drop", "else", "enum", "export", "fail", "false", "fn", "for", "if", "iface", "impl", "import", diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 43b498eae62f44b0c50f98e33de0007fe7f56514..e0e30dc72fcc6dd940ef4a674f62e8b026394154 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1048,6 +1048,9 @@ fn print_opt(s: ps, expr: option<@ast::expr>) { ast::expr_loop_body(body) { print_expr(s, body); } + ast::expr_do_body(body) { + print_expr(s, body); + } ast::expr_block(blk) { // containing cbox, will be closed by print-block at } cbox(s, indent_unit); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a7db0fe085130d1c75f84225b75a4f91119092ed..4a68850674d7b1c71b6ceac7eb38bd1138c71faf 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -382,7 +382,8 @@ fn visit_expr(ex: @expr, e: E, v: vt) { for args.each {|eo| visit_expr_opt(eo, e, v); } } expr_binary(_, a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); } - expr_addr_of(_, x) | expr_unary(_, x) | expr_loop_body(x) | + expr_addr_of(_, x) | expr_unary(_, x) | + expr_loop_body(x) | expr_do_body(x) | expr_check(_, x) | expr_assert(x) { v.visit_expr(x, e, v); } diff --git a/src/rustc/middle/borrowck/categorization.rs b/src/rustc/middle/borrowck/categorization.rs index 4a6f8c15147cb7701292250cdd5dd858e1fb22ea..b8ec0f9c2f1f0980395d607a7fcd162774cfc70e 100644 --- a/src/rustc/middle/borrowck/categorization.rs +++ b/src/rustc/middle/borrowck/categorization.rs @@ -174,7 +174,7 @@ fn cat_expr(expr: @ast::expr) -> cmt { ast::expr_swap(*) | ast::expr_move(*) | ast::expr_assign(*) | ast::expr_assign_op(*) | ast::expr_fn(*) | ast::expr_fn_block(*) | ast::expr_assert(*) | ast::expr_check(*) | ast::expr_ret(*) | - ast::expr_loop_body(*) | ast::expr_unary(*) | + ast::expr_loop_body(*) | ast::expr_do_body(*) | ast::expr_unary(*) | ast::expr_copy(*) | ast::expr_cast(*) | ast::expr_fail(*) | ast::expr_vstore(*) | ast::expr_vec(*) | ast::expr_tup(*) | ast::expr_if_check(*) | ast::expr_if(*) | ast::expr_log(*) | diff --git a/src/rustc/middle/liveness.rs b/src/rustc/middle/liveness.rs index 51d2285d6fea53a304c75c40da66a406c9fa2300..981ec4d63e359e96ca0d52c8668243245c26c569 100644 --- a/src/rustc/middle/liveness.rs +++ b/src/rustc/middle/liveness.rs @@ -412,7 +412,8 @@ fn visit_expr(expr: @expr, &&self: @ir_maps, vt: vt<@ir_maps>) { expr_vec(*) | expr_rec(*) | expr_call(*) | expr_tup(*) | expr_bind(*) | expr_new(*) | expr_log(*) | expr_binary(*) | expr_assert(*) | expr_check(*) | expr_addr_of(*) | expr_copy(*) | - expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) | + expr_loop_body(*) | expr_do_body(*) | expr_cast(*) | + expr_unary(*) | expr_fail(*) | expr_break | expr_cont | expr_lit(_) | expr_ret(*) | expr_block(*) | expr_move(*) | expr_assign(*) | expr_swap(*) | expr_assign_op(*) | expr_mac(*) { @@ -1054,6 +1055,7 @@ fn propagate_through_expr(expr: @expr, succ: live_node) -> live_node { expr_addr_of(_, e) | expr_copy(e) | expr_loop_body(e) | + expr_do_body(e) | expr_cast(e, _) | expr_unary(_, e) { self.propagate_through_expr(e, succ) @@ -1406,7 +1408,8 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) { expr_vec(*) | expr_rec(*) | expr_tup(*) | expr_bind(*) | expr_new(*) | expr_log(*) | expr_binary(*) | expr_assert(*) | expr_check(*) | expr_copy(*) | - expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) | + expr_loop_body(*) | expr_do_body(*) | + expr_cast(*) | expr_unary(*) | expr_fail(*) | expr_ret(*) | expr_break | expr_cont | expr_lit(_) | expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) { visit::visit_expr(expr, self, vt); diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 69280657a0d00d12cd83ac2215d2c023a2764a15..d6520b45d4a03f41bdad9d5be1c2a9af4f727d95 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -3622,6 +3622,9 @@ fn unrooted(bcx: block, e: @ast::expr, dest: dest) -> block { ast::expr_loop_body(blk) { ret trans_loop_body(bcx, e, none, dest); } + ast::expr_do_body(blk) { + ret trans_expr(bcx, blk, dest); + } ast::expr_bind(f, args) { ret closure::trans_bind( bcx, f, args, e.id, dest); diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs index 03cd889e480492d5985a47945ec0eab5cc95658c..e42028fbdf6c20c3a8d1651b93bb911af0995ed6 100644 --- a/src/rustc/middle/trans/type_use.rs +++ b/src/rustc/middle/trans/type_use.rs @@ -223,7 +223,8 @@ fn mark_for_expr(cx: ctx, e: @expr) { expr_while(_, _) | expr_fail(_) | expr_break | expr_cont | expr_unary(_, _) | expr_lit(_) | expr_assert(_) | expr_check(_, _) | expr_if_check(_, _, _) | expr_mac(_) | expr_addr_of(_, _) | - expr_ret(_) | expr_loop(_) | expr_bind(_, _) | expr_loop_body(_) {} + expr_ret(_) | expr_loop(_) | expr_bind(_, _) | + expr_loop_body(_) | expr_do_body(_) {} } } diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs index a51a4f72a0e84a5ba14080845580d4fc4022eb44..110989a6a7933cf2e41208ac6d1616b6209691d2 100644 --- a/src/rustc/middle/tstate/pre_post_conditions.rs +++ b/src/rustc/middle/tstate/pre_post_conditions.rs @@ -364,7 +364,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { } else { find_pre_post_exprs(fcx, [l, r], e.id); } } expr_addr_of(_, x) | expr_cast(x, _) | expr_unary(_, x) | - expr_loop_body(x) | expr_assert(x) | expr_copy(x) { + expr_loop_body(x) | expr_do_body(x) | expr_assert(x) | expr_copy(x) { find_pre_post_expr(fcx, x); copy_pre_post(fcx.ccx, e.id, x); } diff --git a/src/rustc/middle/tstate/states.rs b/src/rustc/middle/tstate/states.rs index 2b39288152b175be6b84e3d2e63895d297f5d8bb..dfc511122a659dfda88964fa9a81502bab3090b5 100644 --- a/src/rustc/middle/tstate/states.rs +++ b/src/rustc/middle/tstate/states.rs @@ -486,7 +486,8 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool { } ret changed | set_poststate_ann(fcx.ccx, e.id, a_post); } - expr_field(x, _, _) | expr_loop_body(x) | expr_unary(_, x) | + expr_field(x, _, _) | expr_loop_body(x) | expr_do_body(x) | + expr_unary(_, x) | expr_addr_of(_, x) | expr_assert(x) | expr_cast(x, _) | expr_copy(x) { ret find_pre_post_state_sub(fcx, pres, x, e.id, none); diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index f547fb5d50cce5f6254fa8070456b3a584f4df19..0ca184e5916577ae1064ae0114771d75f8407037 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -1364,6 +1364,32 @@ fn check_expr_fn(fcx: @fn_ctxt, } } } + ast::expr_do_body(b) { + let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get(); + let (inner_ty, proto) = alt expected_sty { + ty::ty_fn(fty) { + (ty::mk_fn(tcx, fty), fty.proto) + } + _ { + tcx.sess.span_fatal(expr.span, "a do function's last argument \ + should be of function type"); + } + }; + alt check b.node { + ast::expr_fn_block(decl, body, cap_clause) { + check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty)); + demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b)); + capture::check_capture_clause(tcx, b.id, cap_clause); + } + } + let block_ty = structurally_resolved_type( + fcx, expr.span, fcx.node_ty(b.id)); + alt check ty::get(block_ty).struct { + ty::ty_fn(fty) { + fcx.write_ty(expr.id, ty::mk_fn(tcx, fty)); + } + } + } ast::expr_block(b) { // If this is an unchecked block, turn off purity-checking bot = check_block(fcx, b); diff --git a/src/test/compile-fail/do1.rs b/src/test/compile-fail/do1.rs new file mode 100644 index 0000000000000000000000000000000000000000..76a10c6d2f161db32e70eb31f72bba197485004f --- /dev/null +++ b/src/test/compile-fail/do1.rs @@ -0,0 +1,3 @@ +fn main() { + let x = do y; //! ERROR: `do` must be followed by a block call +} diff --git a/src/test/compile-fail/do2.rs b/src/test/compile-fail/do2.rs new file mode 100644 index 0000000000000000000000000000000000000000..8950e69e0091aefed10da60c8ec2c070edc18492 --- /dev/null +++ b/src/test/compile-fail/do2.rs @@ -0,0 +1,5 @@ +fn f(f: fn@(int) -> bool) -> bool { f(10) } + +fn main() { + assert do f() { |i| i == 10 } == 10; //! ERROR: expected `bool` but found `int` +} diff --git a/src/test/run-pass/do1.rs b/src/test/run-pass/do1.rs new file mode 100644 index 0000000000000000000000000000000000000000..af173d62d6a316a3d0c58f7e9ed154be7b419c41 --- /dev/null +++ b/src/test/run-pass/do1.rs @@ -0,0 +1,5 @@ +fn f(f: fn@(int)) { f(10) } + +fn main() { + do f() { |i| assert i == 10 } +} diff --git a/src/test/run-pass/do2.rs b/src/test/run-pass/do2.rs new file mode 100644 index 0000000000000000000000000000000000000000..c8028f806dacea1bca7449f86a0708455751a76d --- /dev/null +++ b/src/test/run-pass/do2.rs @@ -0,0 +1,5 @@ +fn f(f: fn@(int) -> int) -> int { f(10) } + +fn main() { + assert do f() { |i| i } == 10; +} diff --git a/src/test/run-pass/do3.rs b/src/test/run-pass/do3.rs new file mode 100644 index 0000000000000000000000000000000000000000..c4796eb20709bfcb60ec494334f17da981ec699d --- /dev/null +++ b/src/test/run-pass/do3.rs @@ -0,0 +1,5 @@ +fn f(f: fn@(int) -> int) -> int { f(10) } + +fn main() { + assert do f { |i| i } == 10; +}