lib/std/lang/resolver/tests/regions.rad 97.8 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
use std::lang::ast;
8
9
/// Optional aggregate payloads start at their required alignment after the tag.
10
@test fn testOptionalPayloadOffsets() throws (testing::TestError) {
11
    for alignment in [1 as u32, 2, 4, 8, 16] {
12
        let layout = resolver::Layout { size: 32, alignment };
13
        assert resolver::getOptionalValOffset(layout) == alignment;
14
    }
15
}
16
17
/// Each declaration has a distinct identity within its resolver.
18
@test unsafe fn testSymbolIdentities() throws (testing::TestError) {
19
    let mut arena = super::testArena();
20
    let storage: 'test = &mut arena in {
21
        let mut res = super::testResolver(storage);
22
        let result = try super::resolveProgramStr(&mut res, "fn f() {} fn g() {}");
23
        try super::expectNoErrors(&result);
24
        let case ast::NodeValue::Block(block) = result.root.value else throw testing::TestError::Failed;
25
        let first = resolver::symbolFor(&res, block.statements[0]) else throw testing::TestError::Failed;
26
        let second = resolver::symbolFor(&res, block.statements[1]) else throw testing::TestError::Failed;
27
        assert first.id <> second.id;
28
        assert first.id < res.symbolCount;
29
        assert second.id < res.symbolCount;
30
        let firstBinding = resolver::nodeData(&res, block.statements[0]).binding else throw testing::TestError::Failed;
31
        let secondBinding = resolver::nodeData(&res, block.statements[1]).binding else throw testing::TestError::Failed;
32
        assert firstBinding.id == first.id;
33
        assert secondBinding.id == second.id;
34
    }
35
}
36
37
/// Trait lookup accepts empty tables from safe code.
38
@test fn testEmptyTraitMethodLookup() throws (testing::TestError) {
39
    assert resolver::findTraitMethod(&[], "missing") == nil;
40
}
41
42
/// Trait lookup returns the matching method metadata in declaration order.
43
@test unsafe fn testTraitMethodLookup() throws (testing::TestError) {
44
    let mut arena = super::testArena();
45
    let storage: 'test = &mut arena in {
46
        let mut res = super::testResolver(storage);
47
        let result = try super::resolveProgramStr(&mut res, "trait R { fn (&R) first(); fn (&mut R) second(); }");
48
        try super::expectNoErrors(&result);
49
        let case ast::NodeValue::Block(block) = result.root.value else throw testing::TestError::Failed;
50
        let sym = resolver::symbolFor(&res, block.statements[0]) else throw testing::TestError::Failed;
51
        let case resolver::SymbolData::Trait(info) = sym.data else throw testing::TestError::Failed;
52
        let first = resolver::findTraitMethod(&info.methods[..], "first") else throw testing::TestError::Failed;
53
        let last = resolver::findTraitMethod(&info.methods[..], "second") else throw testing::TestError::Failed;
54
        assert first.index == 0;
55
        assert not first.mutable;
56
        assert last.index == 1;
57
        assert last.mutable;
58
        assert resolver::findTraitMethod(&info.methods[..], "missing") == nil;
59
    }
60
}
61
62
/// Standalone method identities select independent registry entries.
63
@test unsafe fn testStandaloneMethodIdentityLookup() throws (testing::TestError) {
64
    let mut arena = super::testArena();
65
    let storage: 'test = &mut arena in {
66
        let mut res = super::testResolver(storage);
67
        let result = try super::resolveProgramStr(&mut res, "record R {} fn (r: &R) first() {} fn (r: &mut R) second() {}");
68
        try super::expectNoErrors(&result);
69
        let case ast::NodeValue::Block(block) = result.root.value else throw testing::TestError::Failed;
70
        let firstSymbol = resolver::symbolFor(&res, block.statements[1]) else throw testing::TestError::Failed;
71
        let lastSymbol = resolver::symbolFor(&res, block.statements[2]) else throw testing::TestError::Failed;
72
        let first = resolver::findMethodBySymbol(&res, firstSymbol.id) else throw testing::TestError::Failed;
73
        let last = resolver::findMethodBySymbol(&res, lastSymbol.id) else throw testing::TestError::Failed;
74
        assert mem::eq(first.name, "first");
75
        assert not first.mutable;
76
        assert mem::eq(last.name, "second");
77
        assert last.mutable;
78
        assert first.fullFnType.paramTypes.len == 1;
79
        assert first.fnType.paramTypes.len == 0;
80
        assert last.fullFnType.paramTypes.len == 1;
81
        assert last.fnType.paramTypes.len == 0;
82
        assert resolver::findMethodBySymbol(&res, res.symbolCount) == nil;
83
    }
84
}
85
86
/// Iteration over raw slices requires permission to read their storage.
87
@test unsafe fn testRawSliceIterationRequiresUnsafe() throws (testing::TestError) {
88
    for program in [
89
        "fn f(p: *unsafe [u32]) { for item in p { assert item == 0; } }",
90
        "fn f(p: *unsafe mut [u32]) { for item, index in p { assert item == index; } }",
91
        "record R { items: *unsafe [u32] } fn f(r: &R) { for item in r.items { assert item == 0; } }",
92
    ] {
93
        let mut arena = super::testArena();
94
        let storage: 'test = &mut arena in {
95
            let mut res = super::testResolver(storage);
96
            let result = try super::resolveProgramStr(&mut res, program);
97
            try super::expectErrorKind(&result, resolver::ErrorKind::UnsafeOperation);
98
        }
99
    }
100
}
101
102
/// Checked iteration is safe, and raw iteration accepts explicit permission.
103
@test unsafe fn testSliceIterationPermissions() throws (testing::TestError) {
104
    for program in [
105
        "unsafe fn f(p: *unsafe [u32]) { for item in p { assert item == 0; } }",
106
        "fn f(p: *unsafe [u32]) { unsafe { for item in p { assert item == 0; } } }",
107
        "fn f(p: &[u32]) { for item in p { assert item == 0; } }",
108
        "fn f(p: &mut [u32]) { for item, index in p { assert item == index; } }",
109
        "fn f(p: [u32; 2]) { for item in p { assert item == 0; } }",
110
    ] {
111
        let mut arena = super::testArena();
112
        let storage: 'test = &mut arena in {
113
            let mut res = super::testResolver(storage);
114
            let result = try super::resolveProgramStr(&mut res, program);
115
            try super::expectNoErrors(&result);
116
        }
117
    }
118
}
119
120
/// Short-circuit paths must agree on exact-use regional ownership.
121
@test unsafe fn testRegionalShortCircuitOwnership() throws (testing::TestError) {
122
    for program in [
123
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r) { let result = false and take(t); }",
124
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r) { let result = true or take(t); }",
125
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r, flag: bool) { let result = flag and take(t); }",
126
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } unsafe fn f 'r (t: Ticket 'r, flag: bool) { let result = flag or take(t); }",
127
    ] {
128
        let mut arena = super::testArena();
129
        let storage: 'test = &mut arena in {
130
            let mut res = super::testResolver(storage);
131
            let result = try super::resolveProgramStr(&mut res, program);
132
            let error = try super::expectError(&result);
133
            let case resolver::ErrorKind::LinearBranchMismatch(_) = error.kind
134
                else throw testing::TestError::Failed;
135
        }
136
    }
137
}
138
139
/// The left operand executes on every short-circuit path.
140
@test unsafe fn testRegionalShortCircuitLeftConsumption() throws (testing::TestError) {
141
    for program in [
142
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r) { let result = take(t) and false; }",
143
        "union Ticket: 'r + Once { Value(&'r u32) } fn take 'r (t: Ticket 'r) -> bool { match t { case Ticket::Value(p) => return *p == 1, } } fn f 'r (t: Ticket 'r) { let result = take(t) or true; }",
144
    ] {
145
        let mut arena = super::testArena();
146
        let storage: 'test = &mut arena in {
147
            let mut res = super::testResolver(storage);
148
            let result = try super::resolveProgramStr(&mut res, program);
149
            try super::expectNoErrors(&result);
150
        }
151
    }
152
}
153
154
/// Earlier reference arguments protect their storage during later arguments.
155
@test unsafe fn testRegionalCallArgumentLoans() throws (testing::TestError) {
156
    for program in [
157
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &mut u32, n: u32) {} fn f 'r (p: &'r mut u32) { outer(&mut *p, inner(p)); }",
158
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32) { outer(&*p, inner(p)); }",
159
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &mut u32, n: u32) {} unsafe fn f 'r (p: &'r mut u32) { outer(&mut *p, inner(p)); }",
160
        "record R { n: u32 } fn (r: &mut R) call(n: u32) {} fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn f 'r (r: &'r mut R) { (&mut *r).call(inner(&mut r.n)); }",
161
    ] {
162
        let mut arena = super::testArena();
163
        let storage: 'test = &mut arena in {
164
            let mut res = super::testResolver(storage);
165
            let result = try super::resolveProgramStr(&mut res, program);
166
            let error = try super::expectError(&result);
167
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
168
                else throw testing::TestError::Failed;
169
        }
170
    }
171
}
172
173
/// Conditional cell creation protects each source from ordinary shared access.
174
@test unsafe fn testConditionalCellArgumentLoans() throws (testing::TestError) {
175
    for program in [
176
        "fn inspect(c: &cell u32, p: &u32) { set *c = 2; } fn f(p: &mut u32, q: &mut u32, flag: bool) { inspect(&cell *p if flag else &cell *q, p); }",
177
        "fn inspect(c: &cell u32, p: &u32) { set *c = 2; } unsafe fn f(p: &mut u32, q: &mut u32, flag: bool) { inspect(&cell *p if flag else &cell *q, q); }",
178
        "fn read(p: &u32) -> u32 { return *p; } fn inspect(c: &cell u32, n: u32) {} fn f(p: &mut u32, q: &mut u32, flag: bool) { inspect(&cell *p if flag else &cell *q, read(q)); }",
179
        "fn inspect(c: &cell u32, p: &u32) {} fn f(p: &mut u32, q: &mut u32, flag: bool) { inspect((&cell *p if flag else &cell *q) as &cell u32, p); }",
180
    ] {
181
        let mut arena = super::testArena();
182
        let storage: 'test = &mut arena in {
183
            let mut res = super::testResolver(storage);
184
            let result = try super::resolveProgramStr(&mut res, program);
185
            let error = try super::expectError(&result);
186
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
187
                else throw testing::TestError::Failed;
188
        }
189
    }
190
}
191
192
/// Conditional cell loans allow separate storage and shared cell aliases.
193
@test unsafe fn testConditionalCellArgumentLoanScopes() throws (testing::TestError) {
194
    for program in [
195
        "fn inspect(c: &cell u32, p: &u32) {} fn f(p: &mut u32, q: &mut u32, r: &u32, flag: bool) { inspect(&cell *p if flag else &cell *q, r); set *p = 1; set *q = 2; }",
196
        "record R { a: u32, b: u32, c: u32 } fn inspect(c: &cell u32, p: &u32) {} fn f(r: &mut R, flag: bool) { inspect(&cell r.a if flag else &cell r.b, &r.c); set r.a = 1; }",
197
        "fn inspect(a: &cell u32, b: &cell u32) {} fn f(a: &cell u32, b: &cell u32, flag: bool) { inspect(a if flag else b, a); }",
198
    ] {
199
        let mut arena = super::testArena();
200
        let storage: 'test = &mut arena in {
201
            let mut res = super::testResolver(storage);
202
            let result = try super::resolveProgramStr(&mut res, program);
203
            try super::expectNoErrors(&result);
204
        }
205
    }
206
}
207
208
/// Conditional explicit arguments protect every possible borrowed place.
209
@test unsafe fn testConditionalCallArgumentLoans() throws (testing::TestError) {
210
    for program in [
211
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(&*p if flag else &*q, inner(p)); }",
212
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(&*p if flag else &*q, inner(q)); }",
213
        "fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(&mut *p if flag else &mut *q, &mut *p); }",
214
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &u32, n: u32) {} unsafe fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(&*p if flag else &*q, inner(q)); }",
215
        "fn outer(p: &mut u32, q: &mut u32) {} unsafe fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(&mut *p if flag else &mut *q, &mut *q); }",
216
        "fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer((&*p if flag else &*q) as &u32, inner(p)); }",
217
        "record R { n: u32 } fn (r: &R) call(n: u32) {} fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn f 'r (p: &'r mut R, q: &'r mut R, flag: bool) { (&*p if flag else &*q).call(inner(&mut q.n)); }",
218
    ] {
219
        let mut arena = super::testArena();
220
        let storage: 'test = &mut arena in {
221
            let mut res = super::testResolver(storage);
222
            let result = try super::resolveProgramStr(&mut res, program);
223
            let error = try super::expectError(&result);
224
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
225
                else throw testing::TestError::Failed;
226
        }
227
    }
228
}
229
230
/// Conditional argument alternatives cannot overlap another exclusive argument.
231
@test unsafe fn testConditionalCallArgumentOverlap() throws (testing::TestError) {
232
    for program in [
233
        "fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(p if flag else q, p); }",
234
        "fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(p if flag else q, q); }",
235
        "fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(p, p if flag else q); }",
236
        "fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(q, p if flag else q); }",
237
        "fn outer(p: &mut u32, q: &mut u32) {} unsafe fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(p if flag else q, p); }",
238
        "fn outer(p: &u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(p if flag else q, q); }",
239
        "fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(p if flag else q, q if flag else p); }",
240
        "fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, r: &'r mut u32, a: bool, b: bool) { outer((p if a else q) if b else r, q); }",
241
        "fn outer(p: &u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer((p if flag else q) as &'r u32, p); }",
242
        "record R { n: u32 } fn (r: &mut R) call(p: &R) {} fn f 'r (p: &'r mut R, q: &'r mut R, flag: bool) { (p if flag else q).call(p); }",
243
        "trait R { fn (&mut R) call(p: &opaque R); } fn f 'r (p: &'r mut opaque R, q: &'r mut opaque R, flag: bool) { (p if flag else q).call(q); }",
244
    ] {
245
        let mut arena = super::testArena();
246
        let storage: 'test = &mut arena in {
247
            let mut res = super::testResolver(storage);
248
            let result = try super::resolveProgramStr(&mut res, program);
249
            let error = try super::expectError(&result);
250
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
251
                else throw testing::TestError::Failed;
252
        }
253
    }
254
}
255
256
/// Conditional argument alternatives permit shared access and disjoint places.
257
@test unsafe fn testConditionalCallArgumentSeparation() throws (testing::TestError) {
258
    for program in [
259
        "fn outer(p: &u32, q: &u32) {} fn f 'r (p: &'r u32, q: &'r u32, flag: bool) { outer(p if flag else q, p); }",
260
        "fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, r: &'r mut u32, flag: bool) { outer(p if flag else q, r); }",
261
        "record R: 'r { a: &'r mut u32, b: &'r mut u32, c: &'r mut u32 } fn outer(p: &mut u32, q: &mut u32) {} fn f 'r (r: &mut R 'r, flag: bool) { outer(r.a if flag else r.b, r.c); }",
262
        "record R { n: u32 } fn (r: &mut R) call(p: &R) {} fn f 'r (p: &'r mut R, q: &'r mut R, r: &'r R, flag: bool) { (p if flag else q).call(r); }",
263
    ] {
264
        let mut arena = super::testArena();
265
        let storage: 'test = &mut arena in {
266
            let mut res = super::testResolver(storage);
267
            let result = try super::resolveProgramStr(&mut res, program);
268
            try super::expectNoErrors(&result);
269
        }
270
    }
271
}
272
273
/// Call loans allow shared reads, separate fields, and access after the call.
274
@test unsafe fn testRegionalCallArgumentLoanScopes() throws (testing::TestError) {
275
    for program in [
276
        "fn read(p: &u32) -> u32 { return *p; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32, q: &'r mut u32, flag: bool) { outer(&*p if flag else &*q, read(p)); set *p = 3; set *q = 4; }",
277
        "record R { a: u32, b: u32, c: u32 } fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &mut u32, n: u32) {} fn f 'r (r: &'r mut R, flag: bool) { outer(&mut r.a if flag else &mut r.b, inner(&mut r.c)); set r.a = 3; }",
278
        "fn outer(p: &mut u32, n: u32) {} fn f 'r (p: &'r mut u32, flag: bool) { outer(&mut *p if flag else &mut *p, 0); set *p = 3; }",
279
        "fn read(p: &u32) -> u32 { return *p; } fn outer(p: &u32, n: u32) {} fn f 'r (p: &'r mut u32) { outer(&*p, read(p)); set *p = 3; }",
280
        "record R { a: u32, b: u32 } fn inner(p: &mut u32) -> u32 { set *p = 2; return 0; } fn outer(p: &mut u32, n: u32) {} fn f 'r (r: &'r mut R) { outer(&mut r.a, inner(&mut r.b)); set r.a = 3; }",
281
    ] {
282
        let mut arena = super::testArena();
283
        let storage: 'test = &mut arena in {
284
            let mut res = super::testResolver(storage);
285
            let result = try super::resolveProgramStr(&mut res, program);
286
            try super::expectNoErrors(&result);
287
        }
288
    }
289
}
290
291
/// Equal region spellings in separate functions have distinct identities.
292
@test unsafe fn testRegionIdentities() throws (testing::TestError) {
293
    let mut testArena1 = super::testArena();
294
    let testStorage1: 'test1 = &mut testArena1 in {
295
        let mut res = super::testResolver(testStorage1);
296
        let result = try super::resolveProgramStr(&mut res,
297
            "fn first 'r (p: &'r u8) -> u8 { return *p; }\nfn second 'r (p: &'r u8) -> u8 { return *p; }"
298
        );
299
        try super::expectNoErrors(&result);
300
        let first = try super::getBlockStmt(result.root, 0);
301
        let second = try super::getBlockStmt(result.root, 1);
302
        let firstType = resolver::typeFor(&res, first) else throw testing::TestError::Failed;
303
        let secondType = resolver::typeFor(&res, second) else throw testing::TestError::Failed;
304
        let case resolver::Type::Fn(a) = firstType else throw testing::TestError::Failed;
305
        let case resolver::Type::Fn(b) = secondType else throw testing::TestError::Failed;
306
        let case resolver::Type::Pointer { class: types::PointerClass::Region(ar), .. } = *a.paramTypes[0]
307
            else throw testing::TestError::Failed;
308
        let case resolver::Type::Pointer { class: types::PointerClass::Region(br), .. } = *b.paramTypes[0]
309
            else throw testing::TestError::Failed;
310
        try testing::expect(mem::eq(ar.name, br.name));
311
        try testing::expect(ar.id <> br.id);
312
        try testing::expect(not resolver::typesEqual(*a.paramTypes[0], *b.paramTypes[0]));
313
        try testing::expect(resolver::getTypeLayout(*a.paramTypes[0]).size == 8);
314
    }
315
}
316
317
/// Parent links resolve forward declarations and preserve transitive ancestry.
318
@test unsafe fn testRegionParents() throws (testing::TestError) {
319
    let mut testArena2 = super::testArena();
320
    let testStorage2: 'test2 = &mut testArena2 in {
321
        let mut res = super::testResolver(testStorage2);
322
        let result = try super::resolveProgramStr(&mut res,
323
            "fn read 'child 'middle 'root (p: &'child u8, q: &'root u8) where 'middle: 'child, 'root: 'middle {}"
324
        );
325
        try super::expectNoErrors(&result);
326
        let func = try super::getBlockStmt(result.root, 0);
327
        let ty = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
328
        let case resolver::Type::Fn(info) = ty else throw testing::TestError::Failed;
329
        let case resolver::Type::Pointer { class: types::PointerClass::Region(child), .. } = *info.paramTypes[0]
330
            else throw testing::TestError::Failed;
331
        let case resolver::Type::Pointer { class: types::PointerClass::Region(root), .. } = *info.paramTypes[1]
332
            else throw testing::TestError::Failed;
333
        try testing::expect(types::regionContains(root, child));
334
        try testing::expect(types::regionContains(child, child));
335
        try testing::expect(not types::regionContains(child, root));
336
    }
337
}
338
339
/// Region declarations reject duplicate names, missing parents, and cycles.
340
@test unsafe fn testInvalidRegionDeclarations() throws (testing::TestError) {
341
    for program in [
342
        "fn f 'r 'r () {}",
343
        "fn f 'r () where 'missing: 'r {}",
344
        "fn f 'r () where 'r: 'r {}",
345
        "fn f 'a 'b 'c () where 'b: 'a, 'c: 'b, 'a: 'c {}",
346
    ] {
347
        let mut testArena3 = super::testArena();
348
        let testStorage3: 'test3 = &mut testArena3 in {
349
            let mut res = super::testResolver(testStorage3);
350
            let result = try super::resolveProgramStr(&mut res, program);
351
            let _ = try super::expectError(&result);
352
        }
353
    }
354
}
355
356
/// Regions from another declaration cannot enter a function signature or body.
357
@test unsafe fn testUnknownRegionNames() throws (testing::TestError) {
358
    for program in [
359
        "fn f(p: &'missing u8) {}",
360
        "fn f 'r (p: &'r u8) {} fn g(p: &'r u8) {}",
361
        "unsafe fn f(p: &'missing u8) {}",
362
        "fn f 'r (p: &'r u8) { let q: &'missing u8 = p; }",
363
    ] {
364
        let mut testArena4 = super::testArena();
365
        let testStorage4: 'test4 = &mut testArena4 in {
366
            let mut res = super::testResolver(testStorage4);
367
            let result = try super::resolveProgramStr(&mut res, program);
368
            let err = try super::expectError(&result);
369
            let case resolver::ErrorKind::UnknownRegion(_) = err.kind
370
                else throw testing::TestError::Failed;
371
        }
372
    }
373
}
374
375
/// An ancestor relation does not make distinct reference regions assignable.
376
@test unsafe fn testRegionInvariance() throws (testing::TestError) {
377
    for program in [
378
        "fn f 'a 'b (p: &'a u8) where 'a: 'b { let q: &'b u8 = p; }",
379
        "unsafe fn f 'a 'b (p: &'b u8) where 'a: 'b { let q: &'a u8 = p; }",
380
    ] {
381
        let mut testArena5 = super::testArena();
382
        let testStorage5: 'test5 = &mut testArena5 in {
383
            let mut res = super::testResolver(testStorage5);
384
            let result = try super::resolveProgramStr(&mut res, program);
385
            let err = try super::expectError(&result);
386
            let case resolver::ErrorKind::TypeMismatch(_) = err.kind
387
                else throw testing::TestError::Failed;
388
        }
389
    }
390
}
391
392
/// Nominal region environments diagnose their own invalid parent relations.
393
@test unsafe fn testNominalRegionNames() throws (testing::TestError) {
394
    for program in [
395
        "record R: 'r where 'missing: 'r { value: u8 }",
396
        "union U: 'r where 'missing: 'r { Empty }",
397
        "record R: 'r { value: &'other u8 }",
398
        "union U: 'r { Value(&'other u8) }",
399
    ] {
400
        let mut testArena6 = super::testArena();
401
        let testStorage6: 'test6 = &mut testArena6 in {
402
            let mut res = super::testResolver(testStorage6);
403
            let result = try super::resolveProgramStr(&mut res, program);
404
            let err = try super::expectError(&result);
405
            let case resolver::ErrorKind::UnknownRegion(_) = err.kind
406
                else throw testing::TestError::Failed;
407
        }
408
    }
409
    for program in [
410
        "record R: 'r + 'r { value: u8 }",
411
        "union U: 'r + 'r { Empty }",
412
    ] {
413
        let mut testArena7 = super::testArena();
414
        let testStorage7: 'test7 = &mut testArena7 in {
415
            let mut res = super::testResolver(testStorage7);
416
            let result = try super::resolveProgramStr(&mut res, program);
417
            let _ = try super::expectErrorKind(&result, resolver::ErrorKind::DuplicateBinding("'r"));
418
        }
419
    }
420
}
421
422
/// Region declarations restore their environment after a signature error.
423
@test unsafe fn testRegionErrorScopeRestoration() throws (testing::TestError) {
424
    let mut testArena8 = super::testArena();
425
    let testStorage8: 'test8 = &mut testArena8 in {
426
        let mut res = super::testResolver(testStorage8);
427
        let result = try super::resolveProgramStr(&mut res,
428
            "fn f 'r (p: &'missing u8) {} fn g 'other (p: &'r u8) {}"
429
        );
430
        let err = try super::expectError(&result);
431
        let case resolver::ErrorKind::UnknownRegion(name) = err.kind
432
            else throw testing::TestError::Failed;
433
        try testing::expect(mem::eq(name, "'missing"));
434
        try testing::expect(res.regionScope == nil);
435
        try testing::expect(res.currentFn == nil);
436
        try testing::expect(res.currentFnNode == nil);
437
    }
438
}
439
440
/// Regional exclusive references retain affine ownership and arithmetic checks.
441
@test unsafe fn testRegionExclusiveOwnership() throws (testing::TestError) {
442
    for program in [
443
        "fn f 'r (p: &'r mut u8) { let q: &'r mut u8 = p; set *p = 3; }",
444
        "unsafe fn f 'r (p: &'r mut u8) { let q: &'r mut u8 = p; set *p = 3; }",
445
        "unsafe fn f 'r (p: &'r mut u8) { let q = p + 1; }",
446
        "unsafe fn f 'r (p: &'r mut u8) { let q = p as *mut u8; }",
447
    ] {
448
        let mut testArena9 = super::testArena();
449
        let testStorage9: 'test9 = &mut testArena9 in {
450
            let mut res = super::testResolver(testStorage9);
451
            let result = try super::resolveProgramStr(&mut res, program);
452
            let _ = try super::expectError(&result);
453
        }
454
    }
455
}
456
457
/// Callback signatures preserve the same region substitution as data arguments.
458
@test unsafe fn testRegionCallbackSubstitution() throws (testing::TestError) {
459
    let mut testArena10 = super::testArena();
460
    let testStorage10: 'test10 = &mut testArena10 in {
461
        let mut res = super::testResolver(testStorage10);
462
        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); }");
463
        let err = try super::expectError(&result);
464
        let case resolver::ErrorKind::RegionInference(_) = err.kind else throw testing::TestError::Failed;
465
    }
466
}
467
468
/// A single region parameter requires one consistent named argument.
469
@test unsafe fn testRegionCallInferenceFailures() throws (testing::TestError) {
470
    for program in [
471
        "fn pair 'r (a: &'r u32, b: &'r u32) {} fn relay 'a 'b (a: &'a u32, b: &'b u32) { pair(a, b); }",
472
        "fn read 'r (p: &'r u32) {} fn relay(p: &u32) { read(p); }",
473
        "unsafe fn read 'r (p: &'r u32) {} unsafe fn relay(p: *unsafe u32) { read(p); }",
474
        "fn answer 'r () -> u32 { return 42; } fn relay() -> u32 { return answer(); }",
475
        "fn read 'r (p: ?&'r u32) {} fn relay() { read(nil); }",
476
        "unsafe fn read 'r (p: ?&'r u32) {} unsafe fn relay() { read(nil); }",
477
    ] {
478
        let mut testArena11 = super::testArena();
479
        let testStorage11: 'test11 = &mut testArena11 in {
480
            let mut res = super::testResolver(testStorage11);
481
            let result = try super::resolveProgramStr(&mut res, program);
482
            let err = try super::expectError(&result);
483
            let case resolver::ErrorKind::RegionInference(_) = err.kind else throw testing::TestError::Failed;
484
        }
485
    }
486
}
487
488
/// Inferred and explicit region arguments must satisfy declared parent relations.
489
@test unsafe fn testRegionCallParents() throws (testing::TestError) {
490
    for program in [
491
        "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); }",
492
        "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); }",
493
    ] {
494
        let mut testArena12 = super::testArena();
495
        let testStorage12: 'test12 = &mut testArena12 in {
496
            let mut res = super::testResolver(testStorage12);
497
            let result = try super::resolveProgramStr(&mut res, program);
498
            let err = try super::expectError(&result);
499
            let case resolver::ErrorKind::RegionParent(_) = err.kind else throw testing::TestError::Failed;
500
        }
501
    }
502
}
503
504
/// Region applications require the declared arity and accessible names.
505
@test unsafe fn testExplicitRegionApplicationErrors() throws (testing::TestError) {
506
    for program in [
507
        "fn read 'r (p: &'r u32) {} fn relay 'a 'b (p: &'a u32) { read 'a 'b (p); }",
508
        "fn read(p: &u32) {} fn relay 'a (p: &'a u32) { read 'a (p); }",
509
    ] {
510
        let mut testArena13 = super::testArena();
511
        let testStorage13: 'test13 = &mut testArena13 in {
512
            let mut res = super::testResolver(testStorage13);
513
            let result = try super::resolveProgramStr(&mut res, program);
514
            let err = try super::expectError(&result);
515
            let case resolver::ErrorKind::RegionArgumentCount(_) = err.kind else throw testing::TestError::Failed;
516
        }
517
    }
518
    let mut testArena14 = super::testArena();
519
    let testStorage14: 'test14 = &mut testArena14 in {
520
        let mut res = super::testResolver(testStorage14);
521
        let result = try super::resolveProgramStr(&mut res, "fn read 'r (p: &'r u32) {} fn relay 'a (p: &'a u32) { read 'missing (p); }");
522
        let err = try super::expectError(&result);
523
        let case resolver::ErrorKind::UnknownRegion(_) = err.kind else throw testing::TestError::Failed;
524
    }
525
}
526
527
/// Region header loans stay active through moves and nested exclusive reborrows.
528
@test unsafe fn testConcreteBorrowConflicts() throws (testing::TestError) {
529
    for program in [
530
        "fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { set x = 2; } }",
531
        "unsafe fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { set x = 2; } }",
532
        "fn run() { let mut x: u32 = 1; let p: 'r = &mut x, q = &mut x in {} }",
533
        "fn run() { let mut x: u32 = 1; let p: 'r = &x, q = &mut x in {} }",
534
        "fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { { let q = p; set *q = 2; } set x = 3; } }",
535
        "fn run() { let mut x: u32 = 1; let p: 'a = &mut x in { let q: 'b = &mut *p in { set *p = 3; } } }",
536
        "fn run(i: u32, j: u32) { let mut x: [u32; 2] = [1, 2]; let p: 'r = &mut x[i], q = &mut x[j] in {} }",
537
    ] {
538
        let mut testArena15 = super::testArena();
539
        let testStorage15: 'test15 = &mut testArena15 in {
540
            let mut res = super::testResolver(testStorage15);
541
            let result = try super::resolveProgramStr(&mut res, program);
542
            let err = try super::expectError(&result);
543
            let case resolver::ErrorKind::BorrowConflict(_) = err.kind else throw testing::TestError::Failed;
544
        }
545
    }
546
}
547
548
/// Borrow headers require existing places and accessible, distinct region names.
549
@test unsafe fn testConcreteRegionNamesAndSources() throws (testing::TestError) {
550
    for program in [
551
        "fn run() { let p: 'r = &1 in {} }",
552
        "fn value() -> u32 { return 1; } fn run() { let p: 'r = &value() in {} }",
553
        "fn run() { let x: u32 = 1; let p: 'r = &x in { let q: 'r = &x in {} } }",
554
        "fn run() { let x: u32 = 1; let p: 'r = &x in {} let q: &'r u32 = &x; }",
555
        "fn run 'a (p: &'a mut u32) { let q: 'b = &mut *p in {} }",
556
    ] {
557
        let mut testArena16 = super::testArena();
558
        let testStorage16: 'test16 = &mut testArena16 in {
559
            let mut res = super::testResolver(testStorage16);
560
            let result = try super::resolveProgramStr(&mut res, program);
561
            let _ = try super::expectError(&result);
562
        }
563
    }
564
565
}
566
567
/// A block-local value cannot supply storage for the whole enclosing region.
568
@test unsafe fn testRegionLocalStorageBoundary() throws (testing::TestError) {
569
    for program in [
570
        "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; } } }",
571
        "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; } } }",
572
        "fn run() { let x: u32 = 1; let p: 'r = &x in { let y: u32 = 2; let q: &'r u32 = &y; } }",
573
        "unsafe fn run() { let x: u32 = 1; let p: 'r = &x in { let y: u32 = 2; let q: &'r u32 = &y; } }",
574
        "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; } } }",
575
    ] {
576
        let mut testArena17 = super::testArena();
577
        let testStorage17: 'test17 = &mut testArena17 in {
578
            let mut res = super::testResolver(testStorage17);
579
            let result = try super::resolveProgramStr(&mut res, program);
580
            let err = try super::expectError(&result);
581
            let case resolver::ErrorKind::TypeMismatch(_) = err.kind else throw testing::TestError::Failed;
582
        }
583
    }
584
585
}
586
587
/// Generic calls keep the exclusive-argument overlap check after substitution.
588
@test unsafe fn testRegionCallBorrowOverlap() throws (testing::TestError) {
589
    let mut testArena18 = super::testArena();
590
    let testStorage18: 'test18 = &mut testArena18 in {
591
        let mut res = super::testResolver(testStorage18);
592
        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); } }");
593
        let err = try super::expectError(&result);
594
        let case resolver::ErrorKind::BorrowConflict(_) = err.kind else throw testing::TestError::Failed;
595
    }
596
}
597
598
/// Ownership markers do not change the positions of nominal region arguments.
599
@test unsafe fn testNominalRegionParameterOrder() throws (testing::TestError) {
600
    for program in [
601
        "record Pair: Copy + 'a + 'b { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }",
602
        "record Pair: 'a + Copy + 'b { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }",
603
        "record Pair: 'a + 'b + Copy { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }",
604
    ] {
605
        let mut arena = super::testArena();
606
        let storage: 'test = &mut arena in {
607
            let mut res = super::testResolver(storage);
608
            let result = try super::resolveProgramStr(&mut res, program);
609
            try super::expectNoErrors(&result);
610
        }
611
    }
612
}
613
614
/// Exact application keys include the base and the ordered region arguments.
615
@test unsafe fn testNominalApplicationKeys() throws (testing::TestError) {
616
    let mut arena = super::testArena();
617
    let storage: 'test = &mut arena in {
618
        let mut res = super::testResolver(storage);
619
        let result = try super::resolveProgramStr(&mut res,
620
            "record N: 'r + 's + Copy { value: u32 } record M: 'r + 's + Copy { value: u32 } fn f 'a 'b (x: N 'a 'b, y: N 'a 'b, z: N 'b 'a, w: N 'a 'a, v: M 'a 'b) {}"
621
        );
622
        try super::expectNoErrors(&result);
623
        let func = try super::getBlockStmt(result.root, 2);
624
        let ty = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
625
        let case resolver::Type::Fn(info) = ty else throw testing::TestError::Failed;
626
        for param, i in info.paramTypes {
627
            for other, j in info.paramTypes {
628
                assert (param == other) == (i == j or (i < 2 and j < 2));
629
            }
630
        }
631
        let mut count: u32 = 0;
632
        let mut cursor = res.applications;
633
        while let entry = cursor {
634
            assert entry.arguments.len == 2;
635
            assert resolver::nominalApplication(entry.view) == entry;
636
            set count += 1;
637
            set cursor = entry.next;
638
        }
639
        assert count == 4;
640
    }
641
}
642
643
/// Exact arguments share one descriptor and all applications share the source layout.
644
@test unsafe fn testNominalRegionApplications() throws (testing::TestError) {
645
    let mut testArena19 = super::testArena();
646
    let testStorage19: 'test19 = &mut testArena19 in {
647
        let mut res = super::testResolver(testStorage19);
648
        let result = try super::resolveProgramStr(&mut res,
649
            "record N: 'r + Copy { value: u32 } fn f 'a 'b (x: N 'a, y: N 'a, z: N 'b) {}"
650
        );
651
        try super::expectNoErrors(&result);
652
        let func = try super::getBlockStmt(result.root, 1);
653
        let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
654
        let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
655
        let case resolver::Type::Nominal(x) = *info.paramTypes[0] else throw testing::TestError::Failed;
656
        let case resolver::Type::Nominal(y) = *info.paramTypes[1] else throw testing::TestError::Failed;
657
        let case resolver::Type::Nominal(z) = *info.paramTypes[2] else throw testing::TestError::Failed;
658
        try testing::expect(x == y);
659
        try testing::expect(x <> z);
660
        try testing::expect(not resolver::typesEqual(*info.paramTypes[0], *info.paramTypes[2]));
661
        let a = resolver::nominalApplication(x) else throw testing::TestError::Failed;
662
        let b = resolver::nominalApplication(z) else throw testing::TestError::Failed;
663
        try testing::expect(a.base == b.base);
664
        try testing::expect(a.arguments[0].id <> b.arguments[0].id);
665
        let case resolver::NominalType::Record(base) = *a.base else throw testing::TestError::Failed;
666
        let case resolver::NominalType::Record(first) = *x else throw testing::TestError::Failed;
667
        let case resolver::NominalType::Record(second) = *z else throw testing::TestError::Failed;
668
        try testing::expect(base.layout == first.layout);
669
        try testing::expect(first.layout == second.layout);
670
        try testing::expect(first.layout.size == 4);
671
    }
672
}
673
674
675
/// Applications introduced in successive function bodies are fully resolved.
676
@test unsafe fn testNominalCompletionAcrossBodies() throws (testing::TestError) {
677
    let mut arena = super::testArena();
678
    let storage: 'test = &mut arena in {
679
        let mut res = super::testResolver(storage);
680
        let result = try super::resolveProgramStr(&mut res,
681
            "record N: 'r + Copy { value: &'r u32 } fn f 'a (x: &'a u32) { let n = N 'a { value: x }; } fn g 'b (x: &'b u32) { let n = N 'b { value: x }; }"
682
        );
683
        try super::expectNoErrors(&result);
684
        let mut count: u32 = 0;
685
        let mut cursor = res.applications;
686
        while let applied = cursor {
687
            let case resolver::NominalType::Record(body) = *applied.view else throw testing::TestError::Failed;
688
            assert body.application == applied;
689
            assert body.fields.len == 1;
690
            set count += 1;
691
            set cursor = applied.next;
692
        }
693
        assert count == 2;
694
    }
695
}
696
697
/// Recursive fields refer to their own exact applied descriptor.
698
@test unsafe fn testRecursiveNominalApplications() throws (testing::TestError) {
699
    let mut testArena20 = super::testArena();
700
    let testStorage20: 'test20 = &mut testArena20 in {
701
        let mut res = super::testResolver(testStorage20);
702
        let result = try super::resolveProgramStr(&mut res,
703
            "record N: 'r + Copy { next: ?*N 'r } fn f 'a 'b (x: N 'a, y: N 'b) {}"
704
        );
705
        try super::expectNoErrors(&result);
706
        let func = try super::getBlockStmt(result.root, 1);
707
        let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
708
        let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
709
        for parameter in info.paramTypes {
710
            let case resolver::Type::Nominal(descriptor) = *parameter else throw testing::TestError::Failed;
711
            let case resolver::NominalType::Record(body) = *descriptor else throw testing::TestError::Failed;
712
            let case resolver::Type::Optional(inner) = body.fields[0].fieldType else throw testing::TestError::Failed;
713
            let case resolver::Type::Pointer { target, .. } = *inner else throw testing::TestError::Failed;
714
            try testing::expect(resolver::typesEqual(*target, *parameter));
715
            try testing::expect(body.layout.size == 8);
716
        }
717
    }
718
}
719
720
/// An inline union payload retains its enclosing application's region arguments.
721
@test unsafe fn testNominalPayloadRegionCapture() throws (testing::TestError) {
722
    let mut testArena21 = super::testArena();
723
    let testStorage21: 'test21 = &mut testArena21 in {
724
        let mut res = super::testResolver(testStorage21);
725
        let result = try super::resolveProgramStr(&mut res,
726
            "record N: 'r + Copy { value: u32 } union U: 'r + Copy { Link { node: *N 'r }, Empty } fn f 'a (u: U 'a, n: N 'a) {}"
727
        );
728
        try super::expectNoErrors(&result);
729
        let func = try super::getBlockStmt(result.root, 2);
730
        let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
731
        let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
732
        let case resolver::Type::Nominal(resolver::NominalType::Union(body)) = *info.paramTypes[0]
733
            else throw testing::TestError::Failed;
734
        let case resolver::Type::Nominal(resolver::NominalType::Record(payload)) = body.variants[0].valueType
735
            else throw testing::TestError::Failed;
736
        let case resolver::Type::Pointer { target, .. } = payload.fields[0].fieldType
737
            else throw testing::TestError::Failed;
738
        try testing::expect(resolver::typesEqual(*target, *info.paramTypes[1]));
739
        let applied = body.application else throw testing::TestError::Failed;
740
        let case resolver::NominalType::Union(base) = *applied.base else throw testing::TestError::Failed;
741
        try testing::expect(body.layout == base.layout);
742
    }
743
}
744
745
/// Nominal applications require exactly the declared number of region arguments.
746
@test unsafe fn testNominalRegionArgumentCount() throws (testing::TestError) {
747
    for program in [
748
        "record N: 'r { value: u32 } fn f(n: N) {}",
749
        "record N { value: u32 } fn f 'r (n: N 'r) {}",
750
        "record N: 'r + 's { value: u32 } fn f 'a (n: N 'a) {}",
751
        "record N: 'r { value: u32 } fn f 'a 'b (n: N 'a 'b) {}",
752
        "record N: 'r { value: u32 } fn f() { let n = N { value: 1 }; }",
753
        "union U: 'r { Empty } fn f() { let u = U::Empty; }",
754
    ] {
755
        let mut testArena22 = super::testArena();
756
        let testStorage22: 'test22 = &mut testArena22 in {
757
            let mut res = super::testResolver(testStorage22);
758
            let result = try super::resolveProgramStr(&mut res, program);
759
            let error = try super::expectError(&result);
760
            let case resolver::ErrorKind::RegionArgumentCount(_) = error.kind else throw testing::TestError::Failed;
761
        }
762
    }
763
}
764
765
/// Type arguments are invariant in values, constructor hints, and patterns.
766
@test unsafe fn testNominalRegionInvariance() throws (testing::TestError) {
767
    for program in [
768
        "record N: 'r + Copy { value: u32 } fn f 'a 'b (n: N 'a) { let x: N 'b = n; }",
769
        "record N: 'r + Copy { value: u32 } unsafe fn f 'a 'b (n: N 'a) { let x: N 'b = n; }",
770
        "record N: 'r + Copy { value: u32 } fn f 'a 'b () { let n: N 'a = N 'b { value: 1 }; }",
771
        "record N: 'r + Copy { value: u32 } fn f 'a 'b (n: N 'a) { let case N 'b { value } = n else panic; }",
772
        "record N: 'r + Copy (u32); fn f 'a 'b (n: N 'a) { let case N 'b (value) = n else panic; }",
773
        "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; }",
774
    ] {
775
        let mut testArena23 = super::testArena();
776
        let testStorage23: 'test23 = &mut testArena23 in {
777
            let mut res = super::testResolver(testStorage23);
778
            let result = try super::resolveProgramStr(&mut res, program);
779
            let error = try super::expectError(&result);
780
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
781
        }
782
    }
783
}
784
785
/// Region inference must agree between an outer reference and its embedded nominal type.
786
@test unsafe fn testNominalRegionInferenceConflict() throws (testing::TestError) {
787
    for program in [
788
        "record N: 'r + Copy { value: u32 } fn take 'r (n: &'r N 'r) {} fn f 'a 'b (n: &'a N 'b) { take(n); }",
789
        "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); }",
790
    ] {
791
        let mut testArena24 = super::testArena();
792
        let testStorage24: 'test24 = &mut testArena24 in {
793
            let mut res = super::testResolver(testStorage24);
794
            let result = try super::resolveProgramStr(&mut res, program);
795
            let error = try super::expectError(&result);
796
            let case resolver::ErrorKind::RegionInference(_) = error.kind else throw testing::TestError::Failed;
797
        }
798
    }
799
}
800
801
/// Applications must satisfy the source declaration's explicit parent relations.
802
@test unsafe fn testNominalRegionParentConstraint() throws (testing::TestError) {
803
    let mut testArena25 = super::testArena();
804
    let testStorage25: 'test25 = &mut testArena25 in {
805
        let mut res = super::testResolver(testStorage25);
806
        let result = try super::resolveProgramStr(&mut res,
807
            "record N: 'r + 's where 'r: 's { value: u32 } fn f 'a 'b (n: N 'a 'b) {}"
808
        );
809
        let error = try super::expectError(&result);
810
        let case resolver::ErrorKind::RegionParent(_) = error.kind else throw testing::TestError::Failed;
811
    }
812
}
813
814
/// An applied affine type retains the source declaration's move rule.
815
@test unsafe fn testNominalRegionMoveRule() throws (testing::TestError) {
816
    let mut testArena26 = super::testArena();
817
    let testStorage26: 'test26 = &mut testArena26 in {
818
        let mut res = super::testResolver(testStorage26);
819
        let result = try super::resolveProgramStr(&mut res,
820
            "record N: 'r { value: u32 } fn f 'a (n: N 'a) { let first = n; let second = n; }"
821
        );
822
        let error = try super::expectError(&result);
823
        let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
824
    }
825
}
826
827
/// By-value cycles have no layout, including cycles through exact applications.
828
@test unsafe fn testNominalRegionValueCycle() throws (testing::TestError) {
829
    for program in [
830
        "record N: 'r { next: N 'r }",
831
        "record N: 'r { next: ?N 'r }",
832
        "union U: 'r { More(U 'r), Empty }",
833
        "record N: 'r { m: M 'r } record M: 'r { n: N 'r }",
834
    ] {
835
        let mut testArena27 = super::testArena();
836
        let testStorage27: 'test27 = &mut testArena27 in {
837
            let mut res = super::testResolver(testStorage27);
838
            let result = try super::resolveProgramStr(&mut res, program);
839
            let error = try super::expectError(&result);
840
            let case resolver::ErrorKind::RecursiveType = error.kind else throw testing::TestError::Failed;
841
        }
842
    }
843
}
844
845
/// Recursive substitutions can permute arguments without expanding the type graph.
846
@test unsafe fn testNominalRegionPermutation() throws (testing::TestError) {
847
    let mut testArena28 = super::testArena();
848
    let testStorage28: 'test28 = &mut testArena28 in {
849
        let mut res = super::testResolver(testStorage28);
850
        let result = try super::resolveProgramStr(&mut res,
851
            "record N: 'r + 's + Copy { next: ?*N 's 'r } fn f 'a 'b (x: N 'a 'b, y: N 'b 'a) {}"
852
        );
853
        try super::expectNoErrors(&result);
854
        let func = try super::getBlockStmt(result.root, 1);
855
        let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
856
        let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
857
        for parameter, i in info.paramTypes {
858
            let case resolver::Type::Nominal(resolver::NominalType::Record(body)) = *parameter
859
                else throw testing::TestError::Failed;
860
            let case resolver::Type::Optional(inner) = body.fields[0].fieldType else throw testing::TestError::Failed;
861
            let case resolver::Type::Pointer { target, .. } = *inner else throw testing::TestError::Failed;
862
            try testing::expect(resolver::typesEqual(*target, *info.paramTypes[1 - i]));
863
        }
864
    }
865
}
866
867
/// Calls transfer named exclusive references on normal and error paths.
868
@test unsafe fn testRegionalCallOwnershipTransfer() throws (testing::TestError) {
869
    for program in [
870
        "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32) { take(p); take(p); }",
871
        "fn take 'r (p: &'r mut u32) {} unsafe fn run 'r (p: &'r mut u32) { take(p); set *p = 1; }",
872
        "fn take 'r (p: &'r mut [u32]) {} fn run 'r (p: &'r mut [u32]) { take(p); p[0]; }",
873
        "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32) { let f = take 'r; f(p); set *p = 1; }",
874
        "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; }",
875
        "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32, c: bool) { if c { take(p); } set *p = 1; }",
876
    ] {
877
        let mut testArena29 = super::testArena();
878
        let testStorage29: 'test29 = &mut testArena29 in {
879
            let mut res = super::testResolver(testStorage29);
880
            let result = try super::resolveProgramStr(&mut res, program);
881
            let error = try super::expectError(&result);
882
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
883
        }
884
    }
885
}
886
887
/// Full-region projections protect their source after a local binding leaves scope.
888
@test unsafe fn testRegionalProjectionLifetime() throws (testing::TestError) {
889
    for program in [
890
        "fn f 'r (p: &'r mut u32) { let shared = &*p; let copy = shared; set *p = 1; }",
891
        "unsafe fn f 'r (p: &'r mut u32) { let shared = &*p; let copy = shared; set *p = 1; }",
892
        "fn f 'r (p: &'r mut u32, q: &'r u32) { let mut cursor = q; set cursor = &*p; set *p = 1; }",
893
        "unsafe fn f 'r (p: &'r mut u32, q: &'r u32) { let mut cursor = q; set cursor = &*p; set *p = 1; }",
894
        "fn f 'r (p: &'r mut u32) { { let q = &mut *p; set *q = 1; } set *p = 2; }",
895
        "fn f 'r (p: &'r mut u32) { { let q = &*p; } set *p = 2; }",
896
        "unsafe fn f 'r (p: &'r mut u32) { { let q = &*p; } set *p = 2; }",
897
        "fn f 'r (p: &'r mut u32) { { let q = &mut *p; let moved = q; } *p; }",
898
        "record P { a: u32, b: u32 } fn f 'r (p: &'r mut P) { { let q = &mut p.a; } p.a; }",
899
        "record P { a: u32, b: u32 } fn f 'r (p: &'r mut P) { { let q = &p.a; } set p.a = 2; }",
900
    ] {
901
        let mut testArena30 = super::testArena();
902
        let testStorage30: 'test30 = &mut testArena30 in {
903
            let mut res = super::testResolver(testStorage30);
904
            let result = try super::resolveProgramStr(&mut res, program);
905
            let error = try super::expectError(&result);
906
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
907
        }
908
    }
909
}
910
911
/// A regional loan on any live branch remains active at the branch join.
912
@test unsafe fn testRegionalProjectionBranchJoin() throws (testing::TestError) {
913
    for program in [
914
        "fn f 'r (p: &'r mut u32, c: bool) { if c { let q = &mut *p; } set *p = 2; }",
915
        "fn f 'r (p: &'r mut u32, c: bool) { if c {} else { let q = &*p; } set *p = 2; }",
916
        "fn f 'r (p: &'r mut u32, c: bool) { match c { case true => { let q = &mut *p; } else => {} } *p; }",
917
        "fn f 'r (p: &'r mut u32, c: ?u32) { if let n = c { let q = &*p; } set *p = 2; }",
918
    ] {
919
        let mut testArena31 = super::testArena();
920
        let testStorage31: 'test31 = &mut testArena31 in {
921
            let mut res = super::testResolver(testStorage31);
922
            let result = try super::resolveProgramStr(&mut res, program);
923
            let error = try super::expectError(&result);
924
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
925
        }
926
    }
927
}
928
929
/// Loop back edges carry regional loans into later iterations.
930
@test unsafe fn testRegionalProjectionLoopBackEdge() throws (testing::TestError) {
931
    for program in [
932
        "fn f 'r (p: &'r mut u32) { for i in 0..2 { let q = &mut *p; } }",
933
        "fn f 'r (p: &'r mut u32) { for i in 0..2 { set *p = 1; let q = &*p; } }",
934
        "fn f 'r (p: &'r mut u32) { for i in 0..2 { set *p = 1; let q = &*p; continue; } }",
935
        "fn f 'r (p: &'r mut u32, c: bool) { while c { let q = &mut *p; } }",
936
        "fn f 'r (p: &'r mut u32, c: ?u32) { while let n = c { let q = &mut *p; } }",
937
        "fn f 'r (p: &'r mut u32) { loop { let q = &mut *p; } }",
938
        "fn f 'r (p: &'r mut u32, c: bool) { loop { if c { set *p = 1; break; } let q = &*p; } }",
939
    ] {
940
        let mut testArena32 = super::testArena();
941
        let testStorage32: 'test32 = &mut testArena32 in {
942
            let mut res = super::testResolver(testStorage32);
943
            let result = try super::resolveProgramStr(&mut res, program);
944
            let error = try super::expectError(&result);
945
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
946
        }
947
    }
948
}
949
950
/// Loans in caller-supplied regions survive loop and nested-region exits.
951
@test unsafe fn testRegionalProjectionLoopExit() throws (testing::TestError) {
952
    for program in [
953
        "fn f 'r (p: &'r mut u32) { loop { let q = &mut *p; break; } set *p = 2; }",
954
        "fn f 'r (p: &'r mut u32, c: bool) { while c { let q = &*p; break; } else {} set *p = 2; }",
955
        "fn f 'r (p: &'r mut u32) { for i in 0..2 { let q = &*p; break; } else {} set *p = 2; }",
956
        "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; }",
957
    ] {
958
        let mut testArena33 = super::testArena();
959
        let testStorage33: 'test33 = &mut testArena33 in {
960
            let mut res = super::testResolver(testStorage33);
961
            let result = try super::resolveProgramStr(&mut res, program);
962
            let error = try super::expectError(&result);
963
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
964
        }
965
    }
966
}
967
968
/// Region erasure cannot merge distinct error alternatives in one signature.
969
@test unsafe fn testRegionalErrorAmbiguity() throws (testing::TestError) {
970
    for program in [
971
        "record E: 'r + Copy {} fn f 'a 'b () throws (E 'a, E 'b) {}",
972
        "record E: 'r + Copy {} unsafe fn f 'a 'b () throws (E 'a, E 'b) {}",
973
        "record E: 'r + Copy {} record Callback: 'a + 'b { f: fn() throws (E 'a, E 'b) }",
974
        "fn f 'a 'b () throws (&'a u32, &'b u32) {}",
975
    ] {
976
        let mut testArena34 = super::testArena();
977
        let testStorage34: 'test34 = &mut testArena34 in {
978
            let mut res = super::testResolver(testStorage34);
979
            let result = try super::resolveProgramStr(&mut res, program);
980
            try super::expectErrorKind(&result, resolver::ErrorKind::AmbiguousRegionalError);
981
        }
982
    }
983
}
984
985
/// Moving an exclusive reference into an aggregate transfers its ownership.
986
@test unsafe fn testRegionalAggregateMove() throws (testing::TestError) {
987
    for program in [
988
        "record W: 'r { p: &'r mut u32 } fn f 'r (p: &'r mut u32) { let w = W 'r { p }; set *p = 1; }",
989
        "record W: 'r { p: &'r mut u32 } unsafe fn f 'r (p: &'r mut u32) { let w = W 'r { p }; set *p = 1; }",
990
        "record W: 'r { p: &'r mut u32 } fn f 'r (w: W 'r) { let case W { p } = w else panic; let again = w; }",
991
        "union W: 'r { P { p: &'r mut u32 } } fn f 'r (p: &'r mut u32) { let w = W 'r::P { p }; set *p = 1; }",
992
        "fn f 'r (p: &'r mut u32) { let a: [&'r mut u32; 1] = [p]; set *p = 1; }",
993
        "fn f 'r (p: &'r mut u32) { let a: ?&'r mut u32 = p; set *p = 1; }",
994
    ] {
995
        let mut testArena35 = super::testArena();
996
        let testStorage35: 'test35 = &mut testArena35 in {
997
            let mut res = super::testResolver(testStorage35);
998
            let result = try super::resolveProgramStr(&mut res, program);
999
            let error = try super::expectError(&result);
1000
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
1001
        }
1002
    }
1003
}
1004
1005
/// Aggregate transfers do not end a projection loan on its source.
1006
@test unsafe fn testRegionalAggregateLoan() throws (testing::TestError) {
1007
    for program in [
1008
        "record W: 'r { p: &'r mut u32 } fn f 'r (p: &'r mut u32) { { let w = W 'r { p: &mut *p }; } set *p = 1; }",
1009
        "record R: 'r + Copy { p: &'r u32 } fn f 'r (p: &'r mut u32) { { let r = R 'r { p: &*p }; } set *p = 1; }",
1010
        "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; }",
1011
        "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; }",
1012
    ] {
1013
        let mut testArena36 = super::testArena();
1014
        let testStorage36: 'test36 = &mut testArena36 in {
1015
            let mut res = super::testResolver(testStorage36);
1016
            let result = try super::resolveProgramStr(&mut res, program);
1017
            let error = try super::expectError(&result);
1018
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1019
        }
1020
    }
1021
}
1022
1023
/// Local storage cannot acquire a caller region through returns or aggregate hints.
1024
@test unsafe fn testRegionalStorageEscape() throws (testing::TestError) {
1025
    for program in [
1026
        "fn f 'r () -> &'r u32 { let x: u32 = 1; return &x; }",
1027
        "unsafe fn f 'r () -> &'r u32 { let x: u32 = 1; return &x; }",
1028
        "record R: 'r + Copy { p: &'r u32 } fn f 'r () -> R 'r { let x: u32 = 1; return R 'r { p: &x }; }",
1029
        "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 }; } }",
1030
        "record R: 'r + Copy { p: &'r u32 } fn f 'r (p: &'r u32) -> &'r R 'r { let r = R 'r { p }; return &r; }",
1031
        "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 }; } }",
1032
    ] {
1033
        let mut testArena37 = super::testArena();
1034
        let testStorage37: 'test37 = &mut testArena37 in {
1035
            let mut res = super::testResolver(testStorage37);
1036
            let result = try super::resolveProgramStr(&mut res, program);
1037
            let error = try super::expectError(&result);
1038
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1039
        }
1040
    }
1041
}
1042
1043
/// Reference fields retain their ownership and storage restrictions.
1044
@test unsafe fn testRegionalFieldRestrictions() throws (testing::TestError) {
1045
    {
1046
        let mut testArena38 = super::testArena();
1047
        let testStorage38: 'test38 = &mut testArena38 in {
1048
            let mut res = super::testResolver(testStorage38);
1049
            let result = try super::resolveProgramStr(&mut res, "record W: 'r { p: &'r mut u32 } fn f 'r (w: W 'r) { let p = w.p; }");
1050
            try super::expectErrorKind(&result, resolver::ErrorKind::LinearPartialMove);
1051
        }
1052
    }
1053
    {
1054
        let mut testArena39 = super::testArena();
1055
        let testStorage39: 'test39 = &mut testArena39 in {
1056
            let mut res = super::testResolver(testStorage39);
1057
            let result = try super::resolveProgramStr(&mut res, "record R: 'r { p: &u32 }");
1058
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition);
1059
        }
1060
    }
1061
    {
1062
        let mut testArena40 = super::testArena();
1063
        let testStorage40: 'test40 = &mut testArena40 in {
1064
            let mut res = super::testResolver(testStorage40);
1065
            let result = try super::resolveProgramStr(&mut res, "fn f 'r (p: &'r u32) { static r: &'r u32 = undefined; }");
1066
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition);
1067
        }
1068
    }
1069
}
1070
1071
/// Call tracking includes all explicit arguments and the implicit receiver.
1072
@test unsafe fn testCallLoanScratchCapacity() throws (testing::TestError) {
1073
    let mut arena = super::testArena();
1074
    let storage: 'test = &mut arena in {
1075
        let mut res = super::testResolver(storage);
1076
        let result = try super::resolveProgramStr(&mut res,
1077
            "record R: Copy { value: u32 } fn (r: &mut R) take(a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: &mut u32) {} fn run() { let mut r = R { value: 0 }; let mut other: u32 = 0; r.take(0, 0, 0, 0, 0, 0, 0, &mut other); set r.value = 1; set other = 2; }"
1078
        );
1079
        try super::expectNoErrors(&result);
1080
    }
1081
    for program in [
1082
        "record R: Copy { value: u32 } fn (r: &mut R) take(a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: &mut u32) {} fn run() { let mut r = R { value: 0 }; r.take(0, 0, 0, 0, 0, 0, 0, &mut r.value); }",
1083
        "fn take(a: &mut u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: &mut u32) {} fn run() { let mut value: u32 = 0; take(&mut value, 0, 0, 0, 0, 0, 0, &mut value); }",
1084
    ] {
1085
        let mut errorArena = super::testArena();
1086
        let errorStorage: 'error = &mut errorArena in {
1087
            let mut res = super::testResolver(errorStorage);
1088
            let result = try super::resolveProgramStr(&mut res, program);
1089
            let error = try super::expectError(&result);
1090
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1091
        }
1092
    }
1093
}
1094
1095
/// Loan compaction preserves outer-region conflicts after child slots expire.
1096
@test unsafe fn testRegionalLoanCompactionConflict() throws (testing::TestError) {
1097
    for program in [
1098
        "fn f 'r (p: &'r mut u32) { let value: u32 = 0; let child: 'child = &value where 'r: 'child in { let local = &*child; let retained = &*p; } set *p = 1; }",
1099
        "fn f 'r (p: &'r mut u32) { let value: u32 = 0; loop { let child: 'child = &value where 'r: 'child in { let local = &*child; let retained = &*p; } break; } set *p = 1; }",
1100
    ] {
1101
        let mut arena = super::testArena();
1102
        let storage: 'test = &mut arena in {
1103
            let mut res = super::testResolver(storage);
1104
            let result = try super::resolveProgramStr(&mut res, program);
1105
            let error = try super::expectError(&result);
1106
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1107
        }
1108
    }
1109
}
1110
1111
/// Regional projection tracking limits simultaneous live projections.
1112
@test unsafe fn testRegionalLoanCapacity() throws (testing::TestError) {
1113
    let mut reuseArena = super::testArena();
1114
    let reuseStorage: 'reuse = &mut reuseArena in {
1115
        let mut res = super::testResolver(reuseStorage);
1116
        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; } } }");
1117
        try super::expectNoErrors(&result);
1118
    }
1119
    let mut testArena41 = super::testArena();
1120
    let testStorage41: 'test41 = &mut testArena41 in {
1121
        let mut res = super::testResolver(testStorage41);
1122
        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]; }");
1123
        try super::expectErrorKind(&result, resolver::ErrorKind::RegionalLoanOverflow);
1124
    }
1125
}
1126
1127
/// Shared regional parameters consume exclusive arguments that can be retained.
1128
@test unsafe fn testRegionalSharedCallTransfer() throws (testing::TestError) {
1129
    for program in [
1130
        "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; }",
1131
        "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; }",
1132
        "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; }",
1133
        "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; }",
1134
    ] {
1135
        let mut testArena42 = super::testArena();
1136
        let testStorage42: 'test42 = &mut testArena42 in {
1137
            let mut res = super::testResolver(testStorage42);
1138
            let result = try super::resolveProgramStr(&mut res, program);
1139
            let error = try super::expectError(&result);
1140
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
1141
        }
1142
    }
1143
}
1144
1145
/// Values stored in a regional destination must cover its full lifetime.
1146
@test unsafe fn testRegionalStoreLifetime() throws (testing::TestError) {
1147
    for program in [
1148
        "fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) { set *dst = p; }",
1149
        "unsafe fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) { set *dst = p; }",
1150
        "fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) where 'a: 'b { set *dst = p; }",
1151
        "record R: 'r + Copy { p: &'r u32 } fn f 'a 'b (dst: &'a mut R 'b, p: &'b u32) { set *dst = R 'b { p }; }",
1152
        "fn f 'a 'b (dst: &'a mut [&'b u32], p: &'b u32) { set dst[0] = p; }",
1153
        "fn f 'a 'b (dst: &'a mut [&'b u32], p: &'b u32) { set dst[..] = p; }",
1154
        "fn f 'a 'b (dst: &'a mut fn(&'b u32), callback: fn(&'b u32)) { set *dst = callback; }",
1155
    ] {
1156
        let mut testArena43 = super::testArena();
1157
        let testStorage43: 'test43 = &mut testArena43 in {
1158
            let mut res = super::testResolver(testStorage43);
1159
            let result = try super::resolveProgramStr(&mut res, program);
1160
            let error = try super::expectError(&result);
1161
            let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed;
1162
        }
1163
    }
1164
}
1165
1166
/// A session holds the arena loan after the interface is moved or discarded.
1167
@test unsafe fn testSessionArenaLoan() throws (testing::TestError) {
1168
    for program in [
1169
        "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { alloc::reset(arena); } }",
1170
        "use std::lang::alloc; unsafe fn f(arena: &mut alloc::Arena) { use *arena as s in { alloc::reset(arena); } }",
1171
        "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { let moved = s; alloc::reset(arena); } }",
1172
        "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { let _ = s; set arena.offset = 0; } }",
1173
        "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { use *arena as t in {} } }",
1174
    ] {
1175
        let mut testArena44 = super::testArena();
1176
        let testStorage44: 'test44 = &mut testArena44 in {
1177
            let mut res = super::testResolver(testStorage44);
1178
            let result = try super::resolveSessionProgramStr(&mut res, program);
1179
            let error = try super::expectError(&result);
1180
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1181
        }
1182
    }
1183
}
1184
1185
/// Session interfaces have affine ownership and invariant region arguments.
1186
@test unsafe fn testSessionOwnership() throws (testing::TestError) {
1187
    for program in [
1188
        "fn f 'r (s: Session 'r) { let moved = s; let again = s; }",
1189
        "unsafe fn f 'r (s: Session 'r) { let moved = s; let again = s; }",
1190
        "fn take 'r (s: Session 'r) {} fn f 'r (s: Session 'r) { take(s); take(s); }",
1191
    ] {
1192
        let mut testArena45 = super::testArena();
1193
        let testStorage45: 'test45 = &mut testArena45 in {
1194
            let mut res = super::testResolver(testStorage45);
1195
            let result = try super::resolveProgramStr(&mut res, program);
1196
            let error = try super::expectError(&result);
1197
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
1198
        }
1199
    }
1200
    {
1201
        let mut testArena46 = super::testArena();
1202
        let testStorage46: 'test46 = &mut testArena46 in {
1203
            let mut res = super::testResolver(testStorage46);
1204
            let result = try super::resolveProgramStr(&mut res,
1205
                "fn f 'r 's (s: Session 's) -> Session 'r where 'r: 's { return s; }");
1206
            let error = try super::expectError(&result);
1207
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1208
        }
1209
    }
1210
}
1211
1212
/// Regional `use` blocks require a mutable allocation trait implementer.
1213
@test unsafe fn testSessionSource() throws (testing::TestError) {
1214
    for program in [
1215
        "record Arena { data: *mut [u8], offset: u32 } fn f(arena: &mut Arena) { use *arena as s in {} }",
1216
        "fn f(value: &mut u32) { use *value as s in {} }",
1217
    ] {
1218
        let mut testArena47 = super::testArena();
1219
        let testStorage47: 'test47 = &mut testArena47 in {
1220
            let mut res = super::testResolver(testStorage47);
1221
            let result = try super::resolveSessionProgramStr(&mut res, program);
1222
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidSessionSource);
1223
        }
1224
    }
1225
    let mut customArena = super::testArena();
1226
    let customStorage: 'custom = &mut customArena in {
1227
        let mut res = super::testResolver(customStorage);
1228
        let result = try super::resolveSessionProgramStr(&mut res,
1229
            "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); } }");
1230
        try super::expectNoErrors(&result);
1231
    }
1232
}
1233
1234
/// Region-dependent values cannot be manufactured from uninitialized storage.
1235
@test unsafe fn testRegionalUndefined() throws (testing::TestError) {
1236
    for program in [
1237
        "unsafe fn f 'r () -> Session 'r { return undefined; }",
1238
        "record R: 'r { s: Session 'r } unsafe fn f 'r () -> R 'r { return undefined; }",
1239
        "unsafe fn f 'r () -> *unsafe Session 'r { return undefined; }",
1240
        "unsafe fn f 'r () -> &'r u32 { return undefined; }",
1241
    ] {
1242
        let mut testArena48 = super::testArena();
1243
        let testStorage48: 'test48 = &mut testArena48 in {
1244
            let mut res = super::testResolver(testStorage48);
1245
            let result = try super::resolveProgramStr(&mut res, program);
1246
            let error = try super::expectError(&result);
1247
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1248
        }
1249
    }
1250
}
1251
1252
/// Pointer casts cannot introduce session or aggregate region dependencies.
1253
@test unsafe fn testRegionalCastForgery() throws (testing::TestError) {
1254
    for program in [
1255
        "unsafe fn f 'r (p: *unsafe opaque) -> *unsafe Session 'r { return p as *unsafe Session 'r; }",
1256
        "unsafe fn f 'r (p: *unsafe [opaque]) -> *unsafe [Session 'r] { return p as *unsafe [Session 'r]; }",
1257
        "record R: 'r { s: Session 'r } unsafe fn f 'r (p: *unsafe opaque) -> *unsafe R 'r { return p as *unsafe R 'r; }",
1258
        "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; }",
1259
    ] {
1260
        let mut testArena49 = super::testArena();
1261
        let testStorage49: 'test49 = &mut testArena49 in {
1262
            let mut res = super::testResolver(testStorage49);
1263
            let result = try super::resolveProgramStr(&mut res, program);
1264
            let error = try super::expectError(&result);
1265
            let case resolver::ErrorKind::InvalidAsCast(_) = error.kind else throw testing::TestError::Failed;
1266
        }
1267
    }
1268
}
1269
1270
/// Bulk allocation rejects resources and values that need ownership cleanup.
1271
@test unsafe fn testSessionAllocationValue() throws (testing::TestError) {
1272
    for program in [
1273
        "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1274
        "record R: Once { n: u32 } unsafe fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1275
        "record R: Once { n: u32 } record Outer { value: R } fn f 'r (s: &Session 'r, value: Outer) { try! s.new(value); }",
1276
        "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: ?R) { try! s.new(value); }",
1277
        "fn f 'r (s: &Session 'r, value: Session 'r) { try! s.new(value); }",
1278
        "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: [R; 1]) { try! s.new(value); }",
1279
        "fn f 'r (s: &Session 'r, value: &'r mut u32) { try! s.fill(value, 2); }",
1280
        "fn f 'r (s: &Session 'r, value: &[&'r mut u32]) { try! s.copy(value); }",
1281
    ] {
1282
        let mut testArena50 = super::testArena();
1283
        let testStorage50: 'test50 = &mut testArena50 in {
1284
            let mut res = super::testResolver(testStorage50);
1285
            let result = try super::resolveSessionProgramStr(&mut res, program);
1286
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidAllocationValue);
1287
        }
1288
    }
1289
}
1290
1291
/// Allocated values must retain dependencies that cover the destination session.
1292
@test unsafe fn testSessionAllocationDependency() throws (testing::TestError) {
1293
    for program in [
1294
        "fn f 'r 's (a: &Session 'r, p: &'s u32) where 'r: 's { try! a.new(p); }",
1295
        "unsafe fn f 'r 's (a: &Session 'r, p: &'s u32) where 'r: 's { try! a.new(p); }",
1296
        "record R: 's + Copy { p: &'s u32 } fn f 'r 's (a: &Session 'r, p: R 's) where 'r: 's { try! a.new(p); }",
1297
        "fn f 'r 's (a: &Session 'r, p: &[&'s u32]) where 'r: 's { try! a.copy(p); }",
1298
    ] {
1299
        let mut testArena51 = super::testArena();
1300
        let testStorage51: 'test51 = &mut testArena51 in {
1301
            let mut res = super::testResolver(testStorage51);
1302
            let result = try super::resolveSessionProgramStr(&mut res, program);
1303
            let error = try super::expectError(&result);
1304
            let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed;
1305
        }
1306
    }
1307
}
1308
1309
/// Allocation operations require error handling and exact source region results.
1310
@test unsafe fn testSessionAllocationContract() throws (testing::TestError) {
1311
    {
1312
        let mut testArena52 = super::testArena();
1313
        let testStorage52: 'test52 = &mut testArena52 in {
1314
            let mut res = super::testResolver(testStorage52);
1315
            let result = try super::resolveSessionProgramStr(&mut res,
1316
                "fn f 'r (s: &Session 'r) { s.new(1 as u32); }");
1317
            try super::expectErrorKind(&result, resolver::ErrorKind::MissingTry);
1318
        }
1319
    }
1320
    {
1321
        let mut testArena53 = super::testArena();
1322
        let testStorage53: 'test53 = &mut testArena53 in {
1323
            let mut res = super::testResolver(testStorage53);
1324
            let result = try super::resolveSessionProgramStr(&mut res,
1325
                "fn f 'r 's (a: &Session 'r) -> &'s mut u32 { return try! a.new(1 as u32); }");
1326
            let error = try super::expectError(&result);
1327
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1328
        }
1329
    }
1330
    {
1331
        let mut testArena54 = super::testArena();
1332
        let testStorage54: 'test54 = &mut testArena54 in {
1333
            let mut res = super::testResolver(testStorage54);
1334
            let result = try super::resolveSessionProgramStr(&mut res,
1335
                "fn f 'r (a: &Session 'r, p: &u32) { try! a.new(p); }");
1336
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition);
1337
        }
1338
    }
1339
}
1340
1341
/// Typed reservations reject array products, aggregate sums, and field-offset overflow.
1342
@test unsafe fn testSessionAllocationLayout() throws (testing::TestError) {
1343
    for program in [
1344
        "fn f 'r (s: &Session 'r, value: [u64; 536870913]) { try! s.new(value); }",
1345
        "unsafe fn f 'r (s: &Session 'r, value: [u64; 536870913]) { try! s.new(value); }",
1346
        "record R { a: [u8; 4294967290], b: u64 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1347
        "record R { a: [u8; 2147483648], b: u8 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1348
        "fn f 'r (s: &Session 'r, value: ?[u8; 4294967295]) { try! s.new(value); }",
1349
        "union R { Data([u8; 4294967295]) } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1350
    ] {
1351
        let mut testArena55 = super::testArena();
1352
        let testStorage55: 'test55 = &mut testArena55 in {
1353
            let mut res = super::testResolver(testStorage55);
1354
            let result = try super::resolveSessionProgramStr(&mut res, program);
1355
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidAllocationLayout);
1356
        }
1357
    }
1358
}
1359
1360
/// Cell payloads must permit plain value copies.
1361
@test unsafe fn testCellPointerPayload() throws (testing::TestError) {
1362
    for program in [
1363
        "union State: 'r { Next(&'r cell State 'r) }",
1364
        "union State: 'r { Ready(&'r u32) } fn f 'r (state: &'r cell State 'r) {}",
1365
        "union State: 'r { Ready(&'r u32) } unsafe fn f 'r (state: &'r cell State 'r) {}",
1366
        "fn f(p: *cell *mut u32) {}",
1367
        "unsafe fn f(p: *cell *mut u32) {}",
1368
        "record R: Once { n: u32 } fn f(p: *cell R) {}",
1369
        "record R { n: u32 } fn f(p: *cell R) {}",
1370
        "fn f 'r (p: &'r cell &'r mut u32) {}",
1371
    ] {
1372
        let mut testArena56 = super::testArena();
1373
        let testStorage56: 'test56 = &mut testArena56 in {
1374
            let mut res = super::testResolver(testStorage56);
1375
            let result = try super::resolveProgramStr(&mut res, program);
1376
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload);
1377
        }
1378
    }
1379
}
1380
1381
/// Direct cell borrows support Copy values, scoped loans, and call arguments.
1382
@test unsafe fn testCellBorrow() throws (testing::TestError) {
1383
    for program in [
1384
        "fn f() -> u32 { let mut n: u32 = 0; { let c = &cell n; let alias = c; set *c = 1; set *alias += 1; } return n; }",
1385
        "fn read(c: &cell u32) { set *c = 1; } fn f(p: &mut u32) { read(&cell *p); set *p = 2; }",
1386
        "fn f() { let mut n: u32 = 0; let c: 'r = &cell n in { let alias = c; set *alias = 1; } set n = 2; }",
1387
        "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; }",
1388
        "fn f() { let mut a: [u32; 2] = [0, 0]; let c = &cell a; set *c = [1, 2]; let snapshot = *c; }",
1389
        "fn forward(p: *mut u32) -> *mut u32 { return p; } fn f(p: *mut u32) -> *cell u32 { return &cell *forward(p); }",
1390
        "record R: Copy { n: u32 } fn f(p: *mut R) -> *cell u32 { return &cell p.n; }",
1391
        "fn f(p: *mut [u32]) -> *cell u32 { return &cell p[0]; }",
1392
    ] {
1393
        let mut arena = super::testArena();
1394
        let storage: 'test = &mut arena in {
1395
            let mut res = super::testResolver(storage);
1396
            let result = try super::resolveProgramStr(&mut res, program);
1397
            try super::expectNoErrors(&result);
1398
        }
1399
    }
1400
}
1401
1402
/// Cell creation requires exclusive access for the full borrow duration.
1403
@test unsafe fn testCellBorrowConflicts() throws (testing::TestError) {
1404
    for program in [
1405
        "fn f() { let mut n: u32 = 0; let c = &cell n; let r = &n; }",
1406
        "unsafe fn f() { let mut n: u32 = 0; let c = &cell n; let r = &n; }",
1407
        "fn f() { let mut n: u32 = 0; let r = &n; let c = &cell n; }",
1408
        "fn f() { let mut n: u32 = 0; let c = &cell n; set n = 1; }",
1409
        "fn f() { let mut n: u32 = 0; let c = &cell n; let other = &cell n; }",
1410
        "fn f() { let mut n: u32 = 0; let c = &cell n as &cell u32; let r = &n; }",
1411
        "fn inspect(c: &cell u32, r: &u32) {} fn f() { let mut n: u32 = 0; inspect(&cell n, &n); }",
1412
        "fn inspect(r: &u32, c: &cell u32) {} fn f() { let mut n: u32 = 0; inspect(&n, &cell n); }",
1413
    ] {
1414
        let mut arena = super::testArena();
1415
        let storage: 'test = &mut arena in {
1416
            let mut res = super::testResolver(storage);
1417
            let result = try super::resolveProgramStr(&mut res, program);
1418
            let error = try super::expectError(&result);
1419
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1420
        }
1421
    }
1422
}
1423
1424
/// Cell creation rejects immutable places and non-Copy payloads.
1425
@test unsafe fn testCellBorrowPayload() throws (testing::TestError) {
1426
    for program in [
1427
        "fn f() { let n: u32 = 0; let c = &cell n; }",
1428
        "fn f(p: &u32) { let c = &cell *p; }",
1429
        "unsafe fn f(p: &u32) { let c = &cell *p; }",
1430
    ] {
1431
        let mut arena = super::testArena();
1432
        let storage: 'test = &mut arena in {
1433
            let mut res = super::testResolver(storage);
1434
            let result = try super::resolveProgramStr(&mut res, program);
1435
            try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding);
1436
        }
1437
    }
1438
    for program in [
1439
        "record R { n: u32 } fn f() { let mut r = R { n: 0 }; let c = &cell r; }",
1440
        "fn f(p: &mut *mut u32) { let c = &cell *p; }",
1441
        "fn f(p: &mut [u32]) { let c = &cell p[..]; }",
1442
    ] {
1443
        let mut arena = super::testArena();
1444
        let storage: 'test = &mut arena in {
1445
            let mut res = super::testResolver(storage);
1446
            let result = try super::resolveProgramStr(&mut res, program);
1447
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload);
1448
        }
1449
    }
1450
}
1451
1452
/// Cell access cannot expose payload references or restore exclusive pointers.
1453
@test unsafe fn testCellPointerAccess() throws (testing::TestError) {
1454
    for program in [
1455
        "fn f(p: *cell u32) { let r = &*p; }",
1456
        "unsafe fn f(p: *cell u32) { let r = &*p; }",
1457
        "record R: Copy { n: u32 } fn f(p: *cell R) { let r = &(*p).n; }",
1458
        "fn f(p: *cell [u32; 2]) { let r = &(*p)[0]; }",
1459
        "record R: Copy { n: u32 } fn f(p: *cell R) { set (*p).n = 1; }",
1460
        "fn f(p: *cell [u32; 2]) { set (*p)[0] = 1; }",
1461
    ] {
1462
        let mut testArena57 = super::testArena();
1463
        let testStorage57: 'test57 = &mut testArena57 in {
1464
            let mut res = super::testResolver(testStorage57);
1465
            let result = try super::resolveProgramStr(&mut res, program);
1466
            try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding);
1467
        }
1468
    }
1469
    for program in [
1470
        "fn f(p: *cell u32) -> *mut u32 { return p as *mut u32; }",
1471
        "unsafe fn f(p: *cell u32) -> *unsafe mut u32 { return p as *unsafe mut u32; }",
1472
        "fn f(p: *u32) -> *cell u32 { return p as *cell u32; }",
1473
        "unsafe fn f(p: *unsafe mut u32) -> *cell u32 { return p as *cell u32; }",
1474
        "fn f(p: *mut u64) -> *cell u32 { return p as *cell u32; }",
1475
        "fn f 'r (p: &'r mut u32) -> *cell u32 { return p as *cell u32; }",
1476
    ] {
1477
        let mut testArena58 = super::testArena();
1478
        let testStorage58: 'test58 = &mut testArena58 in {
1479
            let mut res = super::testResolver(testStorage58);
1480
            let result = try super::resolveProgramStr(&mut res, program);
1481
            let error = try super::expectError(&result);
1482
            let case resolver::ErrorKind::InvalidAsCast(_) = error.kind else throw testing::TestError::Failed;
1483
        }
1484
    }
1485
}
1486
1487
/// An exclusive payload borrow cannot be made from shared cell access.
1488
@test unsafe fn testCellPointerMutablePayload() throws (testing::TestError) {
1489
    let mut testArena59 = super::testArena();
1490
    let testStorage59: 'test59 = &mut testArena59 in {
1491
        let mut res = super::testResolver(testStorage59);
1492
        let result = try super::resolveProgramStr(&mut res,
1493
            "fn f(p: *cell u32) { let r = &mut *p; }");
1494
        try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding);
1495
    }
1496
}
1497
1498
/// Cell conversion consumes exclusive access, including call arguments.
1499
@test unsafe fn testCellPointerOwnership() throws (testing::TestError) {
1500
    for program in [
1501
        "fn f(p: *mut u32) { let c = &cell *p; set *p = 1; }",
1502
        "unsafe fn f(p: *mut u32) { let c = &cell *p; set *p = 1; }",
1503
        "record R: Copy { n: u32 } fn f(p: *mut R) { let c = &cell p.n; set p.n = 1; }",
1504
        "fn f(p: *mut [u32]) { let c = &cell p[0]; set p[0] = 1; }",
1505
        "fn f(p: *mut u32) { let c = p as *cell u32; set *p = 1; }",
1506
        "unsafe fn f(p: *mut u32) { let c = p as *cell u32; set *p = 1; }",
1507
        "fn read(p: &cell u32) {} fn f(p: &mut u32) { read(p as &cell u32); set *p = 1; }",
1508
    ] {
1509
        let mut testArena60 = super::testArena();
1510
        let testStorage60: 'test60 = &mut testArena60 in {
1511
            let mut res = super::testResolver(testStorage60);
1512
            let result = try super::resolveProgramStr(&mut res, program);
1513
            let error = try super::expectError(&result);
1514
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
1515
        }
1516
    }
1517
    for program in [
1518
        "fn f() { let mut n: u32 = 0; let c = &mut n as &cell u32; let r = &n; set *c = 1; }",
1519
        "unsafe fn f() { let mut n: u32 = 0; let c = &mut n as &cell u32; let r = &n; set *c = 1; }",
1520
    ] {
1521
        let mut testArena61 = super::testArena();
1522
        let testStorage61: 'test61 = &mut testArena61 in {
1523
            let mut res = super::testResolver(testStorage61);
1524
            let result = try super::resolveProgramStr(&mut res, program);
1525
            let error = try super::expectError(&result);
1526
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1527
        }
1528
    }
1529
}
1530
1531
/// Cell writes preserve exact payload regions and destination lifetimes.
1532
@test unsafe fn testCellPointerRegion() throws (testing::TestError) {
1533
    for program in [
1534
        "fn f 'r 's (p: &'r cell &'r u32, value: &'s u32) { set *p = value; }",
1535
        "unsafe fn f 'r 's (p: &'r cell &'r u32, value: &'s u32) { set *p = value; }",
1536
        "fn f 'r 's (p: &'r cell u32) -> &'s cell u32 { return p; }",
1537
    ] {
1538
        let mut testArena62 = super::testArena();
1539
        let testStorage62: 'test62 = &mut testArena62 in {
1540
            let mut res = super::testResolver(testStorage62);
1541
            let result = try super::resolveProgramStr(&mut res, program);
1542
            let error = try super::expectError(&result);
1543
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1544
        }
1545
    }
1546
    for program in [
1547
        "fn f 'r 's (p: &'r cell &'s u32, value: &'s u32) where 'r: 's { set *p = value; }",
1548
        "unsafe fn f 'r 's (p: &'r cell &'s u32, value: &'s u32) where 'r: 's { set *p = value; }",
1549
    ] {
1550
        let mut testArena63 = super::testArena();
1551
        let testStorage63: 'test63 = &mut testArena63 in {
1552
            let mut res = super::testResolver(testStorage63);
1553
            let result = try super::resolveProgramStr(&mut res, program);
1554
            let error = try super::expectError(&result);
1555
            let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed;
1556
        }
1557
    }
1558
}
1559
1560
/// Raw cell operations require an unsafe execution context.
1561
@test unsafe fn testCellPointerRawAccess() throws (testing::TestError) {
1562
    for program in [
1563
        "fn f(p: *unsafe cell u32) -> u32 { return *p; }",
1564
        "fn f(p: *unsafe cell u32) { set *p = 1; }",
1565
        "fn f(p: &*unsafe cell u32) { set **p = 1; }",
1566
    ] {
1567
        let mut testArena64 = super::testArena();
1568
        let testStorage64: 'test64 = &mut testArena64 in {
1569
            let mut res = super::testResolver(testStorage64);
1570
            let result = try super::resolveProgramStr(&mut res, program);
1571
            try super::expectErrorKind(&result, resolver::ErrorKind::UnsafeOperation);
1572
        }
1573
    }
1574
}
1575
1576
/// A checked buffer context cannot be copied while its exclusive storage is live.
1577
@test unsafe fn testCheckedBufferOwnership() throws (testing::TestError) {
1578
    for program in [
1579
        "record Buffer: 'r { words: &'r mut [u32] } fn observe 'r (b: &Buffer 'r) {} fn f 'r (b: Buffer 'r) { let moved = b; observe(&b); }",
1580
        "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); }",
1581
    ] {
1582
        let mut testArena65 = super::testArena();
1583
        let testStorage65: 'test65 = &mut testArena65 in {
1584
            let mut res = super::testResolver(testStorage65);
1585
            let result = try super::resolveProgramStr(&mut res, program);
1586
            let error = try super::expectError(&result);
1587
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
1588
        }
1589
    }
1590
}
1591
1592
/// An iterator's stored shared borrow excludes writes through the buffer owner.
1593
@test unsafe fn testCheckedIteratorLoan() throws (testing::TestError) {
1594
    for program in [
1595
        "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; } }",
1596
        "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; } }",
1597
    ] {
1598
        let mut testArena66 = super::testArena();
1599
        let testStorage66: 'test66 = &mut testArena66 in {
1600
            let mut res = super::testResolver(testStorage66);
1601
            let result = try super::resolveProgramStr(&mut res, program);
1602
            let error = try super::expectError(&result);
1603
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1604
        }
1605
    }
1606
}
1607
1608
/// An inferred raw pointer argument requires an unsafe address operation.
1609
@test unsafe fn testRegionCallRawAddress() throws (testing::TestError) {
1610
    let mut arena = super::testArena();
1611
    let storage: 'arena = &mut arena in {
1612
        let mut res = super::testResolver(storage);
1613
        let result = try super::resolveProgramStr(&mut res,
1614
            "record View: 'r + Copy { value: &'r u32 } fn read 'r (view: *unsafe View 'r) {} fn f 'r (view: View 'r) { read(&view); }");
1615
        try super::expectErrorKind(&result, resolver::ErrorKind::UnsafeOperation);
1616
    }
1617
}
1618
1619
/// Shared aggregate access cannot expose mutable access to an exclusive field.
1620
@test unsafe fn testSharedExclusiveFieldAccess() throws (testing::TestError) {
1621
    for program in [
1622
        "record H: 'r { items: &'r mut [u32] } fn f 'r (h: &H 'r) { set h.items[0] = 42; }",
1623
        "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r (h: &H 'r) { set h.items[0] = 42; }",
1624
        "record H: 'r { items: &'r mut [u32] } fn f 'r (h: &'r H 'r) { let p = &mut h.items[0]; }",
1625
        "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r (h: &'r H 'r) { let p = &mut h.items[0]; }",
1626
        "record H: 'r { items: &'r mut [u32] } fn write(p: &mut [u32]) {} fn f 'r (h: &H 'r) { write(h.items); }",
1627
        "record H: 'r { items: &'r mut [u32] } fn write(p: &mut [u32]) {} unsafe fn f 'r (h: &H 'r) { write(h.items); }",
1628
        "record H: 'r { item: &'r mut u32 } fn f 'r (h: &H 'r) { let p: &mut u32 = h.item; }",
1629
        "record H: 'r { item: &'r mut u32 } unsafe fn f 'r (h: &H 'r) { let p: &mut u32 = h.item; }",
1630
        "record H { item: *mut u32 } fn f(h: &H) { set *h.item = 42; }",
1631
        "record H { item: *mut u32 } unsafe fn f(h: &H) { set *h.item = 42; }",
1632
        "record H: 'r { items: [&'r mut u32; 1] } fn f 'r (h: &H 'r) { set *h.items[0] = 42; }",
1633
        "record H: 'r { items: [&'r mut u32; 1] } unsafe fn f 'r (h: &H 'r) { set *h.items[0] = 42; }",
1634
        "fn f 'r (items: &'r [&'r mut u32]) { set *items[0] = 42; }",
1635
        "unsafe fn f 'r (items: &'r [&'r mut u32]) { set *items[0] = 42; }",
1636
        "fn f 'r (p: &'r &'r mut u32) { set **p = 42; }",
1637
        "unsafe fn f 'r (p: &'r &'r mut u32) { set **p = 42; }",
1638
        "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); }",
1639
        "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); }",
1640
        "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(); }",
1641
        "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(); }",
1642
        "trait W { fn (&mut W) write(); } record H: 'r { object: &'r mut opaque W } fn f 'r (h: &H 'r) { h.object.write(); }",
1643
        "trait W { fn (&mut W) write(); } record H: 'r { object: &'r mut opaque W } unsafe fn f 'r (h: &H 'r) { h.object.write(); }",
1644
    ] {
1645
        let mut arena = super::testArena();
1646
        let storage: 'test = &mut arena in {
1647
            let mut res = super::testResolver(storage);
1648
            let result = try super::resolveProgramStr(&mut res, program);
1649
            try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding);
1650
        }
1651
    }
1652
}
1653
1654
/// A reference through an exclusive field cannot outlive the owner's borrow.
1655
@test unsafe fn testExclusiveOwnerBorrowLifetimes() throws (testing::TestError) {
1656
    for program in [
1657
        "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; }",
1658
        "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; }",
1659
        "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; }",
1660
        "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; }",
1661
        "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; }",
1662
        "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; }",
1663
        "record H: 'r { item: &'r mut u32 } fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &*h.item; }",
1664
        "record H: 'r { item: &'r mut u32 } unsafe fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &*h.item; }",
1665
        "record H: 'r { items: &'r mut [u32] } fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &h.items[0]; }",
1666
        "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]; }",
1667
        "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; }",
1668
        "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; }",
1669
        "record H { item: *mut u32 } fn f(h: &H) -> *u32 { return &*h.item; }",
1670
        "record H { item: *mut u32 } unsafe fn f(h: &H) -> *u32 { return &*h.item; }",
1671
        "record H: 'r { items: &'r mut [u32] } fn f 'r 's (h: &'s H 'r) -> &'r [u32] where 'r: 's { return &h.items[..]; }",
1672
        "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r 's (h: &'s H 'r) -> &'r [u32] where 'r: 's { return &h.items[..]; }",
1673
    ] {
1674
        let mut arena = super::testArena();
1675
        let storage: 'test = &mut arena in {
1676
            let mut res = super::testResolver(storage);
1677
            let result = try super::resolveProgramStr(&mut res, program);
1678
            let error = try super::expectError(&result);
1679
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1680
        }
1681
    }
1682
}
1683
1684
/// A shared binding cannot hide a move from an exclusive field.
1685
@test unsafe fn testSharedBindingPreservesSourceOwnership() throws (testing::TestError) {
1686
    for program in [
1687
        "record H { item: *mut u32 } fn f(h: H) -> *u32 { let p: *u32 = h.item; return p; }",
1688
        "record H { item: ?*mut u32 } fn f(h: H) -> ?*u32 { let p: ?*u32 = h.item; return p; }",
1689
        "record H: 'r { item: &'r mut u32 } fn f 'r (h: &'r H 'r) -> &'r u32 { let p: &'r u32 = h.item; return p; }",
1690
        "record H { item: *mut u32 } unsafe fn f(h: H) -> *u32 { let p: *u32 = h.item; return p; }",
1691
        "record H { item: ?*mut u32 } unsafe fn f(h: H) -> ?*u32 { let p: ?*u32 = h.item; return p; }",
1692
        "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; }",
1693
    ] {
1694
        let mut arena = super::testArena();
1695
        let storage: 'test = &mut arena in {
1696
            let mut res = super::testResolver(storage);
1697
            let result = try super::resolveProgramStr(&mut res, program);
1698
            try super::expectErrorKind(&result, resolver::ErrorKind::LinearPartialMove);
1699
        }
1700
    }
1701
}
1702
1703
/// Methods and trait instances resolve declaration region parameters.
1704
@test unsafe fn testRegionalMethods() throws (testing::TestError) {
1705
    for program in [
1706
        "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(); }",
1707
        "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); }",
1708
        "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); }",
1709
    ] {
1710
        let mut arena = super::testArena();
1711
        let storage: 'method = &mut arena in {
1712
            let mut res = super::testResolver(storage);
1713
            let result = try super::resolveProgramStr(&mut res, program);
1714
            try super::expectNoErrors(&result);
1715
        }
1716
    }
1717
}