compiler/
kernel/
lib/
examples/
std/
arch/
char/
collections/
lang/
alloc/
ast/
gen/
il/
module/
parser/
resolver/
tests/
regions.rad
74.2 KiB
printer.rad
24.7 KiB
tests.rad
383.5 KiB
scanner/
alloc.rad
7.1 KiB
ast.rad
26.7 KiB
gen.rad
513 B
il.rad
19.5 KiB
lower.rad
308.1 KiB
module.rad
14.9 KiB
package.rad
1.3 KiB
parser.rad
89.5 KiB
resolver.rad
439.6 KiB
scanner.rad
18.0 KiB
sexpr.rad
6.4 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
9.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
662 B
lib/std/lang/resolver/tests/regions.rad
raw
| 1 | //! Lexical region resolver tests. |
| 2 | |
| 3 | use std::mem; |
| 4 | use std::testing; |
| 5 | use std::lang::types; |
| 6 | use std::lang::resolver; |
| 7 | |
| 8 | /// Equal region spellings in separate functions have distinct identities. |
| 9 | @test unsafe fn testRegionIdentities() throws (testing::TestError) { |
| 10 | let mut testArena1 = super::testArena(); |
| 11 | let testStorage1: 'test1 = &mut testArena1 in { |
| 12 | let mut res = super::testResolver(testStorage1); |
| 13 | let result = try super::resolveProgramStr(&mut res, |
| 14 | "fn first 'r (p: &'r u8) -> u8 { return *p; }\nfn second 'r (p: &'r u8) -> u8 { return *p; }" |
| 15 | ); |
| 16 | try super::expectNoErrors(&result); |
| 17 | let first = try super::getBlockStmt(result.root, 0); |
| 18 | let second = try super::getBlockStmt(result.root, 1); |
| 19 | let firstType = resolver::typeFor(&res, first) else throw testing::TestError::Failed; |
| 20 | let secondType = resolver::typeFor(&res, second) else throw testing::TestError::Failed; |
| 21 | let case resolver::Type::Fn(a) = firstType else throw testing::TestError::Failed; |
| 22 | let case resolver::Type::Fn(b) = secondType else throw testing::TestError::Failed; |
| 23 | let case resolver::Type::Pointer { class: types::PointerClass::Region(ar), .. } = *a.paramTypes[0] |
| 24 | else throw testing::TestError::Failed; |
| 25 | let case resolver::Type::Pointer { class: types::PointerClass::Region(br), .. } = *b.paramTypes[0] |
| 26 | else throw testing::TestError::Failed; |
| 27 | try testing::expect(mem::eq(ar.name, br.name)); |
| 28 | try testing::expect(ar.id <> br.id); |
| 29 | try testing::expect(not resolver::typesEqual(*a.paramTypes[0], *b.paramTypes[0])); |
| 30 | try testing::expect(resolver::getTypeLayout(*a.paramTypes[0]).size == 8); |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | /// Parent links resolve forward declarations and preserve transitive ancestry. |
| 35 | @test unsafe fn testRegionParents() throws (testing::TestError) { |
| 36 | let mut testArena2 = super::testArena(); |
| 37 | let testStorage2: 'test2 = &mut testArena2 in { |
| 38 | let mut res = super::testResolver(testStorage2); |
| 39 | let result = try super::resolveProgramStr(&mut res, |
| 40 | "fn read 'child 'middle 'root (p: &'child u8, q: &'root u8) where 'middle: 'child, 'root: 'middle {}" |
| 41 | ); |
| 42 | try super::expectNoErrors(&result); |
| 43 | let func = try super::getBlockStmt(result.root, 0); |
| 44 | let ty = resolver::typeFor(&res, func) else throw testing::TestError::Failed; |
| 45 | let case resolver::Type::Fn(info) = ty else throw testing::TestError::Failed; |
| 46 | let case resolver::Type::Pointer { class: types::PointerClass::Region(child), .. } = *info.paramTypes[0] |
| 47 | else throw testing::TestError::Failed; |
| 48 | let case resolver::Type::Pointer { class: types::PointerClass::Region(root), .. } = *info.paramTypes[1] |
| 49 | else throw testing::TestError::Failed; |
| 50 | try testing::expect(types::regionContains(root, child)); |
| 51 | try testing::expect(types::regionContains(child, child)); |
| 52 | try testing::expect(not types::regionContains(child, root)); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | /// Region declarations reject duplicate names, missing parents, and cycles. |
| 57 | @test unsafe fn testInvalidRegionDeclarations() throws (testing::TestError) { |
| 58 | for program in [ |
| 59 | "fn f 'r 'r () {}", |
| 60 | "fn f 'r () where 'missing: 'r {}", |
| 61 | "fn f 'r () where 'r: 'r {}", |
| 62 | "fn f 'a 'b 'c () where 'b: 'a, 'c: 'b, 'a: 'c {}", |
| 63 | ] { |
| 64 | let mut testArena3 = super::testArena(); |
| 65 | let testStorage3: 'test3 = &mut testArena3 in { |
| 66 | let mut res = super::testResolver(testStorage3); |
| 67 | let result = try super::resolveProgramStr(&mut res, program); |
| 68 | let _ = try super::expectError(&result); |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | /// Regions from another declaration cannot enter a function signature or body. |
| 74 | @test unsafe fn testUnknownRegionNames() throws (testing::TestError) { |
| 75 | for program in [ |
| 76 | "fn f(p: &'missing u8) {}", |
| 77 | "fn f 'r (p: &'r u8) {} fn g(p: &'r u8) {}", |
| 78 | "unsafe fn f(p: &'missing u8) {}", |
| 79 | "fn f 'r (p: &'r u8) { let q: &'missing u8 = p; }", |
| 80 | ] { |
| 81 | let mut testArena4 = super::testArena(); |
| 82 | let testStorage4: 'test4 = &mut testArena4 in { |
| 83 | let mut res = super::testResolver(testStorage4); |
| 84 | let result = try super::resolveProgramStr(&mut res, program); |
| 85 | let err = try super::expectError(&result); |
| 86 | let case resolver::ErrorKind::UnknownRegion(_) = err.kind |
| 87 | else throw testing::TestError::Failed; |
| 88 | } |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | /// An ancestor relation does not make distinct reference regions assignable. |
| 93 | @test unsafe fn testRegionInvariance() throws (testing::TestError) { |
| 94 | for program in [ |
| 95 | "fn f 'a 'b (p: &'a u8) where 'a: 'b { let q: &'b u8 = p; }", |
| 96 | "unsafe fn f 'a 'b (p: &'b u8) where 'a: 'b { let q: &'a u8 = p; }", |
| 97 | ] { |
| 98 | let mut testArena5 = super::testArena(); |
| 99 | let testStorage5: 'test5 = &mut testArena5 in { |
| 100 | let mut res = super::testResolver(testStorage5); |
| 101 | let result = try super::resolveProgramStr(&mut res, program); |
| 102 | let err = try super::expectError(&result); |
| 103 | let case resolver::ErrorKind::TypeMismatch(_) = err.kind |
| 104 | else throw testing::TestError::Failed; |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | /// Nominal region environments diagnose their own invalid parent relations. |
| 110 | @test unsafe fn testNominalRegionNames() throws (testing::TestError) { |
| 111 | for program in [ |
| 112 | "record R: 'r where 'missing: 'r { value: u8 }", |
| 113 | "union U: 'r where 'missing: 'r { Empty }", |
| 114 | "record R: 'r { value: &'other u8 }", |
| 115 | "union U: 'r { Value(&'other u8) }", |
| 116 | ] { |
| 117 | let mut testArena6 = super::testArena(); |
| 118 | let testStorage6: 'test6 = &mut testArena6 in { |
| 119 | let mut res = super::testResolver(testStorage6); |
| 120 | let result = try super::resolveProgramStr(&mut res, program); |
| 121 | let err = try super::expectError(&result); |
| 122 | let case resolver::ErrorKind::UnknownRegion(_) = err.kind |
| 123 | else throw testing::TestError::Failed; |
| 124 | } |
| 125 | } |
| 126 | for program in [ |
| 127 | "record R: 'r + 'r { value: u8 }", |
| 128 | "union U: 'r + 'r { Empty }", |
| 129 | ] { |
| 130 | let mut testArena7 = super::testArena(); |
| 131 | let testStorage7: 'test7 = &mut testArena7 in { |
| 132 | let mut res = super::testResolver(testStorage7); |
| 133 | let result = try super::resolveProgramStr(&mut res, program); |
| 134 | let _ = try super::expectErrorKind(&result, resolver::ErrorKind::DuplicateBinding("'r")); |
| 135 | } |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | /// Region declarations restore their environment after a signature error. |
| 140 | @test unsafe fn testRegionErrorScopeRestoration() throws (testing::TestError) { |
| 141 | let mut testArena8 = super::testArena(); |
| 142 | let testStorage8: 'test8 = &mut testArena8 in { |
| 143 | let mut res = super::testResolver(testStorage8); |
| 144 | let result = try super::resolveProgramStr(&mut res, |
| 145 | "fn f 'r (p: &'missing u8) {} fn g 'other (p: &'r u8) {}" |
| 146 | ); |
| 147 | let err = try super::expectError(&result); |
| 148 | let case resolver::ErrorKind::UnknownRegion(name) = err.kind |
| 149 | else throw testing::TestError::Failed; |
| 150 | try testing::expect(mem::eq(name, "'missing")); |
| 151 | try testing::expect(res.regionScope == nil); |
| 152 | try testing::expect(res.currentFn == nil); |
| 153 | try testing::expect(res.currentFnNode == nil); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | /// Regional exclusive references retain affine ownership and arithmetic checks. |
| 158 | @test unsafe fn testRegionExclusiveOwnership() throws (testing::TestError) { |
| 159 | for program in [ |
| 160 | "fn f 'r (p: &'r mut u8) { let q: &'r mut u8 = p; set *p = 3; }", |
| 161 | "unsafe fn f 'r (p: &'r mut u8) { let q: &'r mut u8 = p; set *p = 3; }", |
| 162 | "unsafe fn f 'r (p: &'r mut u8) { let q = p + 1; }", |
| 163 | "unsafe fn f 'r (p: &'r mut u8) { let q = p as *mut u8; }", |
| 164 | ] { |
| 165 | let mut testArena9 = super::testArena(); |
| 166 | let testStorage9: 'test9 = &mut testArena9 in { |
| 167 | let mut res = super::testResolver(testStorage9); |
| 168 | let result = try super::resolveProgramStr(&mut res, program); |
| 169 | let _ = try super::expectError(&result); |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | /// Callback signatures preserve the same region substitution as data arguments. |
| 175 | @test unsafe fn testRegionCallbackSubstitution() throws (testing::TestError) { |
| 176 | let mut testArena10 = super::testArena(); |
| 177 | let testStorage10: 'test10 = &mut testArena10 in { |
| 178 | let mut res = super::testResolver(testStorage10); |
| 179 | let result = try super::resolveProgramStr(&mut res, "fn read 'r (p: &'r u32) -> u32 { return *p; } fn useOp 'r (p: &'r u32, op: fn(&'r u32) -> u32) -> u32 { return op(p); } fn relay 'a 'b (p: &'a u32) -> u32 { return useOp(p, read 'b); }"); |
| 180 | let err = try super::expectError(&result); |
| 181 | let case resolver::ErrorKind::RegionInference(_) = err.kind else throw testing::TestError::Failed; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | /// A single region parameter requires one consistent named argument. |
| 186 | @test unsafe fn testRegionCallInferenceFailures() throws (testing::TestError) { |
| 187 | for program in [ |
| 188 | "fn pair 'r (a: &'r u32, b: &'r u32) {} fn relay 'a 'b (a: &'a u32, b: &'b u32) { pair(a, b); }", |
| 189 | "fn read 'r (p: &'r u32) {} fn relay(p: &u32) { read(p); }", |
| 190 | "unsafe fn read 'r (p: &'r u32) {} unsafe fn relay(p: *unsafe u32) { read(p); }", |
| 191 | "fn answer 'r () -> u32 { return 42; } fn relay() -> u32 { return answer(); }", |
| 192 | "fn read 'r (p: ?&'r u32) {} fn relay() { read(nil); }", |
| 193 | "unsafe fn read 'r (p: ?&'r u32) {} unsafe fn relay() { read(nil); }", |
| 194 | ] { |
| 195 | let mut testArena11 = super::testArena(); |
| 196 | let testStorage11: 'test11 = &mut testArena11 in { |
| 197 | let mut res = super::testResolver(testStorage11); |
| 198 | let result = try super::resolveProgramStr(&mut res, program); |
| 199 | let err = try super::expectError(&result); |
| 200 | let case resolver::ErrorKind::RegionInference(_) = err.kind else throw testing::TestError::Failed; |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | /// Inferred and explicit region arguments must satisfy declared parent relations. |
| 206 | @test unsafe fn testRegionCallParents() throws (testing::TestError) { |
| 207 | for program in [ |
| 208 | "fn pair 'p 'c (p: &'p u32, c: &'c u32) where 'p: 'c {} fn relay 'a 'b (a: &'a u32, b: &'b u32) { pair(a, b); }", |
| 209 | "fn pair 'p 'c (p: &'p u32, c: &'c u32) where 'p: 'c {} unsafe fn relay 'a 'b (a: &'a u32, b: &'b u32) where 'a: 'b { pair 'b 'a (b, a); }", |
| 210 | ] { |
| 211 | let mut testArena12 = super::testArena(); |
| 212 | let testStorage12: 'test12 = &mut testArena12 in { |
| 213 | let mut res = super::testResolver(testStorage12); |
| 214 | let result = try super::resolveProgramStr(&mut res, program); |
| 215 | let err = try super::expectError(&result); |
| 216 | let case resolver::ErrorKind::RegionParent(_) = err.kind else throw testing::TestError::Failed; |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | /// Region applications require the declared arity and accessible names. |
| 222 | @test unsafe fn testExplicitRegionApplicationErrors() throws (testing::TestError) { |
| 223 | for program in [ |
| 224 | "fn read 'r (p: &'r u32) {} fn relay 'a 'b (p: &'a u32) { read 'a 'b (p); }", |
| 225 | "fn read(p: &u32) {} fn relay 'a (p: &'a u32) { read 'a (p); }", |
| 226 | ] { |
| 227 | let mut testArena13 = super::testArena(); |
| 228 | let testStorage13: 'test13 = &mut testArena13 in { |
| 229 | let mut res = super::testResolver(testStorage13); |
| 230 | let result = try super::resolveProgramStr(&mut res, program); |
| 231 | let err = try super::expectError(&result); |
| 232 | let case resolver::ErrorKind::RegionArgumentCount(_) = err.kind else throw testing::TestError::Failed; |
| 233 | } |
| 234 | } |
| 235 | let mut testArena14 = super::testArena(); |
| 236 | let testStorage14: 'test14 = &mut testArena14 in { |
| 237 | let mut res = super::testResolver(testStorage14); |
| 238 | let result = try super::resolveProgramStr(&mut res, "fn read 'r (p: &'r u32) {} fn relay 'a (p: &'a u32) { read 'missing (p); }"); |
| 239 | let err = try super::expectError(&result); |
| 240 | let case resolver::ErrorKind::UnknownRegion(_) = err.kind else throw testing::TestError::Failed; |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | /// Region header loans stay active through moves and nested exclusive reborrows. |
| 245 | @test unsafe fn testConcreteBorrowConflicts() throws (testing::TestError) { |
| 246 | for program in [ |
| 247 | "fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { set x = 2; } }", |
| 248 | "unsafe fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { set x = 2; } }", |
| 249 | "fn run() { let mut x: u32 = 1; let p: 'r = &mut x, q = &mut x in {} }", |
| 250 | "fn run() { let mut x: u32 = 1; let p: 'r = &x, q = &mut x in {} }", |
| 251 | "fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { { let q = p; set *q = 2; } set x = 3; } }", |
| 252 | "fn run() { let mut x: u32 = 1; let p: 'a = &mut x in { let q: 'b = &mut *p in { set *p = 3; } } }", |
| 253 | "fn run(i: u32, j: u32) { let mut x: [u32; 2] = [1, 2]; let p: 'r = &mut x[i], q = &mut x[j] in {} }", |
| 254 | ] { |
| 255 | let mut testArena15 = super::testArena(); |
| 256 | let testStorage15: 'test15 = &mut testArena15 in { |
| 257 | let mut res = super::testResolver(testStorage15); |
| 258 | let result = try super::resolveProgramStr(&mut res, program); |
| 259 | let err = try super::expectError(&result); |
| 260 | let case resolver::ErrorKind::BorrowConflict(_) = err.kind else throw testing::TestError::Failed; |
| 261 | } |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | /// Borrow headers require existing places and accessible, distinct region names. |
| 266 | @test unsafe fn testConcreteRegionNamesAndSources() throws (testing::TestError) { |
| 267 | for program in [ |
| 268 | "fn run() { let p: 'r = &1 in {} }", |
| 269 | "fn value() -> u32 { return 1; } fn run() { let p: 'r = &value() in {} }", |
| 270 | "fn run() { let x: u32 = 1; let p: 'r = &x in { let q: 'r = &x in {} } }", |
| 271 | "fn run() { let x: u32 = 1; let p: 'r = &x in {} let q: &'r u32 = &x; }", |
| 272 | "fn run 'a (p: &'a mut u32) { let q: 'b = &mut *p in {} }", |
| 273 | ] { |
| 274 | let mut testArena16 = super::testArena(); |
| 275 | let testStorage16: 'test16 = &mut testArena16 in { |
| 276 | let mut res = super::testResolver(testStorage16); |
| 277 | let result = try super::resolveProgramStr(&mut res, program); |
| 278 | let _ = try super::expectError(&result); |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | } |
| 283 | |
| 284 | /// A block-local value cannot supply storage for the whole enclosing region. |
| 285 | @test unsafe fn testRegionLocalStorageBoundary() throws (testing::TestError) { |
| 286 | for program in [ |
| 287 | "fn run() { let a: u32 = 1; let p: 'outer = &a in { let mut cursor = p; let b: u32 = 2; let q: 'inner = &b where 'outer: 'inner in { set cursor = q; } } }", |
| 288 | "unsafe fn run() { let a: u32 = 1; let p: 'outer = &a in { let mut cursor = p; let b: u32 = 2; let q: 'inner = &b where 'outer: 'inner in { set cursor = q; } } }", |
| 289 | "fn run() { let x: u32 = 1; let p: 'r = &x in { let y: u32 = 2; let q: &'r u32 = &y; } }", |
| 290 | "unsafe fn run() { let x: u32 = 1; let p: 'r = &x in { let y: u32 = 2; let q: &'r u32 = &y; } }", |
| 291 | "fn run() { let mut x: u32 = 1; let p: 'a = &mut x in { let q: 'b = &mut *p in { let outer: &'a mut u32 = q; } } }", |
| 292 | ] { |
| 293 | let mut testArena17 = super::testArena(); |
| 294 | let testStorage17: 'test17 = &mut testArena17 in { |
| 295 | let mut res = super::testResolver(testStorage17); |
| 296 | let result = try super::resolveProgramStr(&mut res, program); |
| 297 | let err = try super::expectError(&result); |
| 298 | let case resolver::ErrorKind::TypeMismatch(_) = err.kind else throw testing::TestError::Failed; |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | } |
| 303 | |
| 304 | /// Generic calls keep the exclusive-argument overlap check after substitution. |
| 305 | @test unsafe fn testRegionCallBorrowOverlap() throws (testing::TestError) { |
| 306 | let mut testArena18 = super::testArena(); |
| 307 | let testStorage18: 'test18 = &mut testArena18 in { |
| 308 | let mut res = super::testResolver(testStorage18); |
| 309 | let result = try super::resolveProgramStr(&mut res, "fn pair 'r (a: &'r mut u32, b: &'r mut u32) {} fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { pair(p, p); } }"); |
| 310 | let err = try super::expectError(&result); |
| 311 | let case resolver::ErrorKind::BorrowConflict(_) = err.kind else throw testing::TestError::Failed; |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | /// Exact arguments share one descriptor and all applications share the source layout. |
| 316 | @test unsafe fn testNominalRegionApplications() throws (testing::TestError) { |
| 317 | let mut testArena19 = super::testArena(); |
| 318 | let testStorage19: 'test19 = &mut testArena19 in { |
| 319 | let mut res = super::testResolver(testStorage19); |
| 320 | let result = try super::resolveProgramStr(&mut res, |
| 321 | "record N: 'r + Copy { value: u32 } fn f 'a 'b (x: N 'a, y: N 'a, z: N 'b) {}" |
| 322 | ); |
| 323 | try super::expectNoErrors(&result); |
| 324 | let func = try super::getBlockStmt(result.root, 1); |
| 325 | let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed; |
| 326 | let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed; |
| 327 | let case resolver::Type::Nominal(x) = *info.paramTypes[0] else throw testing::TestError::Failed; |
| 328 | let case resolver::Type::Nominal(y) = *info.paramTypes[1] else throw testing::TestError::Failed; |
| 329 | let case resolver::Type::Nominal(z) = *info.paramTypes[2] else throw testing::TestError::Failed; |
| 330 | try testing::expect(x == y); |
| 331 | try testing::expect(x <> z); |
| 332 | try testing::expect(not resolver::typesEqual(*info.paramTypes[0], *info.paramTypes[2])); |
| 333 | let a = resolver::nominalApplication(x) else throw testing::TestError::Failed; |
| 334 | let b = resolver::nominalApplication(z) else throw testing::TestError::Failed; |
| 335 | try testing::expect(a.base == b.base); |
| 336 | try testing::expect(a.arguments[0].id <> b.arguments[0].id); |
| 337 | let case resolver::NominalType::Record(base) = *a.base else throw testing::TestError::Failed; |
| 338 | let case resolver::NominalType::Record(first) = *x else throw testing::TestError::Failed; |
| 339 | let case resolver::NominalType::Record(second) = *z else throw testing::TestError::Failed; |
| 340 | try testing::expect(base.layout == first.layout); |
| 341 | try testing::expect(first.layout == second.layout); |
| 342 | try testing::expect(first.layout.size == 4); |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | /// Recursive fields refer to their own exact applied descriptor. |
| 347 | @test unsafe fn testRecursiveNominalApplications() throws (testing::TestError) { |
| 348 | let mut testArena20 = super::testArena(); |
| 349 | let testStorage20: 'test20 = &mut testArena20 in { |
| 350 | let mut res = super::testResolver(testStorage20); |
| 351 | let result = try super::resolveProgramStr(&mut res, |
| 352 | "record N: 'r + Copy { next: ?*N 'r } fn f 'a 'b (x: N 'a, y: N 'b) {}" |
| 353 | ); |
| 354 | try super::expectNoErrors(&result); |
| 355 | let func = try super::getBlockStmt(result.root, 1); |
| 356 | let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed; |
| 357 | let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed; |
| 358 | for parameter in info.paramTypes { |
| 359 | let case resolver::Type::Nominal(descriptor) = *parameter else throw testing::TestError::Failed; |
| 360 | let case resolver::NominalType::Record(body) = *descriptor else throw testing::TestError::Failed; |
| 361 | let case resolver::Type::Optional(inner) = body.fields[0].fieldType else throw testing::TestError::Failed; |
| 362 | let case resolver::Type::Pointer { target, .. } = *inner else throw testing::TestError::Failed; |
| 363 | try testing::expect(resolver::typesEqual(*target, *parameter)); |
| 364 | try testing::expect(body.layout.size == 8); |
| 365 | } |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | /// An inline union payload retains its enclosing application's region arguments. |
| 370 | @test unsafe fn testNominalPayloadRegionCapture() throws (testing::TestError) { |
| 371 | let mut testArena21 = super::testArena(); |
| 372 | let testStorage21: 'test21 = &mut testArena21 in { |
| 373 | let mut res = super::testResolver(testStorage21); |
| 374 | let result = try super::resolveProgramStr(&mut res, |
| 375 | "record N: 'r + Copy { value: u32 } union U: 'r + Copy { Link { node: *N 'r }, Empty } fn f 'a (u: U 'a, n: N 'a) {}" |
| 376 | ); |
| 377 | try super::expectNoErrors(&result); |
| 378 | let func = try super::getBlockStmt(result.root, 2); |
| 379 | let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed; |
| 380 | let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed; |
| 381 | let case resolver::Type::Nominal(resolver::NominalType::Union(body)) = *info.paramTypes[0] |
| 382 | else throw testing::TestError::Failed; |
| 383 | let case resolver::Type::Nominal(resolver::NominalType::Record(payload)) = body.variants[0].valueType |
| 384 | else throw testing::TestError::Failed; |
| 385 | let case resolver::Type::Pointer { target, .. } = payload.fields[0].fieldType |
| 386 | else throw testing::TestError::Failed; |
| 387 | try testing::expect(resolver::typesEqual(*target, *info.paramTypes[1])); |
| 388 | let applied = body.application else throw testing::TestError::Failed; |
| 389 | let case resolver::NominalType::Union(base) = *applied.base else throw testing::TestError::Failed; |
| 390 | try testing::expect(body.layout == base.layout); |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | /// Nominal applications require exactly the declared number of region arguments. |
| 395 | @test unsafe fn testNominalRegionArgumentCount() throws (testing::TestError) { |
| 396 | for program in [ |
| 397 | "record N: 'r { value: u32 } fn f(n: N) {}", |
| 398 | "record N { value: u32 } fn f 'r (n: N 'r) {}", |
| 399 | "record N: 'r + 's { value: u32 } fn f 'a (n: N 'a) {}", |
| 400 | "record N: 'r { value: u32 } fn f 'a 'b (n: N 'a 'b) {}", |
| 401 | "record N: 'r { value: u32 } fn f() { let n = N { value: 1 }; }", |
| 402 | "union U: 'r { Empty } fn f() { let u = U::Empty; }", |
| 403 | ] { |
| 404 | let mut testArena22 = super::testArena(); |
| 405 | let testStorage22: 'test22 = &mut testArena22 in { |
| 406 | let mut res = super::testResolver(testStorage22); |
| 407 | let result = try super::resolveProgramStr(&mut res, program); |
| 408 | let error = try super::expectError(&result); |
| 409 | let case resolver::ErrorKind::RegionArgumentCount(_) = error.kind else throw testing::TestError::Failed; |
| 410 | } |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | /// Type arguments are invariant in values, constructor hints, and patterns. |
| 415 | @test unsafe fn testNominalRegionInvariance() throws (testing::TestError) { |
| 416 | for program in [ |
| 417 | "record N: 'r + Copy { value: u32 } fn f 'a 'b (n: N 'a) { let x: N 'b = n; }", |
| 418 | "record N: 'r + Copy { value: u32 } unsafe fn f 'a 'b (n: N 'a) { let x: N 'b = n; }", |
| 419 | "record N: 'r + Copy { value: u32 } fn f 'a 'b () { let n: N 'a = N 'b { value: 1 }; }", |
| 420 | "record N: 'r + Copy { value: u32 } fn f 'a 'b (n: N 'a) { let case N 'b { value } = n else panic; }", |
| 421 | "record N: 'r + Copy (u32); fn f 'a 'b (n: N 'a) { let case N 'b (value) = n else panic; }", |
| 422 | "record N: 'r + Copy { value: u32 } record M: 'r + Copy { value: u32 } fn f 'a (n: N 'a) { let case M 'a { value } = n else panic; }", |
| 423 | ] { |
| 424 | let mut testArena23 = super::testArena(); |
| 425 | let testStorage23: 'test23 = &mut testArena23 in { |
| 426 | let mut res = super::testResolver(testStorage23); |
| 427 | let result = try super::resolveProgramStr(&mut res, program); |
| 428 | let error = try super::expectError(&result); |
| 429 | let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed; |
| 430 | } |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | /// Region inference must agree between an outer reference and its embedded nominal type. |
| 435 | @test unsafe fn testNominalRegionInferenceConflict() throws (testing::TestError) { |
| 436 | for program in [ |
| 437 | "record N: 'r + Copy { value: u32 } fn take 'r (n: &'r N 'r) {} fn f 'a 'b (n: &'a N 'b) { take(n); }", |
| 438 | "record N: 'r + Copy { value: u32 } fn take 'r (n: N 'r, m: N 'r) {} fn f 'a 'b (n: N 'a, m: N 'b) { take(n, m); }", |
| 439 | ] { |
| 440 | let mut testArena24 = super::testArena(); |
| 441 | let testStorage24: 'test24 = &mut testArena24 in { |
| 442 | let mut res = super::testResolver(testStorage24); |
| 443 | let result = try super::resolveProgramStr(&mut res, program); |
| 444 | let error = try super::expectError(&result); |
| 445 | let case resolver::ErrorKind::RegionInference(_) = error.kind else throw testing::TestError::Failed; |
| 446 | } |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | /// Applications must satisfy the source declaration's explicit parent relations. |
| 451 | @test unsafe fn testNominalRegionParentConstraint() throws (testing::TestError) { |
| 452 | let mut testArena25 = super::testArena(); |
| 453 | let testStorage25: 'test25 = &mut testArena25 in { |
| 454 | let mut res = super::testResolver(testStorage25); |
| 455 | let result = try super::resolveProgramStr(&mut res, |
| 456 | "record N: 'r + 's where 'r: 's { value: u32 } fn f 'a 'b (n: N 'a 'b) {}" |
| 457 | ); |
| 458 | let error = try super::expectError(&result); |
| 459 | let case resolver::ErrorKind::RegionParent(_) = error.kind else throw testing::TestError::Failed; |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | /// An applied affine type retains the source declaration's move rule. |
| 464 | @test unsafe fn testNominalRegionMoveRule() throws (testing::TestError) { |
| 465 | let mut testArena26 = super::testArena(); |
| 466 | let testStorage26: 'test26 = &mut testArena26 in { |
| 467 | let mut res = super::testResolver(testStorage26); |
| 468 | let result = try super::resolveProgramStr(&mut res, |
| 469 | "record N: 'r { value: u32 } fn f 'a (n: N 'a) { let first = n; let second = n; }" |
| 470 | ); |
| 471 | let error = try super::expectError(&result); |
| 472 | let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed; |
| 473 | } |
| 474 | } |
| 475 | |
| 476 | /// By-value cycles have no layout, including cycles through exact applications. |
| 477 | @test unsafe fn testNominalRegionValueCycle() throws (testing::TestError) { |
| 478 | for program in [ |
| 479 | "record N: 'r { next: N 'r }", |
| 480 | "record N: 'r { next: ?N 'r }", |
| 481 | "union U: 'r { More(U 'r), Empty }", |
| 482 | "record N: 'r { m: M 'r } record M: 'r { n: N 'r }", |
| 483 | ] { |
| 484 | let mut testArena27 = super::testArena(); |
| 485 | let testStorage27: 'test27 = &mut testArena27 in { |
| 486 | let mut res = super::testResolver(testStorage27); |
| 487 | let result = try super::resolveProgramStr(&mut res, program); |
| 488 | let error = try super::expectError(&result); |
| 489 | let case resolver::ErrorKind::RecursiveType = error.kind else throw testing::TestError::Failed; |
| 490 | } |
| 491 | } |
| 492 | } |
| 493 | |
| 494 | /// Recursive substitutions can permute arguments without expanding the type graph. |
| 495 | @test unsafe fn testNominalRegionPermutation() throws (testing::TestError) { |
| 496 | let mut testArena28 = super::testArena(); |
| 497 | let testStorage28: 'test28 = &mut testArena28 in { |
| 498 | let mut res = super::testResolver(testStorage28); |
| 499 | let result = try super::resolveProgramStr(&mut res, |
| 500 | "record N: 'r + 's + Copy { next: ?*N 's 'r } fn f 'a 'b (x: N 'a 'b, y: N 'b 'a) {}" |
| 501 | ); |
| 502 | try super::expectNoErrors(&result); |
| 503 | let func = try super::getBlockStmt(result.root, 1); |
| 504 | let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed; |
| 505 | let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed; |
| 506 | for parameter, i in info.paramTypes { |
| 507 | let case resolver::Type::Nominal(resolver::NominalType::Record(body)) = *parameter |
| 508 | else throw testing::TestError::Failed; |
| 509 | let case resolver::Type::Optional(inner) = body.fields[0].fieldType else throw testing::TestError::Failed; |
| 510 | let case resolver::Type::Pointer { target, .. } = *inner else throw testing::TestError::Failed; |
| 511 | try testing::expect(resolver::typesEqual(*target, *info.paramTypes[1 - i])); |
| 512 | } |
| 513 | } |
| 514 | } |
| 515 | |
| 516 | /// Calls transfer named exclusive references on normal and error paths. |
| 517 | @test unsafe fn testRegionalCallOwnershipTransfer() throws (testing::TestError) { |
| 518 | for program in [ |
| 519 | "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32) { take(p); take(p); }", |
| 520 | "fn take 'r (p: &'r mut u32) {} unsafe fn run 'r (p: &'r mut u32) { take(p); set *p = 1; }", |
| 521 | "fn take 'r (p: &'r mut [u32]) {} fn run 'r (p: &'r mut [u32]) { take(p); p[0]; }", |
| 522 | "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32) { let f = take 'r; f(p); set *p = 1; }", |
| 523 | "union E { Bad } fn take 'r (p: &'r mut u32) throws (E) { throw E::Bad; } fn run 'r (p: &'r mut u32) { try take(p) catch {}; set *p = 1; }", |
| 524 | "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32, c: bool) { if c { take(p); } set *p = 1; }", |
| 525 | ] { |
| 526 | let mut testArena29 = super::testArena(); |
| 527 | let testStorage29: 'test29 = &mut testArena29 in { |
| 528 | let mut res = super::testResolver(testStorage29); |
| 529 | let result = try super::resolveProgramStr(&mut res, program); |
| 530 | let error = try super::expectError(&result); |
| 531 | let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed; |
| 532 | } |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | /// Full-region projections protect their source after a local binding leaves scope. |
| 537 | @test unsafe fn testRegionalProjectionLifetime() throws (testing::TestError) { |
| 538 | for program in [ |
| 539 | "fn f 'r (p: &'r mut u32) { let shared = &*p; let copy = shared; set *p = 1; }", |
| 540 | "unsafe fn f 'r (p: &'r mut u32) { let shared = &*p; let copy = shared; set *p = 1; }", |
| 541 | "fn f 'r (p: &'r mut u32, q: &'r u32) { let mut cursor = q; set cursor = &*p; set *p = 1; }", |
| 542 | "unsafe fn f 'r (p: &'r mut u32, q: &'r u32) { let mut cursor = q; set cursor = &*p; set *p = 1; }", |
| 543 | "fn f 'r (p: &'r mut u32) { { let q = &mut *p; set *q = 1; } set *p = 2; }", |
| 544 | "fn f 'r (p: &'r mut u32) { { let q = &*p; } set *p = 2; }", |
| 545 | "unsafe fn f 'r (p: &'r mut u32) { { let q = &*p; } set *p = 2; }", |
| 546 | "fn f 'r (p: &'r mut u32) { { let q = &mut *p; let moved = q; } *p; }", |
| 547 | "record P { a: u32, b: u32 } fn f 'r (p: &'r mut P) { { let q = &mut p.a; } p.a; }", |
| 548 | "record P { a: u32, b: u32 } fn f 'r (p: &'r mut P) { { let q = &p.a; } set p.a = 2; }", |
| 549 | ] { |
| 550 | let mut testArena30 = super::testArena(); |
| 551 | let testStorage30: 'test30 = &mut testArena30 in { |
| 552 | let mut res = super::testResolver(testStorage30); |
| 553 | let result = try super::resolveProgramStr(&mut res, program); |
| 554 | let error = try super::expectError(&result); |
| 555 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 556 | } |
| 557 | } |
| 558 | } |
| 559 | |
| 560 | /// A regional loan on any live branch remains active at the branch join. |
| 561 | @test unsafe fn testRegionalProjectionBranchJoin() throws (testing::TestError) { |
| 562 | for program in [ |
| 563 | "fn f 'r (p: &'r mut u32, c: bool) { if c { let q = &mut *p; } set *p = 2; }", |
| 564 | "fn f 'r (p: &'r mut u32, c: bool) { if c {} else { let q = &*p; } set *p = 2; }", |
| 565 | "fn f 'r (p: &'r mut u32, c: bool) { match c { case true => { let q = &mut *p; } else => {} } *p; }", |
| 566 | "fn f 'r (p: &'r mut u32, c: ?u32) { if let n = c { let q = &*p; } set *p = 2; }", |
| 567 | ] { |
| 568 | let mut testArena31 = super::testArena(); |
| 569 | let testStorage31: 'test31 = &mut testArena31 in { |
| 570 | let mut res = super::testResolver(testStorage31); |
| 571 | let result = try super::resolveProgramStr(&mut res, program); |
| 572 | let error = try super::expectError(&result); |
| 573 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 574 | } |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | /// Loop back edges carry regional loans into later iterations. |
| 579 | @test unsafe fn testRegionalProjectionLoopBackEdge() throws (testing::TestError) { |
| 580 | for program in [ |
| 581 | "fn f 'r (p: &'r mut u32) { for i in 0..2 { let q = &mut *p; } }", |
| 582 | "fn f 'r (p: &'r mut u32) { for i in 0..2 { set *p = 1; let q = &*p; } }", |
| 583 | "fn f 'r (p: &'r mut u32) { for i in 0..2 { set *p = 1; let q = &*p; continue; } }", |
| 584 | "fn f 'r (p: &'r mut u32, c: bool) { while c { let q = &mut *p; } }", |
| 585 | "fn f 'r (p: &'r mut u32, c: ?u32) { while let n = c { let q = &mut *p; } }", |
| 586 | "fn f 'r (p: &'r mut u32) { loop { let q = &mut *p; } }", |
| 587 | "fn f 'r (p: &'r mut u32, c: bool) { loop { if c { set *p = 1; break; } let q = &*p; } }", |
| 588 | ] { |
| 589 | let mut testArena32 = super::testArena(); |
| 590 | let testStorage32: 'test32 = &mut testArena32 in { |
| 591 | let mut res = super::testResolver(testStorage32); |
| 592 | let result = try super::resolveProgramStr(&mut res, program); |
| 593 | let error = try super::expectError(&result); |
| 594 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 595 | } |
| 596 | } |
| 597 | } |
| 598 | |
| 599 | /// Loans in caller-supplied regions survive loop and nested-region exits. |
| 600 | @test unsafe fn testRegionalProjectionLoopExit() throws (testing::TestError) { |
| 601 | for program in [ |
| 602 | "fn f 'r (p: &'r mut u32) { loop { let q = &mut *p; break; } set *p = 2; }", |
| 603 | "fn f 'r (p: &'r mut u32, c: bool) { while c { let q = &*p; break; } else {} set *p = 2; }", |
| 604 | "fn f 'r (p: &'r mut u32) { for i in 0..2 { let q = &*p; break; } else {} set *p = 2; }", |
| 605 | "fn f 'r (p: &'r mut u32) { let x: u32 = 0; let v: 'child = &x where 'r: 'child in { let q = &*p; } set *p = 2; }", |
| 606 | ] { |
| 607 | let mut testArena33 = super::testArena(); |
| 608 | let testStorage33: 'test33 = &mut testArena33 in { |
| 609 | let mut res = super::testResolver(testStorage33); |
| 610 | let result = try super::resolveProgramStr(&mut res, program); |
| 611 | let error = try super::expectError(&result); |
| 612 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 613 | } |
| 614 | } |
| 615 | } |
| 616 | |
| 617 | /// Region erasure cannot merge distinct error alternatives in one signature. |
| 618 | @test unsafe fn testRegionalErrorAmbiguity() throws (testing::TestError) { |
| 619 | for program in [ |
| 620 | "record E: 'r + Copy {} fn f 'a 'b () throws (E 'a, E 'b) {}", |
| 621 | "record E: 'r + Copy {} unsafe fn f 'a 'b () throws (E 'a, E 'b) {}", |
| 622 | "record E: 'r + Copy {} record Callback: 'a + 'b { f: fn() throws (E 'a, E 'b) }", |
| 623 | "fn f 'a 'b () throws (&'a u32, &'b u32) {}", |
| 624 | ] { |
| 625 | let mut testArena34 = super::testArena(); |
| 626 | let testStorage34: 'test34 = &mut testArena34 in { |
| 627 | let mut res = super::testResolver(testStorage34); |
| 628 | let result = try super::resolveProgramStr(&mut res, program); |
| 629 | try super::expectErrorKind(&result, resolver::ErrorKind::AmbiguousRegionalError); |
| 630 | } |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | /// Moving an exclusive reference into an aggregate transfers its ownership. |
| 635 | @test unsafe fn testRegionalAggregateMove() throws (testing::TestError) { |
| 636 | for program in [ |
| 637 | "record W: 'r { p: &'r mut u32 } fn f 'r (p: &'r mut u32) { let w = W 'r { p }; set *p = 1; }", |
| 638 | "record W: 'r { p: &'r mut u32 } unsafe fn f 'r (p: &'r mut u32) { let w = W 'r { p }; set *p = 1; }", |
| 639 | "record W: 'r { p: &'r mut u32 } fn f 'r (w: W 'r) { let case W { p } = w else panic; let again = w; }", |
| 640 | "union W: 'r { P { p: &'r mut u32 } } fn f 'r (p: &'r mut u32) { let w = W 'r::P { p }; set *p = 1; }", |
| 641 | "fn f 'r (p: &'r mut u32) { let a: [&'r mut u32; 1] = [p]; set *p = 1; }", |
| 642 | "fn f 'r (p: &'r mut u32) { let a: ?&'r mut u32 = p; set *p = 1; }", |
| 643 | ] { |
| 644 | let mut testArena35 = super::testArena(); |
| 645 | let testStorage35: 'test35 = &mut testArena35 in { |
| 646 | let mut res = super::testResolver(testStorage35); |
| 647 | let result = try super::resolveProgramStr(&mut res, program); |
| 648 | let error = try super::expectError(&result); |
| 649 | let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed; |
| 650 | } |
| 651 | } |
| 652 | } |
| 653 | |
| 654 | /// Aggregate transfers do not end a projection loan on its source. |
| 655 | @test unsafe fn testRegionalAggregateLoan() throws (testing::TestError) { |
| 656 | for program in [ |
| 657 | "record W: 'r { p: &'r mut u32 } fn f 'r (p: &'r mut u32) { { let w = W 'r { p: &mut *p }; } set *p = 1; }", |
| 658 | "record R: 'r + Copy { p: &'r u32 } fn f 'r (p: &'r mut u32) { { let r = R 'r { p: &*p }; } set *p = 1; }", |
| 659 | "record R: 'r + Copy { p: &'r u32 } fn take 'r (r: R 'r) {} fn f 'r (p: &'r mut u32) { take(R 'r { p: &*p }); set *p = 1; }", |
| 660 | "fn id 'r (p: &'r mut u32) -> &'r mut u32 { return p; } fn f 'r (p: &'r mut u32) { let q = id(p); { let other = &mut *q; } set *q = 1; }", |
| 661 | ] { |
| 662 | let mut testArena36 = super::testArena(); |
| 663 | let testStorage36: 'test36 = &mut testArena36 in { |
| 664 | let mut res = super::testResolver(testStorage36); |
| 665 | let result = try super::resolveProgramStr(&mut res, program); |
| 666 | let error = try super::expectError(&result); |
| 667 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 668 | } |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | /// Local storage cannot acquire a caller region through returns or aggregate hints. |
| 673 | @test unsafe fn testRegionalStorageEscape() throws (testing::TestError) { |
| 674 | for program in [ |
| 675 | "fn f 'r () -> &'r u32 { let x: u32 = 1; return &x; }", |
| 676 | "unsafe fn f 'r () -> &'r u32 { let x: u32 = 1; return &x; }", |
| 677 | "record R: 'r + Copy { p: &'r u32 } fn f 'r () -> R 'r { let x: u32 = 1; return R 'r { p: &x }; }", |
| 678 | "record R: 'r + Copy { p: &'r u32 } fn f 'r () -> R 'r { let x: u32 = 1; let p: 'short = &x in { return R 'short { p }; } }", |
| 679 | "record R: 'r + Copy { p: &'r u32 } fn f 'r (p: &'r u32) -> &'r R 'r { let r = R 'r { p }; return &r; }", |
| 680 | "record R: 'r + Copy { p: &'r u32 } fn f 'r (p: &'r u32) { let mut outer = R 'r { p }; let x: u32 = 1; let q: 'short = &x in { set outer = R 'short { p: q }; } }", |
| 681 | ] { |
| 682 | let mut testArena37 = super::testArena(); |
| 683 | let testStorage37: 'test37 = &mut testArena37 in { |
| 684 | let mut res = super::testResolver(testStorage37); |
| 685 | let result = try super::resolveProgramStr(&mut res, program); |
| 686 | let error = try super::expectError(&result); |
| 687 | let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed; |
| 688 | } |
| 689 | } |
| 690 | } |
| 691 | |
| 692 | /// Reference fields retain their ownership and storage restrictions. |
| 693 | @test unsafe fn testRegionalFieldRestrictions() throws (testing::TestError) { |
| 694 | { |
| 695 | let mut testArena38 = super::testArena(); |
| 696 | let testStorage38: 'test38 = &mut testArena38 in { |
| 697 | let mut res = super::testResolver(testStorage38); |
| 698 | let result = try super::resolveProgramStr(&mut res, "record W: 'r { p: &'r mut u32 } fn f 'r (w: W 'r) { let p = w.p; }"); |
| 699 | try super::expectErrorKind(&result, resolver::ErrorKind::LinearPartialMove); |
| 700 | } |
| 701 | } |
| 702 | { |
| 703 | let mut testArena39 = super::testArena(); |
| 704 | let testStorage39: 'test39 = &mut testArena39 in { |
| 705 | let mut res = super::testResolver(testStorage39); |
| 706 | let result = try super::resolveProgramStr(&mut res, "record R: 'r { p: &u32 }"); |
| 707 | try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition); |
| 708 | } |
| 709 | } |
| 710 | { |
| 711 | let mut testArena40 = super::testArena(); |
| 712 | let testStorage40: 'test40 = &mut testArena40 in { |
| 713 | let mut res = super::testResolver(testStorage40); |
| 714 | let result = try super::resolveProgramStr(&mut res, "fn f 'r (p: &'r u32) { static r: &'r u32 = undefined; }"); |
| 715 | try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition); |
| 716 | } |
| 717 | } |
| 718 | } |
| 719 | |
| 720 | /// Regional projection tracking limits simultaneous live projections. |
| 721 | @test unsafe fn testRegionalLoanCapacity() throws (testing::TestError) { |
| 722 | let mut reuseArena = super::testArena(); |
| 723 | let reuseStorage: 'reuse = &mut reuseArena in { |
| 724 | let mut res = super::testResolver(reuseStorage); |
| 725 | let result = try super::resolveProgramStr(&mut res, "fn f 'r (p: &'r u32) { let outer: 'outer = &*p where 'r: 'outer in { let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } let q: 'x = &*outer in { &*q; } } }"); |
| 726 | try super::expectNoErrors(&result); |
| 727 | } |
| 728 | let mut testArena41 = super::testArena(); |
| 729 | let testStorage41: 'test41 = &mut testArena41 in { |
| 730 | let mut res = super::testResolver(testStorage41); |
| 731 | let result = try super::resolveProgramStr(&mut res, "fn f 'r (p: &'r u32) { [&*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p, &*p]; }"); |
| 732 | try super::expectErrorKind(&result, resolver::ErrorKind::RegionalLoanOverflow); |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | /// Shared regional parameters consume exclusive arguments that can be retained. |
| 737 | @test unsafe fn testRegionalSharedCallTransfer() throws (testing::TestError) { |
| 738 | for program in [ |
| 739 | "fn read 'r (p: &'r u32) -> &'r u32 { return p; } fn f 'r (p: &'r mut u32) -> u32 { let q = read(p); set *p = 2; return *q; }", |
| 740 | "fn read 'r (p: &'r u32) -> &'r u32 { return p; } unsafe fn f 'r (p: &'r mut u32) { let q = read(p); set *p = 2; }", |
| 741 | "fn read 'r (p: &'r [u32]) -> &'r [u32] { return p; } fn f 'r (p: &'r mut [u32]) { let q = read(p); set p[0] = 2; }", |
| 742 | "fn read 'r (p: &'r u32) -> &'r u32 { return p; } fn f 'r (p: &'r mut u32) { let callback = read 'r; let q = callback(p); set *p = 2; }", |
| 743 | ] { |
| 744 | let mut testArena42 = super::testArena(); |
| 745 | let testStorage42: 'test42 = &mut testArena42 in { |
| 746 | let mut res = super::testResolver(testStorage42); |
| 747 | let result = try super::resolveProgramStr(&mut res, program); |
| 748 | let error = try super::expectError(&result); |
| 749 | let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed; |
| 750 | } |
| 751 | } |
| 752 | } |
| 753 | |
| 754 | /// Values stored in a regional destination must cover its full lifetime. |
| 755 | @test unsafe fn testRegionalStoreLifetime() throws (testing::TestError) { |
| 756 | for program in [ |
| 757 | "fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) { set *dst = p; }", |
| 758 | "unsafe fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) { set *dst = p; }", |
| 759 | "fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) where 'a: 'b { set *dst = p; }", |
| 760 | "record R: 'r + Copy { p: &'r u32 } fn f 'a 'b (dst: &'a mut R 'b, p: &'b u32) { set *dst = R 'b { p }; }", |
| 761 | "fn f 'a 'b (dst: &'a mut [&'b u32], p: &'b u32) { set dst[0] = p; }", |
| 762 | "fn f 'a 'b (dst: &'a mut [&'b u32], p: &'b u32) { set dst[..] = p; }", |
| 763 | "fn f 'a 'b (dst: &'a mut fn(&'b u32), callback: fn(&'b u32)) { set *dst = callback; }", |
| 764 | ] { |
| 765 | let mut testArena43 = super::testArena(); |
| 766 | let testStorage43: 'test43 = &mut testArena43 in { |
| 767 | let mut res = super::testResolver(testStorage43); |
| 768 | let result = try super::resolveProgramStr(&mut res, program); |
| 769 | let error = try super::expectError(&result); |
| 770 | let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed; |
| 771 | } |
| 772 | } |
| 773 | } |
| 774 | |
| 775 | /// A session holds the arena loan after the interface is moved or discarded. |
| 776 | @test unsafe fn testSessionArenaLoan() throws (testing::TestError) { |
| 777 | for program in [ |
| 778 | "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { alloc::reset(arena); } }", |
| 779 | "use std::lang::alloc; unsafe fn f(arena: &mut alloc::Arena) { use *arena as s in { alloc::reset(arena); } }", |
| 780 | "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { let moved = s; alloc::reset(arena); } }", |
| 781 | "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { let _ = s; set arena.offset = 0; } }", |
| 782 | "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { use *arena as t in {} } }", |
| 783 | ] { |
| 784 | let mut testArena44 = super::testArena(); |
| 785 | let testStorage44: 'test44 = &mut testArena44 in { |
| 786 | let mut res = super::testResolver(testStorage44); |
| 787 | let result = try super::resolveSessionProgramStr(&mut res, program); |
| 788 | let error = try super::expectError(&result); |
| 789 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 790 | } |
| 791 | } |
| 792 | } |
| 793 | |
| 794 | /// Session interfaces have affine ownership and invariant region arguments. |
| 795 | @test unsafe fn testSessionOwnership() throws (testing::TestError) { |
| 796 | for program in [ |
| 797 | "fn f 'r (s: Session 'r) { let moved = s; let again = s; }", |
| 798 | "unsafe fn f 'r (s: Session 'r) { let moved = s; let again = s; }", |
| 799 | "fn take 'r (s: Session 'r) {} fn f 'r (s: Session 'r) { take(s); take(s); }", |
| 800 | ] { |
| 801 | let mut testArena45 = super::testArena(); |
| 802 | let testStorage45: 'test45 = &mut testArena45 in { |
| 803 | let mut res = super::testResolver(testStorage45); |
| 804 | let result = try super::resolveProgramStr(&mut res, program); |
| 805 | let error = try super::expectError(&result); |
| 806 | let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed; |
| 807 | } |
| 808 | } |
| 809 | { |
| 810 | let mut testArena46 = super::testArena(); |
| 811 | let testStorage46: 'test46 = &mut testArena46 in { |
| 812 | let mut res = super::testResolver(testStorage46); |
| 813 | let result = try super::resolveProgramStr(&mut res, |
| 814 | "fn f 'r 's (s: Session 's) -> Session 'r where 'r: 's { return s; }"); |
| 815 | let error = try super::expectError(&result); |
| 816 | let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed; |
| 817 | } |
| 818 | } |
| 819 | } |
| 820 | |
| 821 | /// Regional `use` blocks require a mutable allocation trait implementer. |
| 822 | @test unsafe fn testSessionSource() throws (testing::TestError) { |
| 823 | for program in [ |
| 824 | "record Arena { data: *mut [u8], offset: u32 } fn f(arena: &mut Arena) { use *arena as s in {} }", |
| 825 | "fn f(value: &mut u32) { use *value as s in {} }", |
| 826 | ] { |
| 827 | let mut testArena47 = super::testArena(); |
| 828 | let testStorage47: 'test47 = &mut testArena47 in { |
| 829 | let mut res = super::testResolver(testStorage47); |
| 830 | let result = try super::resolveSessionProgramStr(&mut res, program); |
| 831 | try super::expectErrorKind(&result, resolver::ErrorKind::InvalidSessionSource); |
| 832 | } |
| 833 | } |
| 834 | let mut customArena = super::testArena(); |
| 835 | let customStorage: 'custom = &mut customArena in { |
| 836 | let mut res = super::testResolver(customStorage); |
| 837 | let result = try super::resolveSessionProgramStr(&mut res, |
| 838 | "use std::lang::alloc; record Wrapper: 'r { arena: &'r mut alloc::Arena } instance alloc::Alloc for Wrapper 'r { unsafe fn (wrapper: &mut Wrapper 'r) reserve(size: u32, alignment: u32) -> *unsafe mut opaque throws (alloc::AllocError) { panic; } unsafe fn (wrapper: &mut Wrapper 'r) reserveSlice(size: u32, alignment: u32, count: u32) -> *unsafe mut [opaque] throws (alloc::AllocError) { panic; } } fn f 'r (wrapper: &'r mut Wrapper 'r) { use *wrapper as session in { try! session.new(1 as u32); } }"); |
| 839 | try super::expectNoErrors(&result); |
| 840 | } |
| 841 | } |
| 842 | |
| 843 | /// Region-dependent values cannot be manufactured from uninitialized storage. |
| 844 | @test unsafe fn testRegionalUndefined() throws (testing::TestError) { |
| 845 | for program in [ |
| 846 | "unsafe fn f 'r () -> Session 'r { return undefined; }", |
| 847 | "record R: 'r { s: Session 'r } unsafe fn f 'r () -> R 'r { return undefined; }", |
| 848 | "unsafe fn f 'r () -> *unsafe Session 'r { return undefined; }", |
| 849 | "unsafe fn f 'r () -> &'r u32 { return undefined; }", |
| 850 | ] { |
| 851 | let mut testArena48 = super::testArena(); |
| 852 | let testStorage48: 'test48 = &mut testArena48 in { |
| 853 | let mut res = super::testResolver(testStorage48); |
| 854 | let result = try super::resolveProgramStr(&mut res, program); |
| 855 | let error = try super::expectError(&result); |
| 856 | let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed; |
| 857 | } |
| 858 | } |
| 859 | } |
| 860 | |
| 861 | /// Pointer casts cannot introduce session or aggregate region dependencies. |
| 862 | @test unsafe fn testRegionalCastForgery() throws (testing::TestError) { |
| 863 | for program in [ |
| 864 | "unsafe fn f 'r (p: *unsafe opaque) -> *unsafe Session 'r { return p as *unsafe Session 'r; }", |
| 865 | "unsafe fn f 'r (p: *unsafe [opaque]) -> *unsafe [Session 'r] { return p as *unsafe [Session 'r]; }", |
| 866 | "record R: 'r { s: Session 'r } unsafe fn f 'r (p: *unsafe opaque) -> *unsafe R 'r { return p as *unsafe R 'r; }", |
| 867 | "record R: 'r + Copy { p: &'r u32 } unsafe fn f 'r 's (p: *unsafe R 'r) -> *unsafe R 's { return p as *unsafe R 's; }", |
| 868 | ] { |
| 869 | let mut testArena49 = super::testArena(); |
| 870 | let testStorage49: 'test49 = &mut testArena49 in { |
| 871 | let mut res = super::testResolver(testStorage49); |
| 872 | let result = try super::resolveProgramStr(&mut res, program); |
| 873 | let error = try super::expectError(&result); |
| 874 | let case resolver::ErrorKind::InvalidAsCast(_) = error.kind else throw testing::TestError::Failed; |
| 875 | } |
| 876 | } |
| 877 | } |
| 878 | |
| 879 | /// Bulk allocation rejects resources and values that need ownership cleanup. |
| 880 | @test unsafe fn testSessionAllocationValue() throws (testing::TestError) { |
| 881 | for program in [ |
| 882 | "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }", |
| 883 | "record R: Once { n: u32 } unsafe fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }", |
| 884 | "record R: Once { n: u32 } record Outer { value: R } fn f 'r (s: &Session 'r, value: Outer) { try! s.new(value); }", |
| 885 | "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: ?R) { try! s.new(value); }", |
| 886 | "fn f 'r (s: &Session 'r, value: Session 'r) { try! s.new(value); }", |
| 887 | "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: [R; 1]) { try! s.new(value); }", |
| 888 | "fn f 'r (s: &Session 'r, value: &'r mut u32) { try! s.fill(value, 2); }", |
| 889 | "fn f 'r (s: &Session 'r, value: &[&'r mut u32]) { try! s.copy(value); }", |
| 890 | ] { |
| 891 | let mut testArena50 = super::testArena(); |
| 892 | let testStorage50: 'test50 = &mut testArena50 in { |
| 893 | let mut res = super::testResolver(testStorage50); |
| 894 | let result = try super::resolveSessionProgramStr(&mut res, program); |
| 895 | try super::expectErrorKind(&result, resolver::ErrorKind::InvalidAllocationValue); |
| 896 | } |
| 897 | } |
| 898 | } |
| 899 | |
| 900 | /// Allocated values must retain dependencies that cover the destination session. |
| 901 | @test unsafe fn testSessionAllocationDependency() throws (testing::TestError) { |
| 902 | for program in [ |
| 903 | "fn f 'r 's (a: &Session 'r, p: &'s u32) where 'r: 's { try! a.new(p); }", |
| 904 | "unsafe fn f 'r 's (a: &Session 'r, p: &'s u32) where 'r: 's { try! a.new(p); }", |
| 905 | "record R: 's + Copy { p: &'s u32 } fn f 'r 's (a: &Session 'r, p: R 's) where 'r: 's { try! a.new(p); }", |
| 906 | "fn f 'r 's (a: &Session 'r, p: &[&'s u32]) where 'r: 's { try! a.copy(p); }", |
| 907 | ] { |
| 908 | let mut testArena51 = super::testArena(); |
| 909 | let testStorage51: 'test51 = &mut testArena51 in { |
| 910 | let mut res = super::testResolver(testStorage51); |
| 911 | let result = try super::resolveSessionProgramStr(&mut res, program); |
| 912 | let error = try super::expectError(&result); |
| 913 | let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed; |
| 914 | } |
| 915 | } |
| 916 | } |
| 917 | |
| 918 | /// Allocation operations require error handling and exact source region results. |
| 919 | @test unsafe fn testSessionAllocationContract() throws (testing::TestError) { |
| 920 | { |
| 921 | let mut testArena52 = super::testArena(); |
| 922 | let testStorage52: 'test52 = &mut testArena52 in { |
| 923 | let mut res = super::testResolver(testStorage52); |
| 924 | let result = try super::resolveSessionProgramStr(&mut res, |
| 925 | "fn f 'r (s: &Session 'r) { s.new(1 as u32); }"); |
| 926 | try super::expectErrorKind(&result, resolver::ErrorKind::MissingTry); |
| 927 | } |
| 928 | } |
| 929 | { |
| 930 | let mut testArena53 = super::testArena(); |
| 931 | let testStorage53: 'test53 = &mut testArena53 in { |
| 932 | let mut res = super::testResolver(testStorage53); |
| 933 | let result = try super::resolveSessionProgramStr(&mut res, |
| 934 | "fn f 'r 's (a: &Session 'r) -> &'s mut u32 { return try! a.new(1 as u32); }"); |
| 935 | let error = try super::expectError(&result); |
| 936 | let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed; |
| 937 | } |
| 938 | } |
| 939 | { |
| 940 | let mut testArena54 = super::testArena(); |
| 941 | let testStorage54: 'test54 = &mut testArena54 in { |
| 942 | let mut res = super::testResolver(testStorage54); |
| 943 | let result = try super::resolveSessionProgramStr(&mut res, |
| 944 | "fn f 'r (a: &Session 'r, p: &u32) { try! a.new(p); }"); |
| 945 | try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition); |
| 946 | } |
| 947 | } |
| 948 | } |
| 949 | |
| 950 | /// Typed reservations reject array products, aggregate sums, and field-offset overflow. |
| 951 | @test unsafe fn testSessionAllocationLayout() throws (testing::TestError) { |
| 952 | for program in [ |
| 953 | "fn f 'r (s: &Session 'r, value: [u64; 536870913]) { try! s.new(value); }", |
| 954 | "unsafe fn f 'r (s: &Session 'r, value: [u64; 536870913]) { try! s.new(value); }", |
| 955 | "record R { a: [u8; 4294967290], b: u64 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }", |
| 956 | "record R { a: [u8; 2147483648], b: u8 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }", |
| 957 | "fn f 'r (s: &Session 'r, value: ?[u8; 4294967295]) { try! s.new(value); }", |
| 958 | "union R { Data([u8; 4294967295]) } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }", |
| 959 | ] { |
| 960 | let mut testArena55 = super::testArena(); |
| 961 | let testStorage55: 'test55 = &mut testArena55 in { |
| 962 | let mut res = super::testResolver(testStorage55); |
| 963 | let result = try super::resolveSessionProgramStr(&mut res, program); |
| 964 | try super::expectErrorKind(&result, resolver::ErrorKind::InvalidAllocationLayout); |
| 965 | } |
| 966 | } |
| 967 | } |
| 968 | |
| 969 | /// Cell payloads must permit plain value copies. |
| 970 | @test unsafe fn testCellPointerPayload() throws (testing::TestError) { |
| 971 | for program in [ |
| 972 | "union State: 'r { Next(&'r cell State 'r) }", |
| 973 | "union State: 'r { Ready(&'r u32) } fn f 'r (state: &'r cell State 'r) {}", |
| 974 | "union State: 'r { Ready(&'r u32) } unsafe fn f 'r (state: &'r cell State 'r) {}", |
| 975 | "fn f(p: *cell *mut u32) {}", |
| 976 | "unsafe fn f(p: *cell *mut u32) {}", |
| 977 | "record R: Once { n: u32 } fn f(p: *cell R) {}", |
| 978 | "record R { n: u32 } fn f(p: *cell R) {}", |
| 979 | "fn f 'r (p: &'r cell &'r mut u32) {}", |
| 980 | ] { |
| 981 | let mut testArena56 = super::testArena(); |
| 982 | let testStorage56: 'test56 = &mut testArena56 in { |
| 983 | let mut res = super::testResolver(testStorage56); |
| 984 | let result = try super::resolveProgramStr(&mut res, program); |
| 985 | try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload); |
| 986 | } |
| 987 | } |
| 988 | } |
| 989 | |
| 990 | /// Direct cell borrows support Copy values, scoped loans, and call arguments. |
| 991 | @test unsafe fn testCellBorrow() throws (testing::TestError) { |
| 992 | for program in [ |
| 993 | "fn f() -> u32 { let mut n: u32 = 0; { let c = &cell n; let alias = c; set *c = 1; set *alias += 1; } return n; }", |
| 994 | "fn read(c: &cell u32) { set *c = 1; } fn f(p: &mut u32) { read(&cell *p); set *p = 2; }", |
| 995 | "fn f() { let mut n: u32 = 0; let c: 'r = &cell n in { let alias = c; set *alias = 1; } set n = 2; }", |
| 996 | "record R: Copy { a: u32, b: u32 } fn f() { let mut r = R { a: 0, b: 0 }; let a = &cell r.a; let b = &cell r.b; set *a = 1; set *b = 2; }", |
| 997 | "fn f() { let mut a: [u32; 2] = [0, 0]; let c = &cell a; set *c = [1, 2]; let snapshot = *c; }", |
| 998 | "fn forward(p: *mut u32) -> *mut u32 { return p; } fn f(p: *mut u32) -> *cell u32 { return &cell *forward(p); }", |
| 999 | "record R: Copy { n: u32 } fn f(p: *mut R) -> *cell u32 { return &cell p.n; }", |
| 1000 | "fn f(p: *mut [u32]) -> *cell u32 { return &cell p[0]; }", |
| 1001 | ] { |
| 1002 | let mut arena = super::testArena(); |
| 1003 | let storage: 'test = &mut arena in { |
| 1004 | let mut res = super::testResolver(storage); |
| 1005 | let result = try super::resolveProgramStr(&mut res, program); |
| 1006 | try super::expectNoErrors(&result); |
| 1007 | } |
| 1008 | } |
| 1009 | } |
| 1010 | |
| 1011 | /// Cell creation requires exclusive access for the full borrow duration. |
| 1012 | @test unsafe fn testCellBorrowConflicts() throws (testing::TestError) { |
| 1013 | for program in [ |
| 1014 | "fn f() { let mut n: u32 = 0; let c = &cell n; let r = &n; }", |
| 1015 | "unsafe fn f() { let mut n: u32 = 0; let c = &cell n; let r = &n; }", |
| 1016 | "fn f() { let mut n: u32 = 0; let r = &n; let c = &cell n; }", |
| 1017 | "fn f() { let mut n: u32 = 0; let c = &cell n; set n = 1; }", |
| 1018 | "fn f() { let mut n: u32 = 0; let c = &cell n; let other = &cell n; }", |
| 1019 | "fn f() { let mut n: u32 = 0; let c = &cell n as &cell u32; let r = &n; }", |
| 1020 | "fn inspect(c: &cell u32, r: &u32) {} fn f() { let mut n: u32 = 0; inspect(&cell n, &n); }", |
| 1021 | "fn inspect(r: &u32, c: &cell u32) {} fn f() { let mut n: u32 = 0; inspect(&n, &cell n); }", |
| 1022 | ] { |
| 1023 | let mut arena = super::testArena(); |
| 1024 | let storage: 'test = &mut arena in { |
| 1025 | let mut res = super::testResolver(storage); |
| 1026 | let result = try super::resolveProgramStr(&mut res, program); |
| 1027 | let error = try super::expectError(&result); |
| 1028 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 1029 | } |
| 1030 | } |
| 1031 | } |
| 1032 | |
| 1033 | /// Cell creation rejects immutable places and non-Copy payloads. |
| 1034 | @test unsafe fn testCellBorrowPayload() throws (testing::TestError) { |
| 1035 | for program in [ |
| 1036 | "fn f() { let n: u32 = 0; let c = &cell n; }", |
| 1037 | "fn f(p: &u32) { let c = &cell *p; }", |
| 1038 | "unsafe fn f(p: &u32) { let c = &cell *p; }", |
| 1039 | ] { |
| 1040 | let mut arena = super::testArena(); |
| 1041 | let storage: 'test = &mut arena in { |
| 1042 | let mut res = super::testResolver(storage); |
| 1043 | let result = try super::resolveProgramStr(&mut res, program); |
| 1044 | try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding); |
| 1045 | } |
| 1046 | } |
| 1047 | for program in [ |
| 1048 | "record R { n: u32 } fn f() { let mut r = R { n: 0 }; let c = &cell r; }", |
| 1049 | "fn f(p: &mut *mut u32) { let c = &cell *p; }", |
| 1050 | "fn f(p: &mut [u32]) { let c = &cell p[..]; }", |
| 1051 | ] { |
| 1052 | let mut arena = super::testArena(); |
| 1053 | let storage: 'test = &mut arena in { |
| 1054 | let mut res = super::testResolver(storage); |
| 1055 | let result = try super::resolveProgramStr(&mut res, program); |
| 1056 | try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload); |
| 1057 | } |
| 1058 | } |
| 1059 | } |
| 1060 | |
| 1061 | /// Cell access cannot expose payload references or restore exclusive pointers. |
| 1062 | @test unsafe fn testCellPointerAccess() throws (testing::TestError) { |
| 1063 | for program in [ |
| 1064 | "fn f(p: *cell u32) { let r = &*p; }", |
| 1065 | "unsafe fn f(p: *cell u32) { let r = &*p; }", |
| 1066 | "record R: Copy { n: u32 } fn f(p: *cell R) { let r = &(*p).n; }", |
| 1067 | "fn f(p: *cell [u32; 2]) { let r = &(*p)[0]; }", |
| 1068 | "record R: Copy { n: u32 } fn f(p: *cell R) { set (*p).n = 1; }", |
| 1069 | "fn f(p: *cell [u32; 2]) { set (*p)[0] = 1; }", |
| 1070 | ] { |
| 1071 | let mut testArena57 = super::testArena(); |
| 1072 | let testStorage57: 'test57 = &mut testArena57 in { |
| 1073 | let mut res = super::testResolver(testStorage57); |
| 1074 | let result = try super::resolveProgramStr(&mut res, program); |
| 1075 | try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding); |
| 1076 | } |
| 1077 | } |
| 1078 | for program in [ |
| 1079 | "fn f(p: *cell u32) -> *mut u32 { return p as *mut u32; }", |
| 1080 | "unsafe fn f(p: *cell u32) -> *unsafe mut u32 { return p as *unsafe mut u32; }", |
| 1081 | "fn f(p: *u32) -> *cell u32 { return p as *cell u32; }", |
| 1082 | "unsafe fn f(p: *unsafe mut u32) -> *cell u32 { return p as *cell u32; }", |
| 1083 | "fn f(p: *mut u64) -> *cell u32 { return p as *cell u32; }", |
| 1084 | "fn f 'r (p: &'r mut u32) -> *cell u32 { return p as *cell u32; }", |
| 1085 | ] { |
| 1086 | let mut testArena58 = super::testArena(); |
| 1087 | let testStorage58: 'test58 = &mut testArena58 in { |
| 1088 | let mut res = super::testResolver(testStorage58); |
| 1089 | let result = try super::resolveProgramStr(&mut res, program); |
| 1090 | let error = try super::expectError(&result); |
| 1091 | let case resolver::ErrorKind::InvalidAsCast(_) = error.kind else throw testing::TestError::Failed; |
| 1092 | } |
| 1093 | } |
| 1094 | } |
| 1095 | |
| 1096 | /// An exclusive payload borrow cannot be made from shared cell access. |
| 1097 | @test unsafe fn testCellPointerMutablePayload() throws (testing::TestError) { |
| 1098 | let mut testArena59 = super::testArena(); |
| 1099 | let testStorage59: 'test59 = &mut testArena59 in { |
| 1100 | let mut res = super::testResolver(testStorage59); |
| 1101 | let result = try super::resolveProgramStr(&mut res, |
| 1102 | "fn f(p: *cell u32) { let r = &mut *p; }"); |
| 1103 | try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding); |
| 1104 | } |
| 1105 | } |
| 1106 | |
| 1107 | /// Cell conversion consumes exclusive access, including call arguments. |
| 1108 | @test unsafe fn testCellPointerOwnership() throws (testing::TestError) { |
| 1109 | for program in [ |
| 1110 | "fn f(p: *mut u32) { let c = &cell *p; set *p = 1; }", |
| 1111 | "unsafe fn f(p: *mut u32) { let c = &cell *p; set *p = 1; }", |
| 1112 | "record R: Copy { n: u32 } fn f(p: *mut R) { let c = &cell p.n; set p.n = 1; }", |
| 1113 | "fn f(p: *mut [u32]) { let c = &cell p[0]; set p[0] = 1; }", |
| 1114 | "fn f(p: *mut u32) { let c = p as *cell u32; set *p = 1; }", |
| 1115 | "unsafe fn f(p: *mut u32) { let c = p as *cell u32; set *p = 1; }", |
| 1116 | "fn read(p: &cell u32) {} fn f(p: &mut u32) { read(p as &cell u32); set *p = 1; }", |
| 1117 | ] { |
| 1118 | let mut testArena60 = super::testArena(); |
| 1119 | let testStorage60: 'test60 = &mut testArena60 in { |
| 1120 | let mut res = super::testResolver(testStorage60); |
| 1121 | let result = try super::resolveProgramStr(&mut res, program); |
| 1122 | let error = try super::expectError(&result); |
| 1123 | let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed; |
| 1124 | } |
| 1125 | } |
| 1126 | for program in [ |
| 1127 | "fn f() { let mut n: u32 = 0; let c = &mut n as &cell u32; let r = &n; set *c = 1; }", |
| 1128 | "unsafe fn f() { let mut n: u32 = 0; let c = &mut n as &cell u32; let r = &n; set *c = 1; }", |
| 1129 | ] { |
| 1130 | let mut testArena61 = super::testArena(); |
| 1131 | let testStorage61: 'test61 = &mut testArena61 in { |
| 1132 | let mut res = super::testResolver(testStorage61); |
| 1133 | let result = try super::resolveProgramStr(&mut res, program); |
| 1134 | let error = try super::expectError(&result); |
| 1135 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 1136 | } |
| 1137 | } |
| 1138 | } |
| 1139 | |
| 1140 | /// Cell writes preserve exact payload regions and destination lifetimes. |
| 1141 | @test unsafe fn testCellPointerRegion() throws (testing::TestError) { |
| 1142 | for program in [ |
| 1143 | "fn f 'r 's (p: &'r cell &'r u32, value: &'s u32) { set *p = value; }", |
| 1144 | "unsafe fn f 'r 's (p: &'r cell &'r u32, value: &'s u32) { set *p = value; }", |
| 1145 | "fn f 'r 's (p: &'r cell u32) -> &'s cell u32 { return p; }", |
| 1146 | ] { |
| 1147 | let mut testArena62 = super::testArena(); |
| 1148 | let testStorage62: 'test62 = &mut testArena62 in { |
| 1149 | let mut res = super::testResolver(testStorage62); |
| 1150 | let result = try super::resolveProgramStr(&mut res, program); |
| 1151 | let error = try super::expectError(&result); |
| 1152 | let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed; |
| 1153 | } |
| 1154 | } |
| 1155 | for program in [ |
| 1156 | "fn f 'r 's (p: &'r cell &'s u32, value: &'s u32) where 'r: 's { set *p = value; }", |
| 1157 | "unsafe fn f 'r 's (p: &'r cell &'s u32, value: &'s u32) where 'r: 's { set *p = value; }", |
| 1158 | ] { |
| 1159 | let mut testArena63 = super::testArena(); |
| 1160 | let testStorage63: 'test63 = &mut testArena63 in { |
| 1161 | let mut res = super::testResolver(testStorage63); |
| 1162 | let result = try super::resolveProgramStr(&mut res, program); |
| 1163 | let error = try super::expectError(&result); |
| 1164 | let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed; |
| 1165 | } |
| 1166 | } |
| 1167 | } |
| 1168 | |
| 1169 | /// Raw cell operations require an unsafe execution context. |
| 1170 | @test unsafe fn testCellPointerRawAccess() throws (testing::TestError) { |
| 1171 | for program in [ |
| 1172 | "fn f(p: *unsafe cell u32) -> u32 { return *p; }", |
| 1173 | "fn f(p: *unsafe cell u32) { set *p = 1; }", |
| 1174 | "fn f(p: &*unsafe cell u32) { set **p = 1; }", |
| 1175 | ] { |
| 1176 | let mut testArena64 = super::testArena(); |
| 1177 | let testStorage64: 'test64 = &mut testArena64 in { |
| 1178 | let mut res = super::testResolver(testStorage64); |
| 1179 | let result = try super::resolveProgramStr(&mut res, program); |
| 1180 | try super::expectErrorKind(&result, resolver::ErrorKind::UnsafeOperation); |
| 1181 | } |
| 1182 | } |
| 1183 | } |
| 1184 | |
| 1185 | /// A checked buffer context cannot be copied while its exclusive storage is live. |
| 1186 | @test unsafe fn testCheckedBufferOwnership() throws (testing::TestError) { |
| 1187 | for program in [ |
| 1188 | "record Buffer: 'r { words: &'r mut [u32] } fn observe 'r (b: &Buffer 'r) {} fn f 'r (b: Buffer 'r) { let moved = b; observe(&b); }", |
| 1189 | "record Buffer: 'r { words: &'r mut [u32] } unsafe fn observe 'r (b: &Buffer 'r) {} unsafe fn f 'r (b: Buffer 'r) { let moved = b; observe(&b); }", |
| 1190 | ] { |
| 1191 | let mut testArena65 = super::testArena(); |
| 1192 | let testStorage65: 'test65 = &mut testArena65 in { |
| 1193 | let mut res = super::testResolver(testStorage65); |
| 1194 | let result = try super::resolveProgramStr(&mut res, program); |
| 1195 | let error = try super::expectError(&result); |
| 1196 | let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed; |
| 1197 | } |
| 1198 | } |
| 1199 | } |
| 1200 | |
| 1201 | /// An iterator's stored shared borrow excludes writes through the buffer owner. |
| 1202 | @test unsafe fn testCheckedIteratorLoan() throws (testing::TestError) { |
| 1203 | for program in [ |
| 1204 | "record Buffer: 'r { words: &'r mut [u32] } record Iter: 'r + 'v + Copy where 'r: 'v { source: &'v Buffer 'r } fn f 'r (b: Buffer 'r) { let mut owner = b; let view: 'scan = &owner where 'r: 'scan in { let iterator: Iter 'r 'scan = Iter { source: view }; set owner.words[0] = 1; } }", |
| 1205 | "record Buffer: 'r { words: &'r mut [u32] } record Iter: 'r + 'v + Copy where 'r: 'v { source: &'v Buffer 'r } unsafe fn f 'r (b: Buffer 'r) { let mut owner = b; let view: 'scan = &owner where 'r: 'scan in { let iterator: Iter 'r 'scan = Iter { source: view }; set owner.words[0] = 1; } }", |
| 1206 | ] { |
| 1207 | let mut testArena66 = super::testArena(); |
| 1208 | let testStorage66: 'test66 = &mut testArena66 in { |
| 1209 | let mut res = super::testResolver(testStorage66); |
| 1210 | let result = try super::resolveProgramStr(&mut res, program); |
| 1211 | let error = try super::expectError(&result); |
| 1212 | let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed; |
| 1213 | } |
| 1214 | } |
| 1215 | } |
| 1216 | |
| 1217 | /// An inferred raw pointer argument requires an unsafe address operation. |
| 1218 | @test unsafe fn testRegionCallRawAddress() throws (testing::TestError) { |
| 1219 | let mut arena = super::testArena(); |
| 1220 | let storage: 'arena = &mut arena in { |
| 1221 | let mut res = super::testResolver(storage); |
| 1222 | let result = try super::resolveProgramStr(&mut res, |
| 1223 | "record View: 'r + Copy { value: &'r u32 } fn read 'r (view: *unsafe View 'r) {} fn f 'r (view: View 'r) { read(&view); }"); |
| 1224 | try super::expectErrorKind(&result, resolver::ErrorKind::UnsafeOperation); |
| 1225 | } |
| 1226 | } |
| 1227 | |
| 1228 | /// Shared aggregate access cannot expose mutable access to an exclusive field. |
| 1229 | @test unsafe fn testSharedExclusiveFieldAccess() throws (testing::TestError) { |
| 1230 | for program in [ |
| 1231 | "record H: 'r { items: &'r mut [u32] } fn f 'r (h: &H 'r) { set h.items[0] = 42; }", |
| 1232 | "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r (h: &H 'r) { set h.items[0] = 42; }", |
| 1233 | "record H: 'r { items: &'r mut [u32] } fn f 'r (h: &'r H 'r) { let p = &mut h.items[0]; }", |
| 1234 | "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r (h: &'r H 'r) { let p = &mut h.items[0]; }", |
| 1235 | "record H: 'r { items: &'r mut [u32] } fn write(p: &mut [u32]) {} fn f 'r (h: &H 'r) { write(h.items); }", |
| 1236 | "record H: 'r { items: &'r mut [u32] } fn write(p: &mut [u32]) {} unsafe fn f 'r (h: &H 'r) { write(h.items); }", |
| 1237 | "record H: 'r { item: &'r mut u32 } fn f 'r (h: &H 'r) { let p: &mut u32 = h.item; }", |
| 1238 | "record H: 'r { item: &'r mut u32 } unsafe fn f 'r (h: &H 'r) { let p: &mut u32 = h.item; }", |
| 1239 | "record H { item: *mut u32 } fn f(h: &H) { set *h.item = 42; }", |
| 1240 | "record H { item: *mut u32 } unsafe fn f(h: &H) { set *h.item = 42; }", |
| 1241 | "record H: 'r { items: [&'r mut u32; 1] } fn f 'r (h: &H 'r) { set *h.items[0] = 42; }", |
| 1242 | "record H: 'r { items: [&'r mut u32; 1] } unsafe fn f 'r (h: &H 'r) { set *h.items[0] = 42; }", |
| 1243 | "fn f 'r (items: &'r [&'r mut u32]) { set *items[0] = 42; }", |
| 1244 | "unsafe fn f 'r (items: &'r [&'r mut u32]) { set *items[0] = 42; }", |
| 1245 | "fn f 'r (p: &'r &'r mut u32) { set **p = 42; }", |
| 1246 | "unsafe fn f 'r (p: &'r &'r mut u32) { set **p = 42; }", |
| 1247 | "record H: 'r { item: &'r mut u32 } fn write(p: &mut u32) {} fn f 'r (h: &H 'r, flag: bool) { write(h.item if flag else h.item); }", |
| 1248 | "record H: 'r { item: &'r mut u32 } fn write(p: &mut u32) {} unsafe fn f 'r (h: &H 'r, flag: bool) { write(h.item if flag else h.item); }", |
| 1249 | "record V { n: u32 } record H { item: *mut V } fn (v: &mut V) write() { set v.n = 42; } fn f(h: &H) { h.item.write(); }", |
| 1250 | "record V { n: u32 } record H { item: *mut V } fn (v: &mut V) write() { set v.n = 42; } unsafe fn f(h: &H) { h.item.write(); }", |
| 1251 | "trait W { fn (&mut W) write(); } record H: 'r { object: &'r mut opaque W } fn f 'r (h: &H 'r) { h.object.write(); }", |
| 1252 | "trait W { fn (&mut W) write(); } record H: 'r { object: &'r mut opaque W } unsafe fn f 'r (h: &H 'r) { h.object.write(); }", |
| 1253 | ] { |
| 1254 | let mut arena = super::testArena(); |
| 1255 | let storage: 'test = &mut arena in { |
| 1256 | let mut res = super::testResolver(storage); |
| 1257 | let result = try super::resolveProgramStr(&mut res, program); |
| 1258 | try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding); |
| 1259 | } |
| 1260 | } |
| 1261 | } |
| 1262 | |
| 1263 | /// A reference through an exclusive field cannot outlive the owner's borrow. |
| 1264 | @test unsafe fn testExclusiveOwnerBorrowLifetimes() throws (testing::TestError) { |
| 1265 | for program in [ |
| 1266 | "record H: 'r { item: &'r mut u32 } fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { let p: &'r u32 = h.item; return p; }", |
| 1267 | "record H: 'r { item: ?&'r mut u32 } fn f 'r 's (h: &'s H 'r) -> ?&'r u32 where 'r: 's { let p: ?&'r u32 = h.item; return p; }", |
| 1268 | "record H: 'r { item: &'r mut [u32] } fn f 'r 's (h: &'s H 'r) -> &'r [u32] where 'r: 's { let p: &'r [u32] = h.item; return p; }", |
| 1269 | "record H: 'r { item: &'r mut u32 } unsafe fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { let p: &'r u32 = h.item; return p; }", |
| 1270 | "record H: 'r { item: ?&'r mut u32 } unsafe fn f 'r 's (h: &'s H 'r) -> ?&'r u32 where 'r: 's { let p: ?&'r u32 = h.item; return p; }", |
| 1271 | "record H: 'r { item: &'r mut [u32] } unsafe fn f 'r 's (h: &'s H 'r) -> &'r [u32] where 'r: 's { let p: &'r [u32] = h.item; return p; }", |
| 1272 | "record H: 'r { item: &'r mut u32 } fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &*h.item; }", |
| 1273 | "record H: 'r { item: &'r mut u32 } unsafe fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &*h.item; }", |
| 1274 | "record H: 'r { items: &'r mut [u32] } fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &h.items[0]; }", |
| 1275 | "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &h.items[0]; }", |
| 1276 | "record H: 'r { item: &'r mut u32 } fn f 'r 's (h: &'s mut H 'r) -> &'r mut u32 where 'r: 's { return &mut *h.item; }", |
| 1277 | "record H: 'r { item: &'r mut u32 } unsafe fn f 'r 's (h: &'s mut H 'r) -> &'r mut u32 where 'r: 's { return &mut *h.item; }", |
| 1278 | "record H { item: *mut u32 } fn f(h: &H) -> *u32 { return &*h.item; }", |
| 1279 | "record H { item: *mut u32 } unsafe fn f(h: &H) -> *u32 { return &*h.item; }", |
| 1280 | "record H: 'r { items: &'r mut [u32] } fn f 'r 's (h: &'s H 'r) -> &'r [u32] where 'r: 's { return &h.items[..]; }", |
| 1281 | "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r 's (h: &'s H 'r) -> &'r [u32] where 'r: 's { return &h.items[..]; }", |
| 1282 | ] { |
| 1283 | let mut arena = super::testArena(); |
| 1284 | let storage: 'test = &mut arena in { |
| 1285 | let mut res = super::testResolver(storage); |
| 1286 | let result = try super::resolveProgramStr(&mut res, program); |
| 1287 | let error = try super::expectError(&result); |
| 1288 | let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed; |
| 1289 | } |
| 1290 | } |
| 1291 | } |
| 1292 | |
| 1293 | /// A shared binding cannot hide a move from an exclusive field. |
| 1294 | @test unsafe fn testSharedBindingPreservesSourceOwnership() throws (testing::TestError) { |
| 1295 | for program in [ |
| 1296 | "record H { item: *mut u32 } fn f(h: H) -> *u32 { let p: *u32 = h.item; return p; }", |
| 1297 | "record H { item: ?*mut u32 } fn f(h: H) -> ?*u32 { let p: ?*u32 = h.item; return p; }", |
| 1298 | "record H: 'r { item: &'r mut u32 } fn f 'r (h: &'r H 'r) -> &'r u32 { let p: &'r u32 = h.item; return p; }", |
| 1299 | "record H { item: *mut u32 } unsafe fn f(h: H) -> *u32 { let p: *u32 = h.item; return p; }", |
| 1300 | "record H { item: ?*mut u32 } unsafe fn f(h: H) -> ?*u32 { let p: ?*u32 = h.item; return p; }", |
| 1301 | "record H: 'r { item: &'r mut u32 } unsafe fn f 'r (h: &'r H 'r) -> &'r u32 { let p: &'r u32 = h.item; return p; }", |
| 1302 | ] { |
| 1303 | let mut arena = super::testArena(); |
| 1304 | let storage: 'test = &mut arena in { |
| 1305 | let mut res = super::testResolver(storage); |
| 1306 | let result = try super::resolveProgramStr(&mut res, program); |
| 1307 | try super::expectErrorKind(&result, resolver::ErrorKind::LinearPartialMove); |
| 1308 | } |
| 1309 | } |
| 1310 | } |
| 1311 | |
| 1312 | /// Methods and trait instances resolve declaration region parameters. |
| 1313 | @test unsafe fn testRegionalMethods() throws (testing::TestError) { |
| 1314 | for program in [ |
| 1315 | "record View: 'r { value: &'r u32 } fn (view: &View 'r) get 'r () -> &'r u32 { return view.value; } fn read 'x (view: &View 'x) -> u32 { return *view.get(); }", |
| 1316 | "trait Pick { fn (&Pick) pick 'r (value: &'r u32) -> &'r u32; } record Picker {} instance Pick for Picker { fn (picker: &Picker) pick 'r (value: &'r u32) -> &'r u32 { return value; } } fn choose 'x (picker: &opaque Pick, value: &'x u32) -> &'x u32 { return picker.pick(value); }", |
| 1317 | "trait Read { fn (&Read) read() -> u32; } record Regional: 'r { value: &'r u32 } instance Read for Regional 'r { fn (value: &Regional 'r) read() -> u32 { return *value.value; } } fn inspect(value: &opaque Read) -> u32 { return value.read(); } fn call 'x (value: &Regional 'x) -> u32 { return inspect(value); }", |
| 1318 | ] { |
| 1319 | let mut arena = super::testArena(); |
| 1320 | let storage: 'method = &mut arena in { |
| 1321 | let mut res = super::testResolver(storage); |
| 1322 | let result = try super::resolveProgramStr(&mut res, program); |
| 1323 | try super::expectNoErrors(&result); |
| 1324 | } |
| 1325 | } |
| 1326 | } |