compiler: Merge ownership across short-circuit paths

b2c3593c2d69bf5e847e78619610c61ce1596f09d4b074a27bbdbaf5da40eb74
Alexis Sellier committed ago 1 parent 4f712f07
lib/std/lang/resolver.rad +8 -0
8593 8593
            }
8594 8594
            try checkLinearNode(checker, env, repeat.item, LinearUse::Consume);
8595 8595
            try checkLinearNode(checker, env, repeat.count, LinearUse::Consume);
8596 8596
        }
8597 8597
        case ast::NodeValue::BinOp(op) => {
8598 +
            if op.op == ast::BinaryOp::And or op.op == ast::BinaryOp::Or {
8599 +
                try checkLinearNode(checker, env, op.left, LinearUse::Consume);
8600 +
                let skipped = *env;
8601 +
                let mut evaluated = skipped;
8602 +
                try checkLinearNode(checker, &mut evaluated, op.right, LinearUse::Consume);
8603 +
                try joinLinearBranches(checker, env, &skipped, &evaluated, node);
8604 +
                return;
8605 +
            }
8598 8606
            let mut operandUse = LinearUse::Consume;
8599 8607
            match op.op {
8600 8608
                case ast::BinaryOp::Eq, ast::BinaryOp::Ne,
8601 8609
                     ast::BinaryOp::Lt, ast::BinaryOp::Gt,
8602 8610
                     ast::BinaryOp::Lte, ast::BinaryOp::Gte =>
lib/std/lang/resolver/tests.rad +27 -0
6394 6394
        let result = try resolveProgramStr(&mut res, program);
6395 6395
        try expectNoErrors(&result);
6396 6396
    }
6397 6397
}
6398 6398
6399 +
/// Short-circuit paths must agree on exact-use ownership.
6400 +
@test unsafe fn testShortCircuitOwnership() throws (testing::TestError) {
6401 +
    for program in [
6402 +
        "union Ticket: Once { Value(u32) } fn take(t: Ticket) -> bool { match t { case Ticket::Value(n) => return n == 1, } } fn f(t: Ticket) { let result = false and take(t); }",
6403 +
        "union Ticket: Once { Value(u32) } fn take(t: Ticket) -> bool { match t { case Ticket::Value(n) => return n == 1, } } fn f(t: Ticket) { let result = true or take(t); }",
6404 +
        "union Ticket: Once { Value(u32) } fn take(t: Ticket) -> bool { match t { case Ticket::Value(n) => return n == 1, } } fn f(t: Ticket, flag: bool) { let result = flag and take(t); }",
6405 +
        "union Ticket: Once { Value(u32) } fn take(t: Ticket) -> bool { match t { case Ticket::Value(n) => return n == 1, } } unsafe fn f(t: Ticket, flag: bool) { let result = flag or take(t); }",
6406 +
    ] {
6407 +
        let mut res = testResolver();
6408 +
        let result = try resolveProgramStr(&mut res, program);
6409 +
        let error = try expectError(&result);
6410 +
        let case super::ErrorKind::LinearBranchMismatch(_) = error.kind
6411 +
            else throw testing::TestError::Failed;
6412 +
    }
6413 +
}
6414 +
6415 +
/// The left operand executes on every short-circuit path.
6416 +
@test unsafe fn testShortCircuitLeftConsumption() throws (testing::TestError) {
6417 +
    for program in [
6418 +
        "union Ticket: Once { Value(u32) } fn take(t: Ticket) -> bool { match t { case Ticket::Value(n) => return n == 1, } } fn f(t: Ticket) { let result = take(t) and false; }",
6419 +
        "union Ticket: Once { Value(u32) } fn take(t: Ticket) -> bool { match t { case Ticket::Value(n) => return n == 1, } } fn f(t: Ticket) { let result = take(t) or true; }",
6420 +
    ] {
6421 +
        let mut res = testResolver();
6422 +
        let result = try resolveProgramStr(&mut res, program);
6423 +
        try expectNoErrors(&result);
6424 +
    }
6425 +
}