compiler: Merge ownership across short-circuit paths
b2c3593c2d69bf5e847e78619610c61ce1596f09d4b074a27bbdbaf5da40eb74
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 | + | } |