compiler: Preserve exclusive loans for conditional cell borrows
4af3a3b7986d92ab09941b64e0d07f995886468b21d8316da15769c96a89dad7
1 parent
0c149827
lib/std/lang/resolver.rad
+2 -0
| 8583 | 8583 | fn createsCellBorrow(node: *ast::Node) -> bool { |
|
| 8584 | 8584 | match node.value { |
|
| 8585 | 8585 | case ast::NodeValue::AddressOf(address) => return address.kind == ast::AddressKind::Cell, |
|
| 8586 | 8586 | case ast::NodeValue::As(expr) => return createsCellBorrow(expr.value), |
|
| 8587 | 8587 | case ast::NodeValue::RegionApply { value, .. } => return createsCellBorrow(value), |
|
| 8588 | + | case ast::NodeValue::CondExpr(cond) => |
|
| 8589 | + | return createsCellBorrow(cond.thenExpr) or createsCellBorrow(cond.elseExpr), |
|
| 8588 | 8590 | else => return false, |
|
| 8589 | 8591 | } |
|
| 8590 | 8592 | } |
|
| 8591 | 8593 | ||
| 8592 | 8594 | /// Find the exclusive handle that owns an addressed place. |
lib/std/lang/resolver/tests/regions.rad
+35 -0
| 56 | 56 | else throw testing::TestError::Failed; |
|
| 57 | 57 | } |
|
| 58 | 58 | } |
|
| 59 | 59 | } |
|
| 60 | 60 | ||
| 61 | + | /// Conditional cell creation protects each source from ordinary shared access. |
|
| 62 | + | @test unsafe fn testConditionalCellArgumentLoans() throws (testing::TestError) { |
|
| 63 | + | for program in [ |
|
| 64 | + | "fn inspect(c: &cell u32, p: &u32) { set *c = 2; } fn f(p: &mut u32, q: &mut u32, flag: bool) { inspect(&cell *p if flag else &cell *q, p); }", |
|
| 65 | + | "fn inspect(c: &cell u32, p: &u32) { set *c = 2; } unsafe fn f(p: &mut u32, q: &mut u32, flag: bool) { inspect(&cell *p if flag else &cell *q, q); }", |
|
| 66 | + | "fn read(p: &u32) -> u32 { return *p; } fn inspect(c: &cell u32, n: u32) {} fn f(p: &mut u32, q: &mut u32, flag: bool) { inspect(&cell *p if flag else &cell *q, read(q)); }", |
|
| 67 | + | "fn inspect(c: &cell u32, p: &u32) {} fn f(p: &mut u32, q: &mut u32, flag: bool) { inspect((&cell *p if flag else &cell *q) as &cell u32, p); }", |
|
| 68 | + | ] { |
|
| 69 | + | let mut arena = super::testArena(); |
|
| 70 | + | let storage: 'test = &mut arena in { |
|
| 71 | + | let mut res = super::testResolver(storage); |
|
| 72 | + | let result = try super::resolveProgramStr(&mut res, program); |
|
| 73 | + | let error = try super::expectError(&result); |
|
| 74 | + | let case resolver::ErrorKind::BorrowConflict(_) = error.kind |
|
| 75 | + | else throw testing::TestError::Failed; |
|
| 76 | + | } |
|
| 77 | + | } |
|
| 78 | + | } |
|
| 79 | + | ||
| 80 | + | /// Conditional cell loans allow separate storage and shared cell aliases. |
|
| 81 | + | @test unsafe fn testConditionalCellArgumentLoanScopes() throws (testing::TestError) { |
|
| 82 | + | for program in [ |
|
| 83 | + | "fn inspect(c: &cell u32, p: &u32) {} fn f(p: &mut u32, q: &mut u32, r: &u32, flag: bool) { inspect(&cell *p if flag else &cell *q, r); set *p = 1; set *q = 2; }", |
|
| 84 | + | "record R { a: u32, b: u32, c: u32 } fn inspect(c: &cell u32, p: &u32) {} fn f(r: &mut R, flag: bool) { inspect(&cell r.a if flag else &cell r.b, &r.c); set r.a = 1; }", |
|
| 85 | + | "fn inspect(a: &cell u32, b: &cell u32) {} fn f(a: &cell u32, b: &cell u32, flag: bool) { inspect(a if flag else b, a); }", |
|
| 86 | + | ] { |
|
| 87 | + | let mut arena = super::testArena(); |
|
| 88 | + | let storage: 'test = &mut arena in { |
|
| 89 | + | let mut res = super::testResolver(storage); |
|
| 90 | + | let result = try super::resolveProgramStr(&mut res, program); |
|
| 91 | + | try super::expectNoErrors(&result); |
|
| 92 | + | } |
|
| 93 | + | } |
|
| 94 | + | } |
|
| 95 | + | ||
| 61 | 96 | /// Conditional explicit arguments protect every possible borrowed place. |
|
| 62 | 97 | @test unsafe fn testConditionalCallArgumentLoans() throws (testing::TestError) { |
|
| 63 | 98 | for program in [ |
|
| 64 | 99 | "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(&*p if flag else &*q, inner(p)); }", |
|
| 65 | 100 | "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(&*p if flag else &*q, inner(q)); }", |