From 2490cd327514471c8e7fb56a9fba2c2304c04552 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 20:17:43 -0400 Subject: [PATCH 01/13] Add a test for block expressions that have results. XFAILed. --- src/test/run-pass/expr-block-box.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/run-pass/expr-block-box.rs diff --git a/src/test/run-pass/expr-block-box.rs b/src/test/run-pass/expr-block-box.rs new file mode 100644 index 0000000000000..b324994a8e8cf --- /dev/null +++ b/src/test/run-pass/expr-block-box.rs @@ -0,0 +1,11 @@ +// xfail-boot +// xfail-stage0 +// -*- rust -*- + +fn main() { + auto x = { + @100 + }; + + check (*x == 100); +} \ No newline at end of file From d631f29d47578c46bfc01e1a8cc021b295866e0c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 20:29:59 -0400 Subject: [PATCH 02/13] Add block_to_str and expr_to_str methods to the pprust module. Since pprust is authed impure these can be used for debug logging. --- src/comp/pretty/pprust.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index d478227ce2278..f3b0f3fe97939 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -32,6 +32,24 @@ fn ty_to_str(&@ast.ty ty) -> str { ret writer.get_str(); } +fn block_to_str(&ast.block blk) -> str { + auto writer = io.string_writer(); + auto s = @rec(s=pp.mkstate(writer.get_writer(), 78u), + comments=option.none[vec[lexer.cmnt]], + mutable cur_cmnt=0u); + print_block(s, blk); + ret writer.get_str(); +} + +fn expr_to_str(&@ast.expr e) -> str { + auto writer = io.string_writer(); + auto s = @rec(s=pp.mkstate(writer.get_writer(), 78u), + comments=option.none[vec[lexer.cmnt]], + mutable cur_cmnt=0u); + print_expr(s, e); + ret writer.get_str(); +} + impure fn hbox(ps s) { pp.hbox(s.s, indent_unit); } From bd1c61548ec2ddde4d85dbef88eed6627b536d13 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 21:18:23 -0400 Subject: [PATCH 03/13] Move str test from expr-if.rs to expr-if-box.rs in preperation for breaking that code path. --- src/test/run-pass/expr-if-box.rs | 8 +++++++- src/test/run-pass/expr-if.rs | 6 ------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/run-pass/expr-if-box.rs b/src/test/run-pass/expr-if-box.rs index 98503211fc2c3..30dce957235b2 100644 --- a/src/test/run-pass/expr-if-box.rs +++ b/src/test/run-pass/expr-if-box.rs @@ -9,6 +9,12 @@ fn test_box() { check (*res == 100); } +fn test_str() { + auto res = if (true) { "happy" } else { "sad" }; + check (res == "happy"); +} + fn main() { test_box(); -} \ No newline at end of file + test_str(); +} diff --git a/src/test/run-pass/expr-if.rs b/src/test/run-pass/expr-if.rs index e69a629f9d055..7c99f2ea82e1c 100644 --- a/src/test/run-pass/expr-if.rs +++ b/src/test/run-pass/expr-if.rs @@ -80,11 +80,6 @@ fn test_if_as_block_result() { check (res); } -fn test_str() { - auto res = if (true) { "happy" } else { "sad" }; - check (res == "happy"); -} - fn main() { test_if(); test_else(); @@ -94,5 +89,4 @@ fn main() { test_inferrence(); test_if_as_if_condition(); test_if_as_block_result(); - test_str(); } From 125bebbf60acf13bcbebaab2d68d2c68d5a06f77 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 21:20:10 -0400 Subject: [PATCH 04/13] Modify trans.rs to allow blocks to result in boxed values --- src/comp/middle/trans.rs | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a945c88e2a68b..6c072c61e83b1 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1026,6 +1026,18 @@ fn find_scope_cx(@block_ctxt cx) -> @block_ctxt { } } +fn find_outer_scope_cx(@block_ctxt cx) -> @block_ctxt { + auto scope_cx = find_scope_cx(cx); + alt (cx.parent) { + case (parent_some(?b)) { + be find_scope_cx(b); + } + case (parent_none) { + fail; + } + } +} + fn umax(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef { auto cond = cx.build.ICmp(lib.llvm.LLVMIntULT, a, b); ret cx.build.Select(cond, b, a); @@ -5368,8 +5380,55 @@ fn trans_block(@block_ctxt cx, &ast.block b) -> result { case (some[@ast.expr](?e)) { r = trans_expr(bcx, e); bcx = r.bcx; + if (is_terminated(bcx)) { ret r; + } else { + // The value resulting from the block gets copied into an + // alloca created in an enclosing scope and it's refcount + // bumped so that it can escape this block. This means that + // it will definitely live until the end of the enclosing + // scope, even if nobody uses it, which may be something of + // a surprise. + + auto r_ty = ty.expr_ty(e); + + fn is_nil(@ty.t r_ty) -> bool { + alt (r_ty.struct) { + case (ty.ty_nil) { + ret true; + } + case (_) { + ret false; + } + } + } + + // FIXME: This is a temporary hack to prevent compile + // failures. There's some expression variant that claims + // to be ty_nil but but does not translate to T_nil. Need + // to hunt it down. + if (!is_nil(r_ty)) { + // This alloca is declared at the function level, above + // the block scope + auto res_alloca = alloc_ty(bcx, r_ty); + bcx = res_alloca.bcx; + auto res_copy = copy_ty(bcx, INIT, + res_alloca.val, r.val, r_ty); + bcx = res_copy.bcx; + + fn drop_hoisted_ty(@block_ctxt cx, + ValueRef alloca_val, + @ty.t t) -> result { + auto reg_val = load_scalar_or_boxed(cx, + alloca_val, t); + ret drop_ty(cx, reg_val, t); + } + + auto cleanup = bind drop_hoisted_ty(_, res_alloca.val, + r_ty); + find_outer_scope_cx(bcx).cleanups += vec(clean(cleanup)); + } } } case (none[@ast.expr]) { From 19a949c15eb0a6179e62c6ac1a540ff15ede1a25 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 21:20:46 -0400 Subject: [PATCH 05/13] Un-XFAIL expr-block-box.rs --- src/test/run-pass/expr-block-box.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/run-pass/expr-block-box.rs b/src/test/run-pass/expr-block-box.rs index b324994a8e8cf..cee2a04c1aef2 100644 --- a/src/test/run-pass/expr-block-box.rs +++ b/src/test/run-pass/expr-block-box.rs @@ -1,5 +1,4 @@ // xfail-boot -// xfail-stage0 // -*- rust -*- fn main() { From c27b72e323d1aabb0eeb9939feb5584bc28ba9e9 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 21:45:08 -0400 Subject: [PATCH 06/13] Add another test for blocks as expressions --- src/test/run-pass/expr-block.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/run-pass/expr-block.rs diff --git a/src/test/run-pass/expr-block.rs b/src/test/run-pass/expr-block.rs new file mode 100644 index 0000000000000..ecc6f04a34029 --- /dev/null +++ b/src/test/run-pass/expr-block.rs @@ -0,0 +1,31 @@ +// xfail-boot +// -*- rust -*- + +// Tests for standalone blocks as expressions + +fn test_basic() { + let bool res = { true }; + check (res); +} + +fn test_rec() { + auto res = { rec(v1 = 10, v2 = 20) }; + check (res.v2 == 20); +} + +fn test_filled_with_stuff() { + auto res = { + auto a = 0; + while (a < 10) { + a += 1; + } + a + }; + check (res == 10); +} + +fn main() { + test_basic(); + test_rec(); + test_filled_with_stuff(); +} From cf16f4f7e5bf5d37fc0e254e3c7ccdf0623c50d3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 21:47:53 -0400 Subject: [PATCH 07/13] Add a test for block expressions of generic types. XFAILed --- src/test/run-pass/expr-block-generic.rs | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/test/run-pass/expr-block-generic.rs diff --git a/src/test/run-pass/expr-block-generic.rs b/src/test/run-pass/expr-block-generic.rs new file mode 100644 index 0000000000000..fc34d112419d7 --- /dev/null +++ b/src/test/run-pass/expr-block-generic.rs @@ -0,0 +1,56 @@ +// xfail-boot +// xfail-stage0 +// -*- rust -*- + +// Tests for standalone blocks as expressions with dynamic type sizes + +type compare[T] = fn(&T t1, &T t2) -> bool; + +fn test_generic[T](&T expected, &compare[T] eq) { + let T actual = { expected }; + check (eq(expected, actual)); +} + +fn test_bool() { + fn compare_bool(&bool b1, &bool b2) -> bool { + ret b1 == b2; + } + auto eq = bind compare_bool(_, _); + test_generic[bool](true, eq); +} + + +fn test_tup() { + type t = tup(int, int); + fn compare_tup(&t t1, &t t2) -> bool { + ret t1 == t2; + } + auto eq = bind compare_tup(_, _); + test_generic[t](tup(1, 2), eq); +} + +fn test_vec() { + fn compare_vec(&vec[int] v1, &vec[int] v2) -> bool { + ret v1 == v2; + } + auto eq = bind compare_vec(_, _); + test_generic[vec[int]](vec(1, 2), eq); +} + +fn test_box() { + fn compare_box(&@bool b1, &@bool b2) -> bool { + ret *b1 == *b2; + } + auto eq = bind compare_box(_, _); + test_generic[@bool](@true, eq); +} + +fn main() { + test_bool(); + test_tup(); + // FIXME: These two don't pass yet + test_vec(); + test_box(); +} + + From f05d3c516b085bd489893d7885be0bb687a786f7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 22:01:35 -0400 Subject: [PATCH 08/13] Add more comments to trans_block --- src/comp/middle/trans.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 6c072c61e83b1..dd11891c0749a 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5407,7 +5407,8 @@ fn trans_block(@block_ctxt cx, &ast.block b) -> result { // FIXME: This is a temporary hack to prevent compile // failures. There's some expression variant that claims // to be ty_nil but but does not translate to T_nil. Need - // to hunt it down. + // to hunt it down. Of course, if we're talking about nil, + // do we really want to do this whole business anyway? if (!is_nil(r_ty)) { // This alloca is declared at the function level, above // the block scope From 524e80358254575bb699756c405050da6c920e28 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 22:32:02 -0400 Subject: [PATCH 09/13] Only use allocas to hold expression results for boxed types --- src/comp/middle/trans.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index dd11891c0749a..f6d59b9292d83 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5393,25 +5393,10 @@ fn trans_block(@block_ctxt cx, &ast.block b) -> result { auto r_ty = ty.expr_ty(e); - fn is_nil(@ty.t r_ty) -> bool { - alt (r_ty.struct) { - case (ty.ty_nil) { - ret true; - } - case (_) { - ret false; - } - } - } + if (ty.type_is_boxed(r_ty)) { - // FIXME: This is a temporary hack to prevent compile - // failures. There's some expression variant that claims - // to be ty_nil but but does not translate to T_nil. Need - // to hunt it down. Of course, if we're talking about nil, - // do we really want to do this whole business anyway? - if (!is_nil(r_ty)) { - // This alloca is declared at the function level, above - // the block scope + // Create an alloca up in the llallocas block to hold the + // expression result. auto res_alloca = alloc_ty(bcx, r_ty); bcx = res_alloca.bcx; auto res_copy = copy_ty(bcx, INIT, From f16e7242d2433378a0530d31427fad4ddd36c69f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 23:11:26 -0400 Subject: [PATCH 10/13] Initialize the alloca used to retrieve boxed block results to null. This allows blocks to be used in conditional constructs where the block may not ever execute: the drop glue will notice that it was never used and ignore it. Also, beef up the comments. --- src/comp/middle/trans.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index f6d59b9292d83..c04e97489a874 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5384,21 +5384,29 @@ fn trans_block(@block_ctxt cx, &ast.block b) -> result { if (is_terminated(bcx)) { ret r; } else { - // The value resulting from the block gets copied into an - // alloca created in an enclosing scope and it's refcount - // bumped so that it can escape this block. This means that - // it will definitely live until the end of the enclosing - // scope, even if nobody uses it, which may be something of - // a surprise. - auto r_ty = ty.expr_ty(e); if (ty.type_is_boxed(r_ty)) { - - // Create an alloca up in the llallocas block to hold the - // expression result. + // The value resulting from the block gets copied into an + // alloca created in an outer scope and it's refcount + // bumped so that it can escape this block. This means + // that it will definitely live until the end of the + // enclosing scope, even if nobody uses it, which may be + // something of a surprise. + + // It's possible we never hit this block, so the alloca + // must be initialized to null, then when the potential + // value finally goes out of scope the drop glue will see + // that it was never used and ignore it. + + // NB: Here we're building and initalizing the alloca in + // the alloca context, not this block's context. auto res_alloca = alloc_ty(bcx, r_ty); - bcx = res_alloca.bcx; + auto alloca_ty = type_of(bcx.fcx.ccx, r_ty); + auto builder = new_builder(bcx.fcx.llallocas); + builder.Store(C_null(alloca_ty), res_alloca.val); + + // Now we're working in our own block context again auto res_copy = copy_ty(bcx, INIT, res_alloca.val, r.val, r_ty); bcx = res_copy.bcx; From dcf04ffbad5f581a8873fd477af83c2814aa7c12 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Mar 2011 23:14:05 -0400 Subject: [PATCH 11/13] Un-XFAIL expr-if-box.rs --- src/test/run-pass/expr-if-box.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/run-pass/expr-if-box.rs b/src/test/run-pass/expr-if-box.rs index 30dce957235b2..a629c9c9bc464 100644 --- a/src/test/run-pass/expr-if-box.rs +++ b/src/test/run-pass/expr-if-box.rs @@ -1,5 +1,4 @@ // xfail-boot -// xfail-stage0 // -*- rust -*- // Tests for if as expressions returning boxed types From efb738153c7248601a9a1b294b0ad8fd9c27023c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 28 Mar 2011 00:46:16 -0400 Subject: [PATCH 12/13] Add an XFAILed test for treating alts as expressions --- src/test/run-pass/expr-alt.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/run-pass/expr-alt.rs diff --git a/src/test/run-pass/expr-alt.rs b/src/test/run-pass/expr-alt.rs new file mode 100644 index 0000000000000..859c593850a6b --- /dev/null +++ b/src/test/run-pass/expr-alt.rs @@ -0,0 +1,31 @@ +// xfail-boot +// xfail-stage0 +// -*- rust -*- + +// Tests for using alt as an expression + +fn test() { + let bool res = alt (true) { + case (true) { + true + } + case (false) { + false + } + }; + check (res); + + res = alt(false) { + case (true) { + false + } + case (false) { + true + } + }; + check (res); +} + +fn main() { + test(); +} \ No newline at end of file From 1bc06bc59b048bc803bfd6029c923a73ba2bb3ff Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 1 Apr 2011 00:00:20 -0400 Subject: [PATCH 13/13] Cleanup typos and newlines --- src/comp/middle/trans.rs | 2 +- src/test/run-pass/expr-alt.rs | 2 +- src/test/run-pass/expr-block-box.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index c04e97489a874..fca1c6c0bc23b 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5388,7 +5388,7 @@ fn trans_block(@block_ctxt cx, &ast.block b) -> result { if (ty.type_is_boxed(r_ty)) { // The value resulting from the block gets copied into an - // alloca created in an outer scope and it's refcount + // alloca created in an outer scope and its refcount // bumped so that it can escape this block. This means // that it will definitely live until the end of the // enclosing scope, even if nobody uses it, which may be diff --git a/src/test/run-pass/expr-alt.rs b/src/test/run-pass/expr-alt.rs index 859c593850a6b..22cdf32a67230 100644 --- a/src/test/run-pass/expr-alt.rs +++ b/src/test/run-pass/expr-alt.rs @@ -28,4 +28,4 @@ fn test() { fn main() { test(); -} \ No newline at end of file +} diff --git a/src/test/run-pass/expr-block-box.rs b/src/test/run-pass/expr-block-box.rs index cee2a04c1aef2..e8ab62091a59d 100644 --- a/src/test/run-pass/expr-block-box.rs +++ b/src/test/run-pass/expr-block-box.rs @@ -7,4 +7,4 @@ fn main() { }; check (*x == 100); -} \ No newline at end of file +}