Be more strict about what constitutes a block expression
Blocks (or statements involving blocks) that end in a semicolon are no longer considered the block-expression of their outer block. This used to be an expression block, but now is a statement block: { if foo { ret 1; } else { ret 10; } } This helps clear up some ambiguities in our grammar.
This commit is contained in:
parent
e945164879
commit
be5537e95f
3 changed files with 37 additions and 9 deletions
|
@ -1571,8 +1571,42 @@ fn parse_source_stmt(p: parser) -> @ast::stmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn stmt_is_expr(stmt: @ast::stmt) -> bool {
|
||||||
|
fn expr_is_expr(e: @ast::expr) -> bool {
|
||||||
|
alt e.node {
|
||||||
|
ast::expr_if(_, th, els) | ast::expr_if_check(_, th, els) {
|
||||||
|
if option::is_none(els) { false }
|
||||||
|
else { !option::is_none(th.node.expr) ||
|
||||||
|
expr_is_expr(option::get(els)) }
|
||||||
|
}
|
||||||
|
ast::expr_alt(_, arms) {
|
||||||
|
let found_expr = false;
|
||||||
|
for arm in arms {
|
||||||
|
if !option::is_none(arm.body.node.expr) { found_expr = true; }
|
||||||
|
}
|
||||||
|
found_expr
|
||||||
|
}
|
||||||
|
ast::expr_block(blk) | ast::expr_while(_, blk) |
|
||||||
|
ast::expr_for(_, _, blk) | ast::expr_for_each(_, _, blk) |
|
||||||
|
ast::expr_do_while(blk, _) {
|
||||||
|
!option::is_none(blk.node.expr)
|
||||||
|
}
|
||||||
|
_ { true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret alt stmt.node {
|
||||||
|
ast::stmt_expr(e, _) { expr_is_expr(e) }
|
||||||
|
_ { false }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn stmt_to_expr(stmt: @ast::stmt) -> option::t<@ast::expr> {
|
fn stmt_to_expr(stmt: @ast::stmt) -> option::t<@ast::expr> {
|
||||||
ret alt stmt.node { ast::stmt_expr(e, _) { some(e) } _ { none } };
|
ret if stmt_is_expr(stmt) {
|
||||||
|
alt stmt.node {
|
||||||
|
ast::stmt_expr(e, _) { some(e) }
|
||||||
|
}
|
||||||
|
} else { none };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
|
fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
|
||||||
|
@ -1627,10 +1661,6 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// We should not be calling this on a cdir.
|
// We should not be calling this on a cdir.
|
||||||
ast::stmt_crate_directive(cdir) {
|
ast::stmt_crate_directive(cdir) {
|
||||||
fail;
|
fail;
|
||||||
|
@ -1681,7 +1711,6 @@ fn parse_block_tail(p: parser, lo: uint, s: ast::check_mode) -> ast::blk {
|
||||||
// Not an expression statement.
|
// Not an expression statement.
|
||||||
stmts += [stmt];
|
stmts += [stmt];
|
||||||
|
|
||||||
|
|
||||||
if p.get_file_type() == SOURCE_FILE &&
|
if p.get_file_type() == SOURCE_FILE &&
|
||||||
stmt_ends_with_semi(*stmt) {
|
stmt_ends_with_semi(*stmt) {
|
||||||
expect(p, token::SEMI);
|
expect(p, token::SEMI);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- rust -*-
|
// -*- rust -*-
|
||||||
// error-pattern: mismatched types
|
// error-pattern: not all control paths return a value
|
||||||
|
|
||||||
fn god_exists(a: int) -> bool { be god_exists(a); }
|
fn god_exists(a: int) -> bool { be god_exists(a); }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// error-pattern: mismatched types
|
// error-pattern: not all control paths return a value
|
||||||
|
|
||||||
fn f() -> int {
|
fn f() -> int {
|
||||||
|
|
||||||
// Make sure typestate doesn't interpret this alt expression
|
// Make sure typestate doesn't interpret this alt expression
|
||||||
// as the function result
|
// as the function result
|
||||||
alt true { true { } }
|
alt true { true { } }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue