compiler: Merge ownership across short-circuit paths

f6689102ee79bee104a4566df03fad7f0ee35cc9814e268a52c2119273f66830
Alexis Sellier committed ago 1 parent bcc4a622
lib/std/lang/resolver.rad +8 -0
11226 11226
            }
11227 11227
            try checkLinearNode(checker, env, repeat.item, LinearUse::Consume);
11228 11228
            try checkLinearNode(checker, env, repeat.count, LinearUse::Consume);
11229 11229
        }
11230 11230
        case ast::NodeValue::BinOp(op) => {
11231 +
            if op.op == ast::BinaryOp::And or op.op == ast::BinaryOp::Or {
11232 +
                try checkLinearNode(checker, env, op.left, LinearUse::Consume);
11233 +
                let skipped = *env;
11234 +
                let mut evaluated = skipped;
11235 +
                try checkLinearNode(checker, &mut evaluated, op.right, LinearUse::Consume);
11236 +
                try joinLinearBranches(checker, env, &skipped, &evaluated, node);
11237 +
                return;
11238 +
            }
11231 11239
            let mut operandUse = LinearUse::Consume;
11232 11240
            match op.op {
11233 11241
                case ast::BinaryOp::Eq, ast::BinaryOp::Ne,
11234 11242
                     ast::BinaryOp::Lt, ast::BinaryOp::Gt,
11235 11243
                     ast::BinaryOp::Lte, ast::BinaryOp::Gte =>
lib/std/lang/resolver/tests/regions.rad +34 -0
3 3
use std::mem;
4 4
use std::testing;
5 5
use std::lang::types;
6 6
use std::lang::resolver;
7 7
8 +
/// Short-circuit paths must agree on exact-use regional ownership.
9 +
@test unsafe fn testRegionalShortCircuitOwnership() throws (testing::TestError) {
10 +
    for program in [
11 +
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r) { let result = false and take(t); }",
12 +
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r) { let result = true or take(t); }",
13 +
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r, flag: bool) { let result = flag and take(t); }",
14 +
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } unsafe fn f 'r (t: Ticket 'r, flag: bool) { let result = flag or take(t); }",
15 +
    ] {
16 +
        let mut arena = super::testArena();
17 +
        let storage: 'test = &mut arena in {
18 +
            let mut res = super::testResolver(storage);
19 +
            let result = try super::resolveProgramStr(&mut res, program);
20 +
            let error = try super::expectError(&result);
21 +
            let case resolver::ErrorKind::LinearBranchMismatch(_) = error.kind
22 +
                else throw testing::TestError::Failed;
23 +
        }
24 +
    }
25 +
}
26 +
27 +
/// The left operand executes on every short-circuit path.
28 +
@test unsafe fn testRegionalShortCircuitLeftConsumption() throws (testing::TestError) {
29 +
    for program in [
30 +
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r) { let result = take(t) and false; }",
31 +
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r) { let result = take(t) or true; }",
32 +
    ] {
33 +
        let mut arena = super::testArena();
34 +
        let storage: 'test = &mut arena in {
35 +
            let mut res = super::testResolver(storage);
36 +
            let result = try super::resolveProgramStr(&mut res, program);
37 +
            try super::expectNoErrors(&result);
38 +
        }
39 +
    }
40 +
}
41 +
8 42
/// Earlier reference arguments protect their storage during later arguments.
9 43
@test unsafe fn testRegionalCallArgumentLoans() throws (testing::TestError) {
10 44
    for program in [
11 45
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &mut u32, n: u32) {} fn f 'r (p: &'r mut u32) { outer(&mut *p, inner(p)); }",
12 46
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32) { outer(&*p, inner(p)); }",