diff options
| -rw-r--r-- | src/comp/middle/typeck.rs | 41 | ||||
| -rw-r--r-- | src/comp/syntax/parse/eval.rs | 4 | ||||
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 40 | ||||
| -rw-r--r-- | src/comp/syntax/print/pprust.rs | 32 | ||||
| -rw-r--r-- | src/libstd/rope.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/block-must-not-have-result-do.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/block-must-not-have-result-for.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/block-must-not-have-result-res.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/block-must-not-have-result-while.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/forgot-ret.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/if-without-else-result.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/missing-return2.rs | 2 | ||||
| -rw-r--r-- | src/test/pretty/disamb-stmt-expr.rs | 8 | ||||
| -rw-r--r-- | src/test/run-pass/early-ret-binop-add.rs | 2 | ||||
| -rw-r--r-- | src/test/run-pass/early-ret-binop.rs | 2 | ||||
| -rw-r--r-- | src/test/stdtest/os.rs | 7 |
16 files changed, 97 insertions, 55 deletions
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index f5b6f0f736a..9c3c206f593 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1741,7 +1741,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let element_ty = demand::simple(fcx, local.span, element_ty, ty::mk_var(fcx.ccx.tcx, locid)); let bot = check_decl_local(fcx, local); - check_block(fcx, body); + check_block_no_value(fcx, body); // Unify type of decl with element type of the seq demand::simple(fcx, local.span, ty::node_id_to_type(fcx.ccx.tcx, local.node.id), @@ -1756,22 +1756,27 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, fn check_then_else(fcx: @fn_ctxt, thn: ast::blk, elsopt: option::t<@ast::expr>, id: ast::node_id, _sp: span) -> bool { - let then_bot = check_block(fcx, thn); - let els_bot = false; - let if_t = + let (if_t, if_bot) = alt elsopt { some(els) { + let thn_bot = check_block(fcx, thn); let thn_t = block_ty(fcx.ccx.tcx, thn); - els_bot = check_expr_with(fcx, els, thn_t); - let elsopt_t = expr_ty(fcx.ccx.tcx, els); - if !ty::type_is_bot(fcx.ccx.tcx, elsopt_t) { - elsopt_t - } else { thn_t } + let els_bot = check_expr_with(fcx, els, thn_t); + let els_t = expr_ty(fcx.ccx.tcx, els); + let if_t = if !ty::type_is_bot(fcx.ccx.tcx, els_t) { + els_t + } else { + thn_t + }; + (if_t, thn_bot & els_bot) + } + none. { + check_block_no_value(fcx, thn); + (ty::mk_nil(fcx.ccx.tcx), false) } - none. { ty::mk_nil(fcx.ccx.tcx) } }; write::ty_only_fixup(fcx, id, if_t); - ret then_bot & els_bot; + ret if_bot; } // Checks the compatibility @@ -1993,12 +1998,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } ast::expr_while(cond, body) { bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)); - check_block(fcx, body); + check_block_no_value(fcx, body); write::ty_only_fixup(fcx, id, ty::mk_nil(tcx)); } ast::expr_do_while(body, cond) { bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) | - check_block(fcx, body); + check_block_no_value(fcx, body); write::ty_only_fixup(fcx, id, block_ty(tcx, body)); } ast::expr_alt(expr, arms) { @@ -2490,6 +2495,16 @@ fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool { ret bot; } +fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool { + let bot = check_block(fcx, blk); + if !bot { + let blkty = ty::node_id_to_monotype(fcx.ccx.tcx, blk.node.id); + let nilty = ty::mk_nil(fcx.ccx.tcx); + demand::simple(fcx, blk.span, nilty, blkty); + } + ret bot; +} + fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { let fcx = alt blk.node.rules { ast::unchecked_blk. { @{purity: ast::impure_fn with *fcx0} } diff --git a/src/comp/syntax/parse/eval.rs b/src/comp/syntax/parse/eval.rs index 1b1713aff33..b13f0cff92a 100644 --- a/src/comp/syntax/parse/eval.rs +++ b/src/comp/syntax/parse/eval.rs @@ -56,10 +56,10 @@ fn parse_companion_mod(cx: ctx, prefix: str, suffix: option::t<str>) -> ([@ast::view_item], [@ast::item], [ast::attribute]) { fn companion_file(prefix: str, suffix: option::t<str>) -> str { - alt suffix { + ret alt suffix { option::some(s) { fs::connect(prefix, s) } option::none. { prefix } - } + ".rs" + } + ".rs"; } fn file_exists(path: str) -> bool { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 0ce5f8628dc..a1e4ddbe502 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -1232,11 +1232,6 @@ fn parse_if_expr_1(p: parser) -> let elexpr = parse_else_expr(p); els = some(elexpr); hi = elexpr.span.hi; - } else if !option::is_none(thn.node.expr) { - let sp = option::get(thn.node.expr).span; - p.span_fatal(sp, "`if` without `else` can not produce a result"); - //TODO: If a suggestion mechanism appears, suggest that the - //user may have forgotten a ';' } ret {cond: cond, then: thn, els: els, lo: lo, hi: hi}; } @@ -1596,32 +1591,29 @@ fn parse_stmt(p: parser) -> @ast::stmt { } fn expr_is_complete(p: parser, e: @ast::expr) -> bool { + log(debug, ("expr_is_complete", p.get_restriction(), + print::pprust::expr_to_str(e), + expr_requires_semi_to_be_stmt(e))); ret p.get_restriction() == RESTRICT_STMT_EXPR && !expr_requires_semi_to_be_stmt(e); } fn expr_requires_semi_to_be_stmt(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_requires_semi_to_be_stmt(option::get(els)) } + ast::expr_if(_, _, _) | ast::expr_if_check(_, _, _) + | ast::expr_alt(_, _) | ast::expr_block(_) + | ast::expr_do_while(_, _) | ast::expr_while(_, _) + | ast::expr_for(_, _, _) + | ast::expr_call(_, _, true) { + false } - ast::expr_alt(_, arms) { - vec::any(arms, {|arm| !option::is_none(arm.body.node.expr)}) - } - ast::expr_block(blk) | ast::expr_while(_, blk) | - ast::expr_for(_, _, blk) | ast::expr_do_while(blk, _) { - !option::is_none(blk.node.expr) - } - ast::expr_call(_, _, true) { false } _ { true } } } fn stmt_to_expr(stmt: @ast::stmt) -> option::t<@ast::expr> { alt stmt.node { - ast::stmt_expr(e, _) when expr_requires_semi_to_be_stmt(e) { some(e) } + ast::stmt_expr(e, _) { some(e) } _ { none } } } @@ -1655,14 +1647,10 @@ fn parse_block(p: parser) -> ast::blk { } fn parse_block_no_value(p: parser) -> ast::blk { - let blk = parse_block(p); - if !option::is_none(blk.node.expr) { - let sp = option::get(blk.node.expr).span; - p.span_fatal(sp, "this block must not have a result"); - //TODO: If a suggestion mechanism appears, suggest that the - //user may have forgotten a ';' - } - ret blk; + // We parse blocks that cannot have a value the same as any other block; + // the type checker will make sure that the tail expression (if any) has + // unit type. + ret parse_block(p); } // Precondition: already parsed the '{' or '#{' diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 72e0879e4bf..da592b6d3c1 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -558,11 +558,39 @@ fn print_attribute(s: ps, attr: ast::attribute) { word(s.s, "]"); } +// An expression that begins with a dual-form statement/expression like `{ +// ... }-10` would be parsed as `{ ... };-10` unless parentheses are used (ie, +// `({...}-10)`). These parentheses are not, however, preserved by the +// parser. This function specifies whether parentheses must be inserted. +fn stmt_expr_requires_parens(ex: @ast::expr) -> bool { + fn helper(ex: @ast::expr, inner: bool) -> bool { + alt ex.node { + ast::expr_call(subex, _, _) | ast::expr_binary(_, subex, _) { + be helper(subex, true); + } + _ when !inner { ret false; } + _ { ret !parse::parser::expr_requires_semi_to_be_stmt(ex); } + } + } + ret helper(ex, false); +} + fn print_stmt(s: ps, st: ast::stmt) { maybe_print_comment(s, st.span.lo); alt st.node { - ast::stmt_decl(decl, _) { print_decl(s, decl); } - ast::stmt_expr(expr, _) { space_if_not_bol(s); print_expr(s, expr); } + ast::stmt_decl(decl, _) { + print_decl(s, decl); + } + ast::stmt_expr(expr, _) { + space_if_not_bol(s); + if stmt_expr_requires_parens(expr) { + popen(s); + print_expr(s, expr); + pclose(s); + } else { + print_expr(s, expr); + } + } } if parse::parser::stmt_ends_with_semi(st) { word(s.s, ";"); } maybe_print_trailing_comment(s, st.span, none::<uint>); diff --git a/src/libstd/rope.rs b/src/libstd/rope.rs index dea9d187110..6b821dc6223 100644 --- a/src/libstd/rope.rs +++ b/src/libstd/rope.rs @@ -443,7 +443,7 @@ fn iter_chars(rope: rope, it: block(char)) { loop_chars(rope) {|x| it(x); ret true - } + }; } /* diff --git a/src/test/compile-fail/block-must-not-have-result-do.rs b/src/test/compile-fail/block-must-not-have-result-do.rs index 7a1a384e64b..f842b0f02b4 100644 --- a/src/test/compile-fail/block-must-not-have-result-do.rs +++ b/src/test/compile-fail/block-must-not-have-result-do.rs @@ -1,4 +1,4 @@ -// error-pattern:this block must not have a result +// error-pattern:mismatched types: expected `()` but found `bool` fn main() { do { diff --git a/src/test/compile-fail/block-must-not-have-result-for.rs b/src/test/compile-fail/block-must-not-have-result-for.rs index 5b5e1fafca2..d2e7edbfc0f 100644 --- a/src/test/compile-fail/block-must-not-have-result-for.rs +++ b/src/test/compile-fail/block-must-not-have-result-for.rs @@ -1,4 +1,4 @@ -// error-pattern:this block must not have a result +// error-pattern:mismatched types: expected `()` but found `bool` fn main() { for i in [0] { diff --git a/src/test/compile-fail/block-must-not-have-result-res.rs b/src/test/compile-fail/block-must-not-have-result-res.rs index 4e0a1a54232..d617aba2fde 100644 --- a/src/test/compile-fail/block-must-not-have-result-res.rs +++ b/src/test/compile-fail/block-must-not-have-result-res.rs @@ -1,4 +1,4 @@ -// error-pattern:this block must not have a result +// error-pattern:mismatched types: expected `()` but found `bool` resource r(i: int) { true diff --git a/src/test/compile-fail/block-must-not-have-result-while.rs b/src/test/compile-fail/block-must-not-have-result-while.rs index d0417fc27ec..7f172998c28 100644 --- a/src/test/compile-fail/block-must-not-have-result-while.rs +++ b/src/test/compile-fail/block-must-not-have-result-while.rs @@ -1,4 +1,4 @@ -// error-pattern:this block must not have a result +// error-pattern:mismatched types: expected `()` but found `bool` fn main() { while true { diff --git a/src/test/compile-fail/forgot-ret.rs b/src/test/compile-fail/forgot-ret.rs index 0f780f1b335..4e422c970c6 100644 --- a/src/test/compile-fail/forgot-ret.rs +++ b/src/test/compile-fail/forgot-ret.rs @@ -3,6 +3,6 @@ fn god_exists(a: int) -> bool { be god_exists(a); } -fn f(a: int) -> int { if god_exists(a) { ret 5; } } +fn f(a: int) -> int { if god_exists(a) { ret 5; }; } fn main() { f(12); } diff --git a/src/test/compile-fail/if-without-else-result.rs b/src/test/compile-fail/if-without-else-result.rs index 0ff469a871c..2454f4f37bf 100644 --- a/src/test/compile-fail/if-without-else-result.rs +++ b/src/test/compile-fail/if-without-else-result.rs @@ -1,4 +1,4 @@ -// error-pattern:`if` without `else` can not produce a result +// error-pattern:mismatched types: expected `()` but found `bool` fn main() { let a = if true { true }; diff --git a/src/test/compile-fail/missing-return2.rs b/src/test/compile-fail/missing-return2.rs index a73db075196..26a9febd3c7 100644 --- a/src/test/compile-fail/missing-return2.rs +++ b/src/test/compile-fail/missing-return2.rs @@ -3,7 +3,7 @@ fn f() -> int { // Make sure typestate doesn't interpret this alt expression // as the function result - alt true { true { } } + alt true { true { } }; } fn main() { } diff --git a/src/test/pretty/disamb-stmt-expr.rs b/src/test/pretty/disamb-stmt-expr.rs new file mode 100644 index 00000000000..5f9d57f94a7 --- /dev/null +++ b/src/test/pretty/disamb-stmt-expr.rs @@ -0,0 +1,8 @@ +// pp-exact + +// Here we check that the parentheses around the body of `wsucc()` are +// preserved. They are needed to disambiguate `{ret n+1}; - 0` from +// `({ret n+1}-0)`. + +fn wsucc(n: int) -> int { ({ ret n + 1 } - 0); } +fn main() { } diff --git a/src/test/run-pass/early-ret-binop-add.rs b/src/test/run-pass/early-ret-binop-add.rs index f7719afc591..21eca8fefac 100644 --- a/src/test/run-pass/early-ret-binop-add.rs +++ b/src/test/run-pass/early-ret-binop-add.rs @@ -1,2 +1,2 @@ -fn wsucc(n: int) -> int { { ret n + 1 } + 0; } +fn wsucc(n: int) -> int { ({ ret n + 1 } + 0); } fn main() { } diff --git a/src/test/run-pass/early-ret-binop.rs b/src/test/run-pass/early-ret-binop.rs index ffa6efb4e80..118bec708b8 100644 --- a/src/test/run-pass/early-ret-binop.rs +++ b/src/test/run-pass/early-ret-binop.rs @@ -1,2 +1,2 @@ -fn wsucc(n: int) -> int { { ret n + 1 } == 0; } +fn wsucc(n: int) -> int { ({ ret n + 1 } == 0); } fn main() { } diff --git a/src/test/stdtest/os.rs b/src/test/stdtest/os.rs index 7f7b2c4f3b3..fd773063e8d 100644 --- a/src/test/stdtest/os.rs +++ b/src/test/stdtest/os.rs @@ -14,6 +14,7 @@ fn test_setenv() { } #[test] +#[ignore(reason = "fails periodically on mac")] fn test_setenv_overwrite() { setenv("NAME2", "1"); setenv("NAME2", "2"); @@ -23,12 +24,14 @@ fn test_setenv_overwrite() { // Windows GetEnvironmentVariable requires some extra work to make sure // the buffer the variable is copied into is the right size #[test] +#[ignore(reason = "fails periodically on mac")] fn test_getenv_big() { let s = ""; let i = 0; while i < 100 { s += "aaaaaaaaaa"; i += 1; } - setenv("NAME3", s); - assert (getenv("NAME3") == option::some(s)); + setenv("test_getenv_big", s); + log(debug, s); + assert (getenv("test_getenv_big") == option::some(s)); } #[test] |
