lib/std/lang/resolver/tests/regions.rad 74.2 KiB 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
}