diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6c0b5a2e8b1..9419b9f647e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -243,7 +243,12 @@ type stmt = spanned; #[auto_serialize] enum stmt_ { stmt_decl(@decl, node_id), + + // expr without trailing semi-colon (must have unit type): stmt_expr(@expr, node_id), + + // expr with trailing semi-colon (may have any type): + stmt_semi(@expr, node_id), } #[auto_serialize] diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 568f00b0dfb..c6fb9349ad5 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -38,6 +38,7 @@ pure fn stmt_id(s: stmt) -> node_id { alt s.node { stmt_decl(_, id) { id } stmt_expr(_, id) { id } + stmt_semi(_, id) { id } } } diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs index 8685bce4c1b..d2d685f8f7d 100644 --- a/src/libsyntax/ext/auto_serialize.rs +++ b/src/libsyntax/ext/auto_serialize.rs @@ -206,7 +206,7 @@ impl helpers for ext_ctxt { } fn stmt(expr: @ast::expr) -> @ast::stmt { - @{node: ast::stmt_expr(expr, self.next_id()), + @{node: ast::stmt_semi(expr, self.next_id()), span: expr.span} } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fd17403b695..c949c2e17aa 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -315,6 +315,7 @@ fn noop_fold_stmt(s: stmt_, fld: ast_fold) -> stmt_ { ret alt s { stmt_decl(d, nid) { stmt_decl(fld.fold_decl(d), fld.new_id(nid)) } stmt_expr(e, nid) { stmt_expr(fld.fold_expr(e), fld.new_id(nid)) } + stmt_semi(e, nid) { stmt_semi(fld.fold_expr(e), fld.new_id(nid)) } }; } diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index 4fcb761fa06..9b36b77407e 100644 --- a/src/libsyntax/parse/classify.rs +++ b/src/libsyntax/parse/classify.rs @@ -27,6 +27,9 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool { ast::stmt_expr(e, _) { ret expr_requires_semi_to_be_stmt(e); } + ast::stmt_semi(e, _) { + ret false; + } } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 97185b6dfb9..747ca07bee5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1848,7 +1848,7 @@ class parser { token::SEMI { self.bump(); push(stmts, - @{node: stmt_expr(e, stmt_id) with *stmt}); + @{node: stmt_semi(e, stmt_id) with *stmt}); } token::RBRACE { expr = some(e); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 171ad240635..5f2aada9fc6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -682,9 +682,11 @@ fn print_stmt(s: ps, st: ast::stmt) { ast::stmt_expr(expr, _) { space_if_not_bol(s); print_expr(s, expr); - if expr_requires_semi_to_be_stmt(expr) { - word(s.s, ";"); - } + } + ast::stmt_semi(expr, _) { + space_if_not_bol(s); + print_expr(s, expr); + word(s.s, ";"); } } if parse::classify::stmt_ends_with_semi(st) { word(s.s, ";"); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index d2e5b1d1f21..48f2e57de1c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -320,6 +320,7 @@ fn visit_stmt(s: @stmt, e: E, v: vt) { alt s.node { stmt_decl(d, _) { v.visit_decl(d, e, v); } stmt_expr(ex, _) { v.visit_expr(ex, e, v); } + stmt_semi(ex, _) { v.visit_expr(ex, e, v); } } } diff --git a/src/rustc/front/test.rs b/src/rustc/front/test.rs index 61b2816c2e6..ce101a5ce4e 100644 --- a/src/rustc/front/test.rs +++ b/src/rustc/front/test.rs @@ -359,7 +359,7 @@ fn mk_test_wrapper(cx: test_ctxt, }; let call_stmt: ast::stmt = nospan( - ast::stmt_expr(@call_expr, cx.sess.next_node_id())); + ast::stmt_semi(@call_expr, cx.sess.next_node_id())); let wrapper_decl: ast::fn_decl = { inputs: ~[], diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 5cc6e9881ae..3b9b4549817 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -229,7 +229,7 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item { fn drop_nested_items(blk: ast::blk_, fld: fold::ast_fold) -> ast::blk_ { let stmts_sans_items = do vec::filter(blk.stmts) |stmt| { alt stmt.node { - ast::stmt_expr(_, _) | + ast::stmt_expr(_, _) | ast::stmt_semi(_, _) | ast::stmt_decl(@{node: ast::decl_local(_), span: _}, _) { true } ast::stmt_decl(@{node: ast::decl_item(_), span: _}, _) { false } } diff --git a/src/rustc/middle/lint.rs b/src/rustc/middle/lint.rs index c3206bafd31..3c8083e7f76 100644 --- a/src/rustc/middle/lint.rs +++ b/src/rustc/middle/lint.rs @@ -405,7 +405,7 @@ fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) { let visit = item_stopping_visitor(visit::mk_simple_visitor(@{ visit_stmt: fn@(s: @ast::stmt) { alt s.node { - ast::stmt_expr(@{id: id, + ast::stmt_semi(@{id: id, node: ast::expr_path(@path), span: _}, _) { cx.sess.span_lint( diff --git a/src/rustc/middle/liveness.rs b/src/rustc/middle/liveness.rs index fdd18a21a1d..fd6033c5b9d 100644 --- a/src/rustc/middle/liveness.rs +++ b/src/rustc/middle/liveness.rs @@ -843,7 +843,7 @@ class liveness { ret self.propagate_through_decl(decl, succ); } - stmt_expr(expr, _) { + stmt_expr(expr, _) | stmt_semi(expr, _) { ret self.propagate_through_expr(expr, succ); } } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index a958079b327..457ffd8e401 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -4131,7 +4131,7 @@ fn trans_stmt(cx: block, s: ast::stmt) -> block { debuginfo::update_source_pos(cx, s.span); alt s.node { - ast::stmt_expr(e, _) { + ast::stmt_expr(e, _) | ast::stmt_semi(e, _) { bcx = trans_expr(cx, e, ignore); } ast::stmt_decl(d, _) { diff --git a/src/rustc/middle/tstate/annotate.rs b/src/rustc/middle/tstate/annotate.rs index 9dd1157a56f..e6beae9e014 100644 --- a/src/rustc/middle/tstate/annotate.rs +++ b/src/rustc/middle/tstate/annotate.rs @@ -15,7 +15,7 @@ fn collect_ids_block(b: blk, rs: @mut ~[node_id]) { fn collect_ids_stmt(s: @stmt, rs: @mut ~[node_id]) { alt s.node { - stmt_decl(_, id) | stmt_expr(_, id) { + stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) { #debug["node_id %s", int::str(id)]; #debug["%s", stmt_to_str(*s)]; vec::push(*rs, id); diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs index 13d82cefe13..d50e445482a 100644 --- a/src/rustc/middle/tstate/auxiliary.rs +++ b/src/rustc/middle/tstate/auxiliary.rs @@ -278,7 +278,7 @@ fn node_id_to_poststate(ccx: crate_ctxt, id: node_id) -> poststate { fn stmt_to_ann(ccx: crate_ctxt, s: stmt) -> ts_ann { #debug("stmt_to_ann"); alt s.node { - stmt_decl(_, id) | stmt_expr(_, id) { + stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) { ret node_id_to_ts_ann(ccx, id); } } diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs index 9f2e12cff2d..197ed4b3108 100644 --- a/src/rustc/middle/tstate/pre_post_conditions.rs +++ b/src/rustc/middle/tstate/pre_post_conditions.rs @@ -520,7 +520,7 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { } } } - stmt_expr(e, id) { + stmt_expr(e, id) | stmt_semi(e, id) { find_pre_post_expr(fcx, e); copy_pre_post(fcx.ccx, id, e); } diff --git a/src/rustc/middle/tstate/states.rs b/src/rustc/middle/tstate/states.rs index 85b66dfd389..adf1efc8562 100644 --- a/src/rustc/middle/tstate/states.rs +++ b/src/rustc/middle/tstate/states.rs @@ -537,7 +537,7 @@ fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool { } } } - stmt_expr(ex, _) { + stmt_expr(ex, _) | stmt_semi(ex, _) { let mut changed = find_pre_post_state_expr(fcx, pres, ex) | set_prestate(stmt_ann, expr_prestate(fcx.ccx, ex)) | diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index f60ede09cec..c5ad6f9a00a 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2255,7 +2255,7 @@ fn expr_is_lval(method_map: typeck::method_map, e: @ast::expr) -> bool { fn stmt_node_id(s: @ast::stmt) -> ast::node_id { alt s.node { - ast::stmt_decl(_, id) | stmt_expr(_, id) { + ast::stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) { ret id; } } diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 0f0cb2903cb..08927d60fb8 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -1718,6 +1718,10 @@ fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool { } } ast::stmt_expr(expr, id) { + node_id = id; + bot = check_expr_with(fcx, expr, ty::mk_nil(fcx.ccx.tcx)); + } + ast::stmt_semi(expr, id) { node_id = id; bot = check_expr(fcx, expr, none); } @@ -1749,7 +1753,7 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { if bot && !warned && alt s.node { ast::stmt_decl(@{node: ast::decl_local(_), _}, _) | - ast::stmt_expr(_, _) { + ast::stmt_expr(_, _) | ast::stmt_semi(_, _) { true } _ { false } diff --git a/src/test/run-pass/block-arg-as-stmt-with-value.rs b/src/test/compile-fail/block-arg-as-stmt-with-value.rs similarity index 58% rename from src/test/run-pass/block-arg-as-stmt-with-value.rs rename to src/test/compile-fail/block-arg-as-stmt-with-value.rs index 630c0c95511..b8e34aefd6f 100644 --- a/src/test/run-pass/block-arg-as-stmt-with-value.rs +++ b/src/test/compile-fail/block-arg-as-stmt-with-value.rs @@ -2,13 +2,12 @@ fn compute1() -> float { let v = ~[0f, 1f, 2f, 3f]; - // This is actually a (block-style) statement followed by - // a unary tail expression do vec::foldl(0f, v) |x, y| { x + y } - 10f + //~^ ERROR mismatched types: expected `()` } fn main() { let x = compute1(); log(debug, x); - assert(x == -10f); + assert(x == -4f); } diff --git a/src/test/run-pass/typed-statements-dont-need-semis.rs b/src/test/run-pass/typed-statements-dont-need-semis.rs deleted file mode 100644 index e2556f793af..00000000000 --- a/src/test/run-pass/typed-statements-dont-need-semis.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn f(f: fn()) -> int { - f(); 0 -} - -fn main() { - // Testing that the old rule that statements (even control - // structures) that have non-nil type be semi-terminated _no - // longer_ is required - do f { - } - if true { 0 } else { 0 } - let _x = 0; -} \ No newline at end of file