about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/comp/middle/typeck.rs41
-rw-r--r--src/comp/syntax/parse/eval.rs4
-rw-r--r--src/comp/syntax/parse/parser.rs40
-rw-r--r--src/comp/syntax/print/pprust.rs32
-rw-r--r--src/libstd/rope.rs2
-rw-r--r--src/test/compile-fail/block-must-not-have-result-do.rs2
-rw-r--r--src/test/compile-fail/block-must-not-have-result-for.rs2
-rw-r--r--src/test/compile-fail/block-must-not-have-result-res.rs2
-rw-r--r--src/test/compile-fail/block-must-not-have-result-while.rs2
-rw-r--r--src/test/compile-fail/forgot-ret.rs2
-rw-r--r--src/test/compile-fail/if-without-else-result.rs2
-rw-r--r--src/test/compile-fail/missing-return2.rs2
-rw-r--r--src/test/pretty/disamb-stmt-expr.rs8
-rw-r--r--src/test/run-pass/early-ret-binop-add.rs2
-rw-r--r--src/test/run-pass/early-ret-binop.rs2
-rw-r--r--src/test/stdtest/os.rs7
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]