compiler: Merge ownership across short-circuit paths
f6689102ee79bee104a4566df03fad7f0ee35cc9814e268a52c2119273f66830
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)); }", |