Change the destructor-ordering test to use channels instead of a shared mutable object.
This test used to take advantage of a hole in the type system that allows objects with destructors to refer to stateful objects.
This commit is contained in:
parent
fdb842f9e6
commit
987589e946
@ -389,6 +389,7 @@ TEST_XFAILS_X86 := $(TASK_XFAILS) \
|
||||
test/run-pass/child-outlives-parent.rs \
|
||||
test/run-pass/clone-with-exterior.rs \
|
||||
test/run-pass/constrained-type.rs \
|
||||
test/run-pass/destructor-ordering.rs \
|
||||
test/run-pass/obj-as.rs \
|
||||
test/run-pass/vec-slice.rs \
|
||||
test/run-pass/fn-lval.rs \
|
||||
|
@ -1,58 +1,93 @@
|
||||
// We share an instance of this type among all the destructor-order
|
||||
// checkers. It tracks how many destructors have run so far and
|
||||
// 'fail's when one runs out of order.
|
||||
// FIXME: Make it easier to collect a failure message.
|
||||
state obj order_tracker(mutable int init) {
|
||||
fn assert_order(int expected, str fail_message) {
|
||||
if (expected != init) {
|
||||
log expected;
|
||||
// This test checks that destructors run in the right order. Because
|
||||
// stateful objects can't have destructors, we have the destructors
|
||||
// record their expected order into a channel when they execute (so
|
||||
// the object becomes 'io' rather than 'state'). Then each test case
|
||||
// asserts that the channel produces values in ascending order.
|
||||
//
|
||||
// FIXME: Write an int->str function and concatenate the whole failure
|
||||
// message into a single log statement (or, even better, a print).
|
||||
//
|
||||
// FIXME: check_order should take only 1 line in a test, not 2+a block
|
||||
// block. Since destructor-having objects can't refer to mutable state
|
||||
// (like the port), we'd need a with-like construct to do the same for
|
||||
// stateful objects within a scope.
|
||||
//
|
||||
// FIXME #21: Each test should execute in its own task, so it can fail
|
||||
// independently, writing its error message to a channel that the
|
||||
// parent task aggregates.
|
||||
|
||||
type order_info = rec(int order, str msg);
|
||||
|
||||
io fn check_order(port[order_info] expected_p) {
|
||||
chan(expected_p) <| rec(order=-1, msg="");
|
||||
let mutable int actual = 0;
|
||||
auto expected <- expected_p; // FIXME #121: Workaround for while(true) bug.
|
||||
auto done = -1; // FIXME: Workaround for typechecking bug.
|
||||
while(expected.order != done) {
|
||||
if (expected.order != actual) {
|
||||
log expected.order;
|
||||
log " != ";
|
||||
log init;
|
||||
log fail_message;
|
||||
log actual;
|
||||
log expected.msg;
|
||||
fail;
|
||||
}
|
||||
init += 1;
|
||||
actual += 1;
|
||||
expected <- expected_p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
obj dorder(@order_tracker tracker, int order, str message) {
|
||||
obj dorder(chan[order_info] expected, int order, str message) {
|
||||
drop {
|
||||
tracker.assert_order(order, message);
|
||||
expected <| rec(order=order, msg=message);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_simple() {
|
||||
auto tracker = @order_tracker(0);
|
||||
io fn test_simple() {
|
||||
let port[order_info] tracker_p = port();
|
||||
auto tracker = chan(tracker_p);
|
||||
dorder(tracker, 1, "Reverse decl order");
|
||||
dorder(tracker, 0, "Reverse decl order");
|
||||
check_order(tracker_p);
|
||||
}
|
||||
|
||||
fn test_block() {
|
||||
auto tracker = @order_tracker(0);
|
||||
dorder(tracker, 2, "Before block");
|
||||
io fn test_block() {
|
||||
let port[order_info] tracker_p = port();
|
||||
auto tracker = chan(tracker_p);
|
||||
{
|
||||
dorder(tracker, 0, "Inside block");
|
||||
dorder(tracker, 2, "Before block");
|
||||
{
|
||||
dorder(tracker, 0, "Inside block");
|
||||
}
|
||||
dorder(tracker, 1, "After block");
|
||||
}
|
||||
dorder(tracker, 1, "After block");
|
||||
check_order(tracker_p);
|
||||
}
|
||||
|
||||
fn test_decl_v_init() {
|
||||
auto tracker = @order_tracker(0);
|
||||
auto var1;
|
||||
auto var2;
|
||||
var2 = dorder(tracker, 0, "decl, not init");
|
||||
var1 = dorder(tracker, 1, "decl, not init");
|
||||
}
|
||||
|
||||
fn test_overwritten_obj() {
|
||||
auto tracker = @order_tracker(0);
|
||||
auto var1 = dorder(tracker, 0, "overwritten object destroyed first");
|
||||
auto var2 = dorder(tracker, 2, "destroyed at end of scope");
|
||||
var1 = dorder(tracker, 3, "overwriter deleted in rev decl order");
|
||||
io fn test_decl_v_init() {
|
||||
let port[order_info] tracker_p = port();
|
||||
auto tracker = chan(tracker_p);
|
||||
{
|
||||
dorder(tracker, 1, "overwritten object destroyed before end of scope");
|
||||
auto var1;
|
||||
auto var2;
|
||||
var2 = dorder(tracker, 0, "decl, not init");
|
||||
var1 = dorder(tracker, 1, "decl, not init");
|
||||
}
|
||||
check_order(tracker_p);
|
||||
}
|
||||
|
||||
io fn test_overwritten_obj() {
|
||||
let port[order_info] tracker_p = port();
|
||||
auto tracker = chan(tracker_p);
|
||||
{
|
||||
auto var1 = dorder(tracker, 0, "overwritten object destroyed first");
|
||||
auto var2 = dorder(tracker, 2, "destroyed at end of scope");
|
||||
var1 = dorder(tracker, 3, "overwriter deleted in rev decl order");
|
||||
{
|
||||
dorder(tracker, 1, "overwritten object destroyed before end of scope");
|
||||
}
|
||||
}
|
||||
check_order(tracker_p);
|
||||
}
|
||||
|
||||
// Used to embed dorder objects into an expression. Note that the
|
||||
@ -60,17 +95,21 @@ fn test_overwritten_obj() {
|
||||
fn combine_dorders(dorder d1, dorder d2) -> int {
|
||||
ret 1;
|
||||
}
|
||||
fn test_expression_destroyed_right_to_left() {
|
||||
auto tracker = @order_tracker(0);
|
||||
combine_dorders(dorder(tracker, 4, ""), dorder(tracker, 3, ""))
|
||||
/ combine_dorders(dorder(tracker, 2, ""), dorder(tracker, 1, ""));
|
||||
io fn test_expression_destroyed_right_to_left() {
|
||||
let port[order_info] tracker_p = port();
|
||||
auto tracker = chan(tracker_p);
|
||||
{
|
||||
dorder(tracker, 0,
|
||||
"expression objects live to end of block, not statement");
|
||||
combine_dorders(dorder(tracker, 4, ""), dorder(tracker, 3, ""))
|
||||
/ combine_dorders(dorder(tracker, 2, ""), dorder(tracker, 1, ""));
|
||||
{
|
||||
dorder(tracker, 0,
|
||||
"expression objects live to end of block, not statement");
|
||||
}
|
||||
}
|
||||
check_order(tracker_p);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
io fn main() {
|
||||
test_simple();
|
||||
test_block();
|
||||
test_decl_v_init();
|
||||
|
Loading…
Reference in New Issue
Block a user