Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block expression results #305

Merged
merged 13 commits into from
Apr 1, 2011
Merged
53 changes: 53 additions & 0 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -5368,8 +5380,49 @@ 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 {
auto r_ty = ty.expr_ty(e);

if (ty.type_is_boxed(r_ty)) {
// The value resulting from the block gets copied into an
// 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
// 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);
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;

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]) {
Expand Down
18 changes: 18 additions & 0 deletions src/comp/pretty/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
31 changes: 31 additions & 0 deletions src/test/run-pass/expr-alt.rs
Original file line number Diff line number Diff line change
@@ -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();
}
10 changes: 10 additions & 0 deletions src/test/run-pass/expr-block-box.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// xfail-boot
// -*- rust -*-

fn main() {
auto x = {
@100
};

check (*x == 100);
}
56 changes: 56 additions & 0 deletions src/test/run-pass/expr-block-generic.rs
Original file line number Diff line number Diff line change
@@ -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();
}


31 changes: 31 additions & 0 deletions src/test/run-pass/expr-block.rs
Original file line number Diff line number Diff line change
@@ -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();
}
9 changes: 7 additions & 2 deletions src/test/run-pass/expr-if-box.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// xfail-boot
// xfail-stage0
// -*- rust -*-

// Tests for if as expressions returning boxed types
Expand All @@ -9,6 +8,12 @@ fn test_box() {
check (*res == 100);
}

fn test_str() {
auto res = if (true) { "happy" } else { "sad" };
check (res == "happy");
}

fn main() {
test_box();
}
test_str();
}
6 changes: 0 additions & 6 deletions src/test/run-pass/expr-if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -94,5 +89,4 @@ fn main() {
test_inferrence();
test_if_as_if_condition();
test_if_as_block_result();
test_str();
}