require a non-semi expr acting as a stmt to have unit return type

This commit is contained in:
Niko Matsakis 2012-01-04 14:16:41 -08:00
parent 37ba5f3b32
commit f832edc369
18 changed files with 92 additions and 69 deletions

View File

@ -318,7 +318,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: [],

View File

@ -155,7 +155,7 @@ fn visit_block(cx: @ctx, b: ast::blk, sc: scope, v: vt<scope>) {
}
}
}
ast::stmt_expr(ex, _) {
ast::stmt_expr(ex, _) | ast::stmt_semi(ex, _) {
v.visit_expr(ex, sc, v);
}
}

View File

@ -4053,7 +4053,9 @@ fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt {
debuginfo::update_source_pos(cx, s.span);
alt s.node {
ast::stmt_expr(e, _) { bcx = trans_expr(cx, e, ignore); }
ast::stmt_expr(e, _) | ast::stmt_semi(e, _) {
bcx = trans_expr(cx, e, ignore);
}
ast::stmt_decl(d, _) {
alt d.node {
ast::decl_local(locals) {

View File

@ -14,14 +14,9 @@ fn collect_ids_block(b: blk, rs: @mutable [node_id]) { *rs += [b.node.id]; }
fn collect_ids_stmt(s: @stmt, rs: @mutable [node_id]) {
alt s.node {
stmt_decl(_, id) {
stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) {
log(debug, "node_id " + int::str(id));
log_stmt(*s);;
*rs += [id];
}
stmt_expr(_, id) {
log(debug, "node_id " + int::str(id));
log_stmt(*s);;
log_stmt(*s);
*rs += [id];
}
_ { }

View File

@ -324,8 +324,9 @@ 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) { ret node_id_to_ts_ann(ccx, id); }
stmt_expr(_, id) { ret node_id_to_ts_ann(ccx, id); }
stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) {
ret node_id_to_ts_ann(ccx, id);
}
}
}

View File

@ -647,7 +647,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);
}

View File

@ -664,7 +664,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 changed =
find_pre_post_state_expr(fcx, pres, ex) |
set_prestate(stmt_ann, expr_prestate(fcx.ccx, ex)) |

View File

@ -1660,8 +1660,9 @@ fn expr_is_lval(method_map: typeck::method_map, tcx: ty::ctxt,
fn stmt_node_id(s: @ast::stmt) -> ast::node_id {
alt s.node {
ast::stmt_decl(_, id) { ret id; }
ast::stmt_expr(_, id) { ret id; }
ast::stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) {
ret id;
}
}
}

View File

@ -2539,7 +2539,14 @@ fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool {
ast::decl_item(_) {/* ignore for now */ }
}
}
ast::stmt_expr(expr, id) { node_id = id; bot = check_expr(fcx, expr); }
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);
}
}
write::nil_ty(fcx.ccx.tcx, node_id);
ret bot;
@ -2567,7 +2574,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 }

View File

@ -156,7 +156,12 @@ type stmt = spanned<stmt_>;
tag 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);
}
tag init_op { init_assign; init_move; }

View File

@ -272,8 +272,9 @@ fn noop_fold_block(b: blk_, fld: ast_fold) -> blk_ {
fn noop_fold_stmt(s: stmt_, fld: ast_fold) -> stmt_ {
ret alt s {
stmt_decl(d, nid) { stmt_decl(fld.fold_decl(d), nid) }
stmt_expr(e, nid) { stmt_expr(fld.fold_expr(e), nid) }
stmt_decl(d, nid) { stmt_decl(fld.fold_decl(d), nid) }
stmt_expr(e, nid) { stmt_expr(fld.fold_expr(e), nid) }
stmt_semi(e, nid) { stmt_semi(fld.fold_expr(e), nid) }
};
}

View File

@ -1639,13 +1639,6 @@ fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool {
}
}
fn stmt_to_expr(stmt: @ast::stmt) -> option::t<@ast::expr> {
alt stmt.node {
ast::stmt_expr(e, _) { some(e) }
_ { none }
}
}
fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
alt stmt.node {
ast::stmt_decl(d, _) {
@ -1657,6 +1650,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;
}
}
}
@ -1695,11 +1691,16 @@ fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk {
}
_ {
let stmt = parse_stmt(p);
alt stmt_to_expr(stmt) {
some(e) {
alt stmt.node {
ast::stmt_expr(e, stmt_id) { // Expression without semicolon:
alt p.peek() {
token::SEMI. { p.bump(); stmts += [stmt]; }
token::RBRACE. { expr = some(e); }
token::SEMI. {
p.bump();
stmts += [@{node: ast::stmt_semi(e, stmt_id) with *stmt}];
}
token::RBRACE. {
expr = some(e);
}
t {
if stmt_ends_with_semi(*stmt) {
p.fatal("expected ';' or '}' after expression but \
@ -1710,8 +1711,8 @@ fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk {
}
}
}
none. {
// Not an expression statement.
_ { // All other kinds of statements:
stmts += [stmt];
if stmt_ends_with_semi(*stmt) {

View File

@ -569,6 +569,11 @@ fn print_stmt(s: ps, st: ast::stmt) {
space_if_not_bol(s);
print_tl_expr(s, expr);
}
ast::stmt_semi(expr, _) {
space_if_not_bol(s);
print_tl_expr(s, expr);
word(s.s, ";");
}
}
if parse::parser::stmt_ends_with_semi(st) { word(s.s, ";"); }
maybe_print_trailing_comment(s, st.span, none::<uint>);

View File

@ -262,6 +262,7 @@ fn visit_stmt<E>(s: @stmt, e: E, v: vt<E>) {
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); }
}
}

View File

@ -0,0 +1,13 @@
fn compute1() -> float {
let v = [0f, 1f, 2f, 3f];
vec::foldl(0f, v) { |x, y| x + y } - 10f
//!^ ERROR mismatched types: expected `()`
}
fn main() {
let x = compute1();
log(debug, x);
assert(y == -4f);
}

View File

@ -1,25 +0,0 @@
fn compute1() -> float {
let v = [0f, 1f, 2f, 3f];
// Here the "-10f" parses as a second
// statement in tail position:
vec::foldl(0f, v) { |x, y| x + y } - 10f
}
fn compute2() -> float {
let v = [0f, 1f, 2f, 3f];
// Here the ret makes this explicit:
ret vec::foldl(0f, v) { |x, y| x + y } - 10f;
}
fn main() {
let x = compute1();
log(debug, x);
assert(x == -10f);
let y = compute2();
log(debug, y);
assert(y == -4f);
}

View File

@ -1,21 +1,26 @@
fn w_semi(v: [int]) -> int {
// the semicolon causes compiler not to
// complain about the ignored return value:
vec::foldl(0, v) {|x,y| x+y};
-10
}
fn wo_paren(v: [int]) -> int {
// Perhaps surprising: this is parsed equivalently to w_semi()
vec::foldl(0, v) {|x,y| x+y} - 10
}
fn w_paren(v: [int]) -> int {
// Here the parentheses force interpretation as an expression:
fn w_paren1(v: [int]) -> int {
(vec::foldl(0, v) {|x,y| x+y}) - 10
}
fn main() {
assert wo_paren([0, 1, 2, 3]) == -10;
assert w_semi([0, 1, 2, 3]) == -10;
assert w_paren([0, 1, 2, 3]) == -4;
fn w_paren2(v: [int]) -> int {
(vec::foldl(0, v) {|x,y| x+y} - 10)
}
fn w_ret(v: [int]) -> int {
ret vec::foldl(0, v) {|x,y| x+y} - 10;
}
fn main() {
assert w_semi([0, 1, 2, 3]) == -10;
assert w_paren1([0, 1, 2, 3]) == -4;
assert w_paren2([0, 1, 2, 3]) == -4;
assert w_ret([0, 1, 2, 3]) == -4;
}

View File

@ -0,0 +1,11 @@
// Make sure #1399 stays fixed
fn foo() -> lambda() -> int {
let k = ~22;
let _u = {a: k};
ret lambda[move k]() -> int { 22 };
}
fn main() {
assert foo()() == 22;
}