lib/std/lang/resolver/tests/regions.rad 148.1 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
/// Call results resolve regional nominal views before type consumers inspect them.
10
@test unsafe fn testCallResultNominalViews() throws (testing::TestError) {
11
    let programs = [
12
        "union R: 'r + Copy { V(&'r u32), E } record M {} fn (m: *M) get 'r(p: &'r u32) -> R 'r { return R::V(p); } fn f 'r(m: *M, p: &'r u32) { let x = m.get 'r(p); match x { case R::V(v) => {}, case R::E => {} } }",
13
        "union R: 'r + Copy { V(&'r u32), E } trait T { fn (*T) get 'r(p: &'r u32) -> R 'r; } fn f 'r(t: *opaque T, p: &'r u32) { let x = t.get 'r(p); match x { case R::V(v) => {}, case R::E => {} } }",
14
        "union R: 'r + Copy { V(&'r u32), E } fn get 'r(p: &'r u32) -> ?R 'r { return R::V(p); } fn f 'r(p: &'r u32) { let x = get 'r(p); if let v = x { match v { case R::V(y) => {}, case R::E => {} } } }",
15
        "union R: 'r + Copy { V(&'r u32), E } fn get 'r(p: &'r u32) -> [R 'r; 1] { return [R::V(p)]; } fn f 'r(p: &'r u32) { let x = get 'r(p); match x[0] { case R::V(y) => {}, case R::E => {} } }",
16
    ];
17
    for program in programs {
18
        let mut arena = super::testArena();
19
        let storage: 'test = &mut arena in {
20
            let mut res = super::testResolver(storage);
21
            let result = try super::resolveProgramStr(&mut res, program);
22
            try super::expectNoErrors(&result);
23
        }
24
    }
25
}
26
27
/// Optional aggregate payloads start at their required alignment after the tag.
28
@test fn testOptionalPayloadOffsets() throws (testing::TestError) {
29
    for alignment in [1 as u32, 2, 4, 8, 16] {
30
        let layout = resolver::Layout { size: 32, alignment };
31
        assert resolver::getOptionalValOffset(layout) == alignment;
32
    }
33
}
34
35
/// Each declaration has a distinct identity within its resolver.
36
@test unsafe fn testSymbolIdentities() throws (testing::TestError) {
37
    let mut arena = super::testArena();
38
    let storage: 'test = &mut arena in {
39
        let mut res = super::testResolver(storage);
40
        let result = try super::resolveProgramStr(&mut res, "fn f() {} fn g() {}");
41
        try super::expectNoErrors(&result);
42
        let case ast::NodeValue::Block(block) = result.root.value else throw testing::TestError::Failed;
43
        let first = resolver::symbolFor(&res, block.statements[0]) else throw testing::TestError::Failed;
44
        let second = resolver::symbolFor(&res, block.statements[1]) else throw testing::TestError::Failed;
45
        assert first.id <> second.id;
46
        assert first.id < res.symbolCount;
47
        assert second.id < res.symbolCount;
48
        let firstBinding = resolver::nodeData(&res, block.statements[0]).binding else throw testing::TestError::Failed;
49
        let secondBinding = resolver::nodeData(&res, block.statements[1]).binding else throw testing::TestError::Failed;
50
        assert firstBinding.id == first.id;
51
        assert secondBinding.id == second.id;
52
    }
53
}
54
55
/// Trait lookup accepts empty tables from safe code.
56
@test fn testEmptyTraitMethodLookup() throws (testing::TestError) {
57
    assert resolver::findTraitMethod(&[], "missing") == nil;
58
}
59
60
/// Trait lookup returns the matching method metadata in declaration order.
61
@test unsafe fn testTraitMethodLookup() throws (testing::TestError) {
62
    let mut arena = super::testArena();
63
    let storage: 'test = &mut arena in {
64
        let mut res = super::testResolver(storage);
65
        let result = try super::resolveProgramStr(&mut res, "trait R { fn (&R) first(); fn (&mut R) second(); }");
66
        try super::expectNoErrors(&result);
67
        let case ast::NodeValue::Block(block) = result.root.value else throw testing::TestError::Failed;
68
        let sym = resolver::symbolFor(&res, block.statements[0]) else throw testing::TestError::Failed;
69
        let case resolver::SymbolData::Trait(info) = sym.data else throw testing::TestError::Failed;
70
        let first = resolver::findTraitMethod(&info.methods[..], "first") else throw testing::TestError::Failed;
71
        let last = resolver::findTraitMethod(&info.methods[..], "second") else throw testing::TestError::Failed;
72
        assert first.index == 0;
73
        assert not first.mutable;
74
        assert last.index == 1;
75
        assert last.mutable;
76
        assert resolver::findTraitMethod(&info.methods[..], "missing") == nil;
77
    }
78
}
79
80
/// Standalone method identities select independent registry entries.
81
@test unsafe fn testStandaloneMethodIdentityLookup() throws (testing::TestError) {
82
    let mut arena = super::testArena();
83
    let storage: 'test = &mut arena in {
84
        let mut res = super::testResolver(storage);
85
        let result = try super::resolveProgramStr(&mut res, "record R {} fn (r: &R) first() {} fn (r: &mut R) second() {}");
86
        try super::expectNoErrors(&result);
87
        let case ast::NodeValue::Block(block) = result.root.value else throw testing::TestError::Failed;
88
        let firstSymbol = resolver::symbolFor(&res, block.statements[1]) else throw testing::TestError::Failed;
89
        let lastSymbol = resolver::symbolFor(&res, block.statements[2]) else throw testing::TestError::Failed;
90
        let first = resolver::findMethodBySymbol(&res, firstSymbol.id) else throw testing::TestError::Failed;
91
        let last = resolver::findMethodBySymbol(&res, lastSymbol.id) else throw testing::TestError::Failed;
92
        assert mem::eq(first.name, "first");
93
        assert not first.mutable;
94
        assert mem::eq(last.name, "second");
95
        assert last.mutable;
96
        assert first.fullFnType.paramTypes.len == 1;
97
        assert first.fnType.paramTypes.len == 0;
98
        assert last.fullFnType.paramTypes.len == 1;
99
        assert last.fnType.paramTypes.len == 0;
100
        assert resolver::findMethodBySymbol(&res, res.symbolCount) == nil;
101
    }
102
}
103
104
/// Iteration over raw slices requires permission to read their storage.
105
@test unsafe fn testRawSliceIterationRequiresUnsafe() throws (testing::TestError) {
106
    for program in [
107
        "fn f(p: *unsafe [u32]) { for item in p { assert item == 0; } }",
108
        "fn f(p: *unsafe mut [u32]) { for item, index in p { assert item == index; } }",
109
        "record R { items: *unsafe [u32] } fn f(r: &R) { for item in r.items { 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::expectErrorKind(&result, resolver::ErrorKind::UnsafeOperation);
116
        }
117
    }
118
}
119
120
/// Checked iteration is safe, and raw iteration accepts explicit permission.
121
@test unsafe fn testSliceIterationPermissions() throws (testing::TestError) {
122
    for program in [
123
        "unsafe fn f(p: *unsafe [u32]) { for item in p { assert item == 0; } }",
124
        "fn f(p: *unsafe [u32]) { unsafe { for item in p { assert item == 0; } } }",
125
        "fn f(p: &[u32]) { for item in p { assert item == 0; } }",
126
        "fn f(p: &mut [u32]) { for item, index in p { assert item == index; } }",
127
        "fn f(p: [u32; 2]) { for item in p { assert item == 0; } }",
128
    ] {
129
        let mut arena = super::testArena();
130
        let storage: 'test = &mut arena in {
131
            let mut res = super::testResolver(storage);
132
            let result = try super::resolveProgramStr(&mut res, program);
133
            try super::expectNoErrors(&result);
134
        }
135
    }
136
}
137
138
/// Short-circuit paths must agree on exact-use regional ownership.
139
@test unsafe fn testRegionalShortCircuitOwnership() throws (testing::TestError) {
140
    for program in [
141
        "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); }",
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 = true or take(t); }",
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, flag: bool) { let result = flag and take(t); }",
144
        "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); }",
145
    ] {
146
        let mut arena = super::testArena();
147
        let storage: 'test = &mut arena in {
148
            let mut res = super::testResolver(storage);
149
            let result = try super::resolveProgramStr(&mut res, program);
150
            let error = try super::expectError(&result);
151
            let case resolver::ErrorKind::LinearBranchMismatch(_) = error.kind
152
                else throw testing::TestError::Failed;
153
        }
154
    }
155
}
156
157
/// The left operand executes on every short-circuit path.
158
@test unsafe fn testRegionalShortCircuitLeftConsumption() throws (testing::TestError) {
159
    for program in [
160
        "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; }",
161
        "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; }",
162
    ] {
163
        let mut arena = super::testArena();
164
        let storage: 'test = &mut arena in {
165
            let mut res = super::testResolver(storage);
166
            let result = try super::resolveProgramStr(&mut res, program);
167
            try super::expectNoErrors(&result);
168
        }
169
    }
170
}
171
172
/// Earlier reference arguments protect their storage during later arguments.
173
@test unsafe fn testRegionalCallArgumentLoans() throws (testing::TestError) {
174
    for program in [
175
        "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)); }",
176
        "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)); }",
177
        "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)); }",
178
        "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)); }",
179
    ] {
180
        let mut arena = super::testArena();
181
        let storage: 'test = &mut arena in {
182
            let mut res = super::testResolver(storage);
183
            let result = try super::resolveProgramStr(&mut res, program);
184
            let error = try super::expectError(&result);
185
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
186
                else throw testing::TestError::Failed;
187
        }
188
    }
189
}
190
191
/// Conditional cell creation protects each source from ordinary shared access.
192
@test unsafe fn testConditionalCellArgumentLoans() throws (testing::TestError) {
193
    for program in [
194
        "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); }",
195
        "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); }",
196
        "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)); }",
197
        "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); }",
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
            let error = try super::expectError(&result);
204
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
205
                else throw testing::TestError::Failed;
206
        }
207
    }
208
}
209
210
/// Conditional cell loans allow separate storage and shared cell aliases.
211
@test unsafe fn testConditionalCellArgumentLoanScopes() throws (testing::TestError) {
212
    for program in [
213
        "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; }",
214
        "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; }",
215
        "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); }",
216
    ] {
217
        let mut arena = super::testArena();
218
        let storage: 'test = &mut arena in {
219
            let mut res = super::testResolver(storage);
220
            let result = try super::resolveProgramStr(&mut res, program);
221
            try super::expectNoErrors(&result);
222
        }
223
    }
224
}
225
226
/// Conditional explicit arguments protect every possible borrowed place.
227
@test unsafe fn testConditionalCallArgumentLoans() throws (testing::TestError) {
228
    for program in [
229
        "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)); }",
230
        "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)); }",
231
        "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); }",
232
        "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)); }",
233
        "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); }",
234
        "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)); }",
235
        "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)); }",
236
    ] {
237
        let mut arena = super::testArena();
238
        let storage: 'test = &mut arena in {
239
            let mut res = super::testResolver(storage);
240
            let result = try super::resolveProgramStr(&mut res, program);
241
            let error = try super::expectError(&result);
242
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
243
                else throw testing::TestError::Failed;
244
        }
245
    }
246
}
247
248
/// Conditional argument alternatives cannot overlap another exclusive argument.
249
@test unsafe fn testConditionalCallArgumentOverlap() throws (testing::TestError) {
250
    for program in [
251
        "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); }",
252
        "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); }",
253
        "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); }",
254
        "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); }",
255
        "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); }",
256
        "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); }",
257
        "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); }",
258
        "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); }",
259
        "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); }",
260
        "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); }",
261
        "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); }",
262
    ] {
263
        let mut arena = super::testArena();
264
        let storage: 'test = &mut arena in {
265
            let mut res = super::testResolver(storage);
266
            let result = try super::resolveProgramStr(&mut res, program);
267
            let error = try super::expectError(&result);
268
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
269
                else throw testing::TestError::Failed;
270
        }
271
    }
272
}
273
274
/// Conditional argument alternatives permit shared access and disjoint places.
275
@test unsafe fn testConditionalCallArgumentSeparation() throws (testing::TestError) {
276
    for program in [
277
        "fn outer(p: &u32, q: &u32) {} fn f 'r (p: &'r u32, q: &'r u32, flag: bool) { outer(p if flag else q, p); }",
278
        "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); }",
279
        "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); }",
280
        "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); }",
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
/// Call loans allow shared reads, separate fields, and access after the call.
292
@test unsafe fn testRegionalCallArgumentLoanScopes() throws (testing::TestError) {
293
    for program in [
294
        "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; }",
295
        "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; }",
296
        "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; }",
297
        "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; }",
298
        "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; }",
299
    ] {
300
        let mut arena = super::testArena();
301
        let storage: 'test = &mut arena in {
302
            let mut res = super::testResolver(storage);
303
            let result = try super::resolveProgramStr(&mut res, program);
304
            try super::expectNoErrors(&result);
305
        }
306
    }
307
}
308
309
/// Equal region spellings in separate functions have distinct identities.
310
@test unsafe fn testRegionIdentities() throws (testing::TestError) {
311
    let mut testArena1 = super::testArena();
312
    let testStorage1: 'test1 = &mut testArena1 in {
313
        let mut res = super::testResolver(testStorage1);
314
        let result = try super::resolveProgramStr(&mut res,
315
            "fn first 'r (p: &'r u8) -> u8 { return *p; }\nfn second 'r (p: &'r u8) -> u8 { return *p; }"
316
        );
317
        try super::expectNoErrors(&result);
318
        let first = try super::getBlockStmt(result.root, 0);
319
        let second = try super::getBlockStmt(result.root, 1);
320
        let firstType = resolver::typeFor(&res, first) else throw testing::TestError::Failed;
321
        let secondType = resolver::typeFor(&res, second) else throw testing::TestError::Failed;
322
        let case resolver::Type::Fn(a) = firstType else throw testing::TestError::Failed;
323
        let case resolver::Type::Fn(b) = secondType else throw testing::TestError::Failed;
324
        let case resolver::Type::Pointer { class: types::PointerClass::Region(ar), .. } = *a.paramTypes[0]
325
            else throw testing::TestError::Failed;
326
        let case resolver::Type::Pointer { class: types::PointerClass::Region(br), .. } = *b.paramTypes[0]
327
            else throw testing::TestError::Failed;
328
        try testing::expect(mem::eq(ar.name, br.name));
329
        try testing::expect(ar.id <> br.id);
330
        try testing::expect(not resolver::typesEqual(*a.paramTypes[0], *b.paramTypes[0]));
331
        try testing::expect(resolver::getTypeLayout(*a.paramTypes[0]).size == 8);
332
    }
333
}
334
335
/// Parent links resolve forward declarations and preserve transitive ancestry.
336
@test unsafe fn testRegionParents() throws (testing::TestError) {
337
    let mut testArena2 = super::testArena();
338
    let testStorage2: 'test2 = &mut testArena2 in {
339
        let mut res = super::testResolver(testStorage2);
340
        let result = try super::resolveProgramStr(&mut res,
341
            "fn read 'child 'middle 'root (p: &'child u8, q: &'root u8) where 'middle: 'child, 'root: 'middle {}"
342
        );
343
        try super::expectNoErrors(&result);
344
        let func = try super::getBlockStmt(result.root, 0);
345
        let ty = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
346
        let case resolver::Type::Fn(info) = ty else throw testing::TestError::Failed;
347
        let case resolver::Type::Pointer { class: types::PointerClass::Region(child), .. } = *info.paramTypes[0]
348
            else throw testing::TestError::Failed;
349
        let case resolver::Type::Pointer { class: types::PointerClass::Region(root), .. } = *info.paramTypes[1]
350
            else throw testing::TestError::Failed;
351
        try testing::expect(types::regionContains(root, child));
352
        try testing::expect(types::regionContains(child, child));
353
        try testing::expect(not types::regionContains(child, root));
354
    }
355
}
356
357
/// Region declarations reject duplicate names, missing parents, and cycles.
358
@test unsafe fn testInvalidRegionDeclarations() throws (testing::TestError) {
359
    for program in [
360
        "fn f 'r 'r () {}",
361
        "fn f 'r () where 'missing: 'r {}",
362
        "fn f 'r () where 'r: 'r {}",
363
        "fn f 'a 'b 'c () where 'b: 'a, 'c: 'b, 'a: 'c {}",
364
    ] {
365
        let mut testArena3 = super::testArena();
366
        let testStorage3: 'test3 = &mut testArena3 in {
367
            let mut res = super::testResolver(testStorage3);
368
            let result = try super::resolveProgramStr(&mut res, program);
369
            let _ = try super::expectError(&result);
370
        }
371
    }
372
}
373
374
/// Regions from another declaration cannot enter a function signature or body.
375
@test unsafe fn testUnknownRegionNames() throws (testing::TestError) {
376
    for program in [
377
        "fn f(p: &'missing u8) {}",
378
        "fn f 'r (p: &'r u8) {} fn g(p: &'r u8) {}",
379
        "unsafe fn f(p: &'missing u8) {}",
380
        "fn f 'r (p: &'r u8) { let q: &'missing u8 = p; }",
381
    ] {
382
        let mut testArena4 = super::testArena();
383
        let testStorage4: 'test4 = &mut testArena4 in {
384
            let mut res = super::testResolver(testStorage4);
385
            let result = try super::resolveProgramStr(&mut res, program);
386
            let err = try super::expectError(&result);
387
            let case resolver::ErrorKind::UnknownRegion(_) = err.kind
388
                else throw testing::TestError::Failed;
389
        }
390
    }
391
}
392
393
/// An ancestor relation does not make distinct reference regions assignable.
394
@test unsafe fn testRegionInvariance() throws (testing::TestError) {
395
    for program in [
396
        "fn f 'a 'b (p: &'a u8) where 'a: 'b { let q: &'b u8 = p; }",
397
        "unsafe fn f 'a 'b (p: &'b u8) where 'a: 'b { let q: &'a u8 = p; }",
398
    ] {
399
        let mut testArena5 = super::testArena();
400
        let testStorage5: 'test5 = &mut testArena5 in {
401
            let mut res = super::testResolver(testStorage5);
402
            let result = try super::resolveProgramStr(&mut res, program);
403
            let err = try super::expectError(&result);
404
            let case resolver::ErrorKind::TypeMismatch(_) = err.kind
405
                else throw testing::TestError::Failed;
406
        }
407
    }
408
}
409
410
/// Nominal region environments diagnose their own invalid parent relations.
411
@test unsafe fn testNominalRegionNames() throws (testing::TestError) {
412
    for program in [
413
        "record R: 'r where 'missing: 'r { value: u8 }",
414
        "union U: 'r where 'missing: 'r { Empty }",
415
        "record R: 'r { value: &'other u8 }",
416
        "union U: 'r { Value(&'other u8) }",
417
    ] {
418
        let mut testArena6 = super::testArena();
419
        let testStorage6: 'test6 = &mut testArena6 in {
420
            let mut res = super::testResolver(testStorage6);
421
            let result = try super::resolveProgramStr(&mut res, program);
422
            let err = try super::expectError(&result);
423
            let case resolver::ErrorKind::UnknownRegion(_) = err.kind
424
                else throw testing::TestError::Failed;
425
        }
426
    }
427
    for program in [
428
        "record R: 'r + 'r { value: u8 }",
429
        "union U: 'r + 'r { Empty }",
430
    ] {
431
        let mut testArena7 = super::testArena();
432
        let testStorage7: 'test7 = &mut testArena7 in {
433
            let mut res = super::testResolver(testStorage7);
434
            let result = try super::resolveProgramStr(&mut res, program);
435
            let _ = try super::expectErrorKind(&result, resolver::ErrorKind::DuplicateBinding("'r"));
436
        }
437
    }
438
}
439
440
/// Region declarations restore their environment after a signature error.
441
@test unsafe fn testRegionErrorScopeRestoration() throws (testing::TestError) {
442
    let mut testArena8 = super::testArena();
443
    let testStorage8: 'test8 = &mut testArena8 in {
444
        let mut res = super::testResolver(testStorage8);
445
        let result = try super::resolveProgramStr(&mut res,
446
            "fn f 'r (p: &'missing u8) {} fn g 'other (p: &'r u8) {}"
447
        );
448
        let err = try super::expectError(&result);
449
        let case resolver::ErrorKind::UnknownRegion(name) = err.kind
450
            else throw testing::TestError::Failed;
451
        try testing::expect(mem::eq(name, "'missing"));
452
        try testing::expect(res.regionScope == nil);
453
        try testing::expect(res.currentFn == nil);
454
        try testing::expect(res.currentFnNode == nil);
455
    }
456
}
457
458
/// Regional exclusive references retain affine ownership and arithmetic checks.
459
@test unsafe fn testRegionExclusiveOwnership() throws (testing::TestError) {
460
    for program in [
461
        "fn f 'r (p: &'r mut u8) { let q: &'r mut u8 = p; set *p = 3; }",
462
        "unsafe fn f 'r (p: &'r mut u8) { let q: &'r mut u8 = p; set *p = 3; }",
463
        "unsafe fn f 'r (p: &'r mut u8) { let q = p + 1; }",
464
        "unsafe fn f 'r (p: &'r mut u8) { let q = p as *mut u8; }",
465
    ] {
466
        let mut testArena9 = super::testArena();
467
        let testStorage9: 'test9 = &mut testArena9 in {
468
            let mut res = super::testResolver(testStorage9);
469
            let result = try super::resolveProgramStr(&mut res, program);
470
            let _ = try super::expectError(&result);
471
        }
472
    }
473
}
474
475
/// Callback signatures preserve the same region substitution as data arguments.
476
@test unsafe fn testRegionCallbackSubstitution() throws (testing::TestError) {
477
    let mut testArena10 = super::testArena();
478
    let testStorage10: 'test10 = &mut testArena10 in {
479
        let mut res = super::testResolver(testStorage10);
480
        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); }");
481
        let err = try super::expectError(&result);
482
        let case resolver::ErrorKind::RegionInference(_) = err.kind else throw testing::TestError::Failed;
483
    }
484
}
485
486
/// A single region parameter requires one consistent named argument.
487
@test unsafe fn testRegionCallInferenceFailures() throws (testing::TestError) {
488
    for program in [
489
        "fn pair 'r (a: &'r u32, b: &'r u32) {} fn relay 'a 'b (a: &'a u32, b: &'b u32) { pair(a, b); }",
490
        "fn read 'r (p: &'r u32) {} fn relay(p: &u32) { read(p); }",
491
        "unsafe fn read 'r (p: &'r u32) {} unsafe fn relay(p: *unsafe u32) { read(p); }",
492
        "fn answer 'r () -> u32 { return 42; } fn relay() -> u32 { return answer(); }",
493
        "fn read 'r (p: ?&'r u32) {} fn relay() { read(nil); }",
494
        "unsafe fn read 'r (p: ?&'r u32) {} unsafe fn relay() { read(nil); }",
495
    ] {
496
        let mut testArena11 = super::testArena();
497
        let testStorage11: 'test11 = &mut testArena11 in {
498
            let mut res = super::testResolver(testStorage11);
499
            let result = try super::resolveProgramStr(&mut res, program);
500
            let err = try super::expectError(&result);
501
            let case resolver::ErrorKind::RegionInference(_) = err.kind else throw testing::TestError::Failed;
502
        }
503
    }
504
}
505
506
/// Inferred and explicit region arguments must satisfy declared parent relations.
507
@test unsafe fn testRegionCallParents() throws (testing::TestError) {
508
    for program in [
509
        "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); }",
510
        "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); }",
511
    ] {
512
        let mut testArena12 = super::testArena();
513
        let testStorage12: 'test12 = &mut testArena12 in {
514
            let mut res = super::testResolver(testStorage12);
515
            let result = try super::resolveProgramStr(&mut res, program);
516
            let err = try super::expectError(&result);
517
            let case resolver::ErrorKind::RegionParent(_) = err.kind else throw testing::TestError::Failed;
518
        }
519
    }
520
}
521
522
/// Region applications require the declared arity and accessible names.
523
@test unsafe fn testExplicitRegionApplicationErrors() throws (testing::TestError) {
524
    for program in [
525
        "fn read 'r (p: &'r u32) {} fn relay 'a 'b (p: &'a u32) { read 'a 'b (p); }",
526
        "fn read(p: &u32) {} fn relay 'a (p: &'a u32) { read 'a (p); }",
527
    ] {
528
        let mut testArena13 = super::testArena();
529
        let testStorage13: 'test13 = &mut testArena13 in {
530
            let mut res = super::testResolver(testStorage13);
531
            let result = try super::resolveProgramStr(&mut res, program);
532
            let err = try super::expectError(&result);
533
            let case resolver::ErrorKind::RegionArgumentCount(_) = err.kind else throw testing::TestError::Failed;
534
        }
535
    }
536
    let mut testArena14 = super::testArena();
537
    let testStorage14: 'test14 = &mut testArena14 in {
538
        let mut res = super::testResolver(testStorage14);
539
        let result = try super::resolveProgramStr(&mut res, "fn read 'r (p: &'r u32) {} fn relay 'a (p: &'a u32) { read 'missing (p); }");
540
        let err = try super::expectError(&result);
541
        let case resolver::ErrorKind::UnknownRegion(_) = err.kind else throw testing::TestError::Failed;
542
    }
543
}
544
545
/// Region header loans stay active through moves and nested exclusive reborrows.
546
@test unsafe fn testConcreteBorrowConflicts() throws (testing::TestError) {
547
    for program in [
548
        "fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { set x = 2; } }",
549
        "unsafe fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { set x = 2; } }",
550
        "fn run() { let mut x: u32 = 1; let p: 'r = &mut x, q = &mut x in {} }",
551
        "fn run() { let mut x: u32 = 1; let p: 'r = &x, q = &mut x in {} }",
552
        "fn run() { let mut x: u32 = 1; let p: 'r = &mut x in { { let q = p; set *q = 2; } set x = 3; } }",
553
        "fn run() { let mut x: u32 = 1; let p: 'a = &mut x in { let q: 'b = &mut *p in { set *p = 3; } } }",
554
        "fn run(i: u32, j: u32) { let mut x: [u32; 2] = [1, 2]; let p: 'r = &mut x[i], q = &mut x[j] in {} }",
555
    ] {
556
        let mut testArena15 = super::testArena();
557
        let testStorage15: 'test15 = &mut testArena15 in {
558
            let mut res = super::testResolver(testStorage15);
559
            let result = try super::resolveProgramStr(&mut res, program);
560
            let err = try super::expectError(&result);
561
            let case resolver::ErrorKind::BorrowConflict(_) = err.kind else throw testing::TestError::Failed;
562
        }
563
    }
564
}
565
566
/// Borrow headers require existing places and accessible, distinct region names.
567
@test unsafe fn testConcreteRegionNamesAndSources() throws (testing::TestError) {
568
    for program in [
569
        "fn run() { let p: 'r = &1 in {} }",
570
        "fn value() -> u32 { return 1; } fn run() { let p: 'r = &value() in {} }",
571
        "fn run() { let x: u32 = 1; let p: 'r = &x in { let q: 'r = &x in {} } }",
572
        "fn run() { let x: u32 = 1; let p: 'r = &x in {} let q: &'r u32 = &x; }",
573
        "fn run 'a (p: &'a mut u32) { let q: 'b = &mut *p in {} }",
574
    ] {
575
        let mut testArena16 = super::testArena();
576
        let testStorage16: 'test16 = &mut testArena16 in {
577
            let mut res = super::testResolver(testStorage16);
578
            let result = try super::resolveProgramStr(&mut res, program);
579
            let _ = try super::expectError(&result);
580
        }
581
    }
582
583
}
584
585
/// A block-local value cannot supply storage for the whole enclosing region.
586
@test unsafe fn testRegionLocalStorageBoundary() throws (testing::TestError) {
587
    for program in [
588
        "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; } } }",
589
        "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; } } }",
590
        "fn run() { let x: u32 = 1; let p: 'r = &x in { let y: u32 = 2; let q: &'r u32 = &y; } }",
591
        "unsafe fn run() { let x: u32 = 1; let p: 'r = &x in { let y: u32 = 2; let q: &'r u32 = &y; } }",
592
        "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; } } }",
593
    ] {
594
        let mut testArena17 = super::testArena();
595
        let testStorage17: 'test17 = &mut testArena17 in {
596
            let mut res = super::testResolver(testStorage17);
597
            let result = try super::resolveProgramStr(&mut res, program);
598
            let err = try super::expectError(&result);
599
            let case resolver::ErrorKind::TypeMismatch(_) = err.kind else throw testing::TestError::Failed;
600
        }
601
    }
602
603
}
604
605
/// Generic calls keep the exclusive-argument overlap check after substitution.
606
@test unsafe fn testRegionCallBorrowOverlap() throws (testing::TestError) {
607
    let mut testArena18 = super::testArena();
608
    let testStorage18: 'test18 = &mut testArena18 in {
609
        let mut res = super::testResolver(testStorage18);
610
        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); } }");
611
        let err = try super::expectError(&result);
612
        let case resolver::ErrorKind::BorrowConflict(_) = err.kind else throw testing::TestError::Failed;
613
    }
614
}
615
616
/// Ownership markers do not change the positions of nominal region arguments.
617
@test unsafe fn testNominalRegionParameterOrder() throws (testing::TestError) {
618
    for program in [
619
        "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 }; }",
620
        "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 }; }",
621
        "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 }; }",
622
    ] {
623
        let mut arena = super::testArena();
624
        let storage: 'test = &mut arena in {
625
            let mut res = super::testResolver(storage);
626
            let result = try super::resolveProgramStr(&mut res, program);
627
            try super::expectNoErrors(&result);
628
        }
629
    }
630
}
631
632
/// Exact application keys include the base and the ordered region arguments.
633
@test unsafe fn testNominalApplicationKeys() throws (testing::TestError) {
634
    let mut arena = super::testArena();
635
    let storage: 'test = &mut arena in {
636
        let mut res = super::testResolver(storage);
637
        let result = try super::resolveProgramStr(&mut res,
638
            "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) {}"
639
        );
640
        try super::expectNoErrors(&result);
641
        let func = try super::getBlockStmt(result.root, 2);
642
        let ty = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
643
        let case resolver::Type::Fn(info) = ty else throw testing::TestError::Failed;
644
        for param, i in info.paramTypes {
645
            for other, j in info.paramTypes {
646
                assert (param == other) == (i == j or (i < 2 and j < 2));
647
            }
648
        }
649
        let mut count: u32 = 0;
650
        let mut cursor = res.applications;
651
        while let entry = cursor {
652
            assert entry.arguments.len == 2;
653
            assert resolver::nominalApplication(entry.view) == entry;
654
            set count += 1;
655
            set cursor = entry.next;
656
        }
657
        assert count == 4;
658
    }
659
}
660
661
/// Exact arguments share one descriptor and all applications share the source layout.
662
@test unsafe fn testNominalRegionApplications() throws (testing::TestError) {
663
    let mut testArena19 = super::testArena();
664
    let testStorage19: 'test19 = &mut testArena19 in {
665
        let mut res = super::testResolver(testStorage19);
666
        let result = try super::resolveProgramStr(&mut res,
667
            "record N: 'r + Copy { value: u32 } fn f 'a 'b (x: N 'a, y: N 'a, z: N 'b) {}"
668
        );
669
        try super::expectNoErrors(&result);
670
        let func = try super::getBlockStmt(result.root, 1);
671
        let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
672
        let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
673
        let case resolver::Type::Nominal(x) = *info.paramTypes[0] else throw testing::TestError::Failed;
674
        let case resolver::Type::Nominal(y) = *info.paramTypes[1] else throw testing::TestError::Failed;
675
        let case resolver::Type::Nominal(z) = *info.paramTypes[2] else throw testing::TestError::Failed;
676
        try testing::expect(x == y);
677
        try testing::expect(x <> z);
678
        try testing::expect(not resolver::typesEqual(*info.paramTypes[0], *info.paramTypes[2]));
679
        let a = resolver::nominalApplication(x) else throw testing::TestError::Failed;
680
        let b = resolver::nominalApplication(z) else throw testing::TestError::Failed;
681
        try testing::expect(a.base == b.base);
682
        try testing::expect(a.arguments[0].id <> b.arguments[0].id);
683
        let case resolver::NominalType::Record(base) = *a.base else throw testing::TestError::Failed;
684
        let case resolver::NominalType::Record(first) = *x else throw testing::TestError::Failed;
685
        let case resolver::NominalType::Record(second) = *z else throw testing::TestError::Failed;
686
        try testing::expect(base.layout == first.layout);
687
        try testing::expect(first.layout == second.layout);
688
        try testing::expect(first.layout.size == 4);
689
    }
690
}
691
692
693
/// Applications introduced in successive function bodies are fully resolved.
694
@test unsafe fn testNominalCompletionAcrossBodies() throws (testing::TestError) {
695
    let mut arena = super::testArena();
696
    let storage: 'test = &mut arena in {
697
        let mut res = super::testResolver(storage);
698
        let result = try super::resolveProgramStr(&mut res,
699
            "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 }; }"
700
        );
701
        try super::expectNoErrors(&result);
702
        let mut count: u32 = 0;
703
        let mut cursor = res.applications;
704
        while let applied = cursor {
705
            let case resolver::NominalType::Record(body) = *applied.view else throw testing::TestError::Failed;
706
            assert body.application == applied;
707
            assert body.fields.len == 1;
708
            set count += 1;
709
            set cursor = applied.next;
710
        }
711
        assert count == 2;
712
    }
713
}
714
715
/// Recursive fields refer to their own exact applied descriptor.
716
@test unsafe fn testRecursiveNominalApplications() throws (testing::TestError) {
717
    let mut testArena20 = super::testArena();
718
    let testStorage20: 'test20 = &mut testArena20 in {
719
        let mut res = super::testResolver(testStorage20);
720
        let result = try super::resolveProgramStr(&mut res,
721
            "record N: 'r + Copy { next: ?*N 'r } fn f 'a 'b (x: N 'a, y: N 'b) {}"
722
        );
723
        try super::expectNoErrors(&result);
724
        let func = try super::getBlockStmt(result.root, 1);
725
        let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
726
        let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
727
        for parameter in info.paramTypes {
728
            let case resolver::Type::Nominal(descriptor) = *parameter else throw testing::TestError::Failed;
729
            let case resolver::NominalType::Record(body) = *descriptor else throw testing::TestError::Failed;
730
            let case resolver::Type::Optional(inner) = body.fields[0].fieldType else throw testing::TestError::Failed;
731
            let case resolver::Type::Pointer { target, .. } = *inner else throw testing::TestError::Failed;
732
            try testing::expect(resolver::typesEqual(*target, *parameter));
733
            try testing::expect(body.layout.size == 8);
734
        }
735
    }
736
}
737
738
/// An inline union payload retains its enclosing application's region arguments.
739
@test unsafe fn testNominalPayloadRegionCapture() throws (testing::TestError) {
740
    let mut testArena21 = super::testArena();
741
    let testStorage21: 'test21 = &mut testArena21 in {
742
        let mut res = super::testResolver(testStorage21);
743
        let result = try super::resolveProgramStr(&mut res,
744
            "record N: 'r + Copy { value: u32 } union U: 'r + Copy { Link { node: *N 'r }, Empty } fn f 'a (u: U 'a, n: N 'a) {}"
745
        );
746
        try super::expectNoErrors(&result);
747
        let func = try super::getBlockStmt(result.root, 2);
748
        let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
749
        let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
750
        let case resolver::Type::Nominal(resolver::NominalType::Union(body)) = *info.paramTypes[0]
751
            else throw testing::TestError::Failed;
752
        let case resolver::Type::Nominal(resolver::NominalType::Record(payload)) = body.variants[0].valueType
753
            else throw testing::TestError::Failed;
754
        let case resolver::Type::Pointer { target, .. } = payload.fields[0].fieldType
755
            else throw testing::TestError::Failed;
756
        try testing::expect(resolver::typesEqual(*target, *info.paramTypes[1]));
757
        let applied = body.application else throw testing::TestError::Failed;
758
        let case resolver::NominalType::Union(base) = *applied.base else throw testing::TestError::Failed;
759
        try testing::expect(body.layout == base.layout);
760
    }
761
}
762
763
/// Nominal applications require exactly the declared number of region arguments.
764
@test unsafe fn testNominalRegionArgumentCount() throws (testing::TestError) {
765
    for program in [
766
        "record N: 'r { value: u32 } fn f(n: N) {}",
767
        "record N { value: u32 } fn f 'r (n: N 'r) {}",
768
        "record N: 'r + 's { value: u32 } fn f 'a (n: N 'a) {}",
769
        "record N: 'r { value: u32 } fn f 'a 'b (n: N 'a 'b) {}",
770
        "record N: 'r { value: u32 } fn f() { let n = N { value: 1 }; }",
771
        "union U: 'r { Empty } fn f() { let u = U::Empty; }",
772
    ] {
773
        let mut testArena22 = super::testArena();
774
        let testStorage22: 'test22 = &mut testArena22 in {
775
            let mut res = super::testResolver(testStorage22);
776
            let result = try super::resolveProgramStr(&mut res, program);
777
            let error = try super::expectError(&result);
778
            let case resolver::ErrorKind::RegionArgumentCount(_) = error.kind else throw testing::TestError::Failed;
779
        }
780
    }
781
}
782
783
/// Type arguments are invariant in values, constructor hints, and patterns.
784
@test unsafe fn testNominalRegionInvariance() throws (testing::TestError) {
785
    for program in [
786
        "record N: 'r + Copy { value: u32 } fn f 'a 'b (n: N 'a) { let x: N 'b = n; }",
787
        "record N: 'r + Copy { value: u32 } unsafe fn f 'a 'b (n: N 'a) { let x: N 'b = n; }",
788
        "record N: 'r + Copy { value: u32 } fn f 'a 'b () { let n: N 'a = N 'b { value: 1 }; }",
789
        "record N: 'r + Copy { value: u32 } fn f 'a 'b (n: N 'a) { let case N 'b { value } = n else panic; }",
790
        "record N: 'r + Copy (u32); fn f 'a 'b (n: N 'a) { let case N 'b (value) = n else panic; }",
791
        "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; }",
792
    ] {
793
        let mut testArena23 = super::testArena();
794
        let testStorage23: 'test23 = &mut testArena23 in {
795
            let mut res = super::testResolver(testStorage23);
796
            let result = try super::resolveProgramStr(&mut res, program);
797
            let error = try super::expectError(&result);
798
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
799
        }
800
    }
801
}
802
803
/// Region inference must agree between an outer reference and its embedded nominal type.
804
@test unsafe fn testNominalRegionInferenceConflict() throws (testing::TestError) {
805
    for program in [
806
        "record N: 'r + Copy { value: u32 } fn take 'r (n: &'r N 'r) {} fn f 'a 'b (n: &'a N 'b) { take(n); }",
807
        "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); }",
808
    ] {
809
        let mut testArena24 = super::testArena();
810
        let testStorage24: 'test24 = &mut testArena24 in {
811
            let mut res = super::testResolver(testStorage24);
812
            let result = try super::resolveProgramStr(&mut res, program);
813
            let error = try super::expectError(&result);
814
            let case resolver::ErrorKind::RegionInference(_) = error.kind else throw testing::TestError::Failed;
815
        }
816
    }
817
}
818
819
/// Applications must satisfy the source declaration's explicit parent relations.
820
@test unsafe fn testNominalRegionParentConstraint() throws (testing::TestError) {
821
    let mut testArena25 = super::testArena();
822
    let testStorage25: 'test25 = &mut testArena25 in {
823
        let mut res = super::testResolver(testStorage25);
824
        let result = try super::resolveProgramStr(&mut res,
825
            "record N: 'r + 's where 'r: 's { value: u32 } fn f 'a 'b (n: N 'a 'b) {}"
826
        );
827
        let error = try super::expectError(&result);
828
        let case resolver::ErrorKind::RegionParent(_) = error.kind else throw testing::TestError::Failed;
829
    }
830
}
831
832
/// An applied affine type retains the source declaration's move rule.
833
@test unsafe fn testNominalRegionMoveRule() throws (testing::TestError) {
834
    let mut testArena26 = super::testArena();
835
    let testStorage26: 'test26 = &mut testArena26 in {
836
        let mut res = super::testResolver(testStorage26);
837
        let result = try super::resolveProgramStr(&mut res,
838
            "record N: 'r { value: u32 } fn f 'a (n: N 'a) { let first = n; let second = n; }"
839
        );
840
        let error = try super::expectError(&result);
841
        let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
842
    }
843
}
844
845
/// By-value cycles have no layout, including cycles through exact applications.
846
@test unsafe fn testNominalRegionValueCycle() throws (testing::TestError) {
847
    for program in [
848
        "record N: 'r { next: N 'r }",
849
        "record N: 'r { next: ?N 'r }",
850
        "union U: 'r { More(U 'r), Empty }",
851
        "record N: 'r { m: M 'r } record M: 'r { n: N 'r }",
852
    ] {
853
        let mut testArena27 = super::testArena();
854
        let testStorage27: 'test27 = &mut testArena27 in {
855
            let mut res = super::testResolver(testStorage27);
856
            let result = try super::resolveProgramStr(&mut res, program);
857
            let error = try super::expectError(&result);
858
            let case resolver::ErrorKind::RecursiveType = error.kind else throw testing::TestError::Failed;
859
        }
860
    }
861
}
862
863
/// Recursive substitutions can permute arguments without expanding the type graph.
864
@test unsafe fn testNominalRegionPermutation() throws (testing::TestError) {
865
    let mut testArena28 = super::testArena();
866
    let testStorage28: 'test28 = &mut testArena28 in {
867
        let mut res = super::testResolver(testStorage28);
868
        let result = try super::resolveProgramStr(&mut res,
869
            "record N: 'r + 's + Copy { next: ?*N 's 'r } fn f 'a 'b (x: N 'a 'b, y: N 'b 'a) {}"
870
        );
871
        try super::expectNoErrors(&result);
872
        let func = try super::getBlockStmt(result.root, 1);
873
        let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
874
        let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
875
        for parameter, i in info.paramTypes {
876
            let case resolver::Type::Nominal(resolver::NominalType::Record(body)) = *parameter
877
                else throw testing::TestError::Failed;
878
            let case resolver::Type::Optional(inner) = body.fields[0].fieldType else throw testing::TestError::Failed;
879
            let case resolver::Type::Pointer { target, .. } = *inner else throw testing::TestError::Failed;
880
            try testing::expect(resolver::typesEqual(*target, *info.paramTypes[1 - i]));
881
        }
882
    }
883
}
884
885
/// Calls transfer named exclusive references on normal and error paths.
886
@test unsafe fn testRegionalCallOwnershipTransfer() throws (testing::TestError) {
887
    for program in [
888
        "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32) { take(p); take(p); }",
889
        "fn take 'r (p: &'r mut u32) {} unsafe fn run 'r (p: &'r mut u32) { take(p); set *p = 1; }",
890
        "fn take 'r (p: &'r mut [u32]) {} fn run 'r (p: &'r mut [u32]) { take(p); p[0]; }",
891
        "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32) { let f = take 'r; f(p); set *p = 1; }",
892
        "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; }",
893
        "fn take 'r (p: &'r mut u32) {} fn run 'r (p: &'r mut u32, c: bool) { if c { take(p); } set *p = 1; }",
894
    ] {
895
        let mut testArena29 = super::testArena();
896
        let testStorage29: 'test29 = &mut testArena29 in {
897
            let mut res = super::testResolver(testStorage29);
898
            let result = try super::resolveProgramStr(&mut res, program);
899
            let error = try super::expectError(&result);
900
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
901
        }
902
    }
903
}
904
905
/// Full-region projections protect their source after a local binding leaves scope.
906
@test unsafe fn testRegionalProjectionLifetime() throws (testing::TestError) {
907
    for program in [
908
        "fn f 'r (p: &'r mut u32) { let shared = &*p; let copy = shared; set *p = 1; }",
909
        "unsafe fn f 'r (p: &'r mut u32) { let shared = &*p; let copy = shared; set *p = 1; }",
910
        "fn f 'r (p: &'r mut u32, q: &'r u32) { let mut cursor = q; set cursor = &*p; set *p = 1; }",
911
        "unsafe fn f 'r (p: &'r mut u32, q: &'r u32) { let mut cursor = q; set cursor = &*p; set *p = 1; }",
912
        "fn f 'r (p: &'r mut u32) { { let q = &mut *p; set *q = 1; } set *p = 2; }",
913
        "fn f 'r (p: &'r mut u32) { { let q = &*p; } set *p = 2; }",
914
        "unsafe fn f 'r (p: &'r mut u32) { { let q = &*p; } set *p = 2; }",
915
        "fn f 'r (p: &'r mut u32) { { let q = &mut *p; let moved = q; } *p; }",
916
        "record P { a: u32, b: u32 } fn f 'r (p: &'r mut P) { { let q = &mut p.a; } p.a; }",
917
        "record P { a: u32, b: u32 } fn f 'r (p: &'r mut P) { { let q = &p.a; } set p.a = 2; }",
918
    ] {
919
        let mut testArena30 = super::testArena();
920
        let testStorage30: 'test30 = &mut testArena30 in {
921
            let mut res = super::testResolver(testStorage30);
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
/// A regional loan on any live branch remains active at the branch join.
930
@test unsafe fn testRegionalProjectionBranchJoin() throws (testing::TestError) {
931
    for program in [
932
        "fn f 'r (p: &'r mut u32, c: bool) { if c { let q = &mut *p; } set *p = 2; }",
933
        "fn f 'r (p: &'r mut u32, c: bool) { if c {} else { let q = &*p; } set *p = 2; }",
934
        "fn f 'r (p: &'r mut u32, c: bool) { match c { case true => { let q = &mut *p; } else => {} } *p; }",
935
        "fn f 'r (p: &'r mut u32, c: ?u32) { if let n = c { let q = &*p; } set *p = 2; }",
936
    ] {
937
        let mut testArena31 = super::testArena();
938
        let testStorage31: 'test31 = &mut testArena31 in {
939
            let mut res = super::testResolver(testStorage31);
940
            let result = try super::resolveProgramStr(&mut res, program);
941
            let error = try super::expectError(&result);
942
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
943
        }
944
    }
945
}
946
947
/// Loop back edges carry regional loans into later iterations.
948
@test unsafe fn testRegionalProjectionLoopBackEdge() throws (testing::TestError) {
949
    for program in [
950
        "fn f 'r (p: &'r mut u32) { for i in 0..2 { let q = &mut *p; } }",
951
        "fn f 'r (p: &'r mut u32) { for i in 0..2 { set *p = 1; let q = &*p; } }",
952
        "fn f 'r (p: &'r mut u32) { for i in 0..2 { set *p = 1; let q = &*p; continue; } }",
953
        "fn f 'r (p: &'r mut u32, c: bool) { while c { let q = &mut *p; } }",
954
        "fn f 'r (p: &'r mut u32, c: ?u32) { while let n = c { let q = &mut *p; } }",
955
        "fn f 'r (p: &'r mut u32) { loop { let q = &mut *p; } }",
956
        "fn f 'r (p: &'r mut u32, c: bool) { loop { if c { set *p = 1; break; } let q = &*p; } }",
957
    ] {
958
        let mut testArena32 = super::testArena();
959
        let testStorage32: 'test32 = &mut testArena32 in {
960
            let mut res = super::testResolver(testStorage32);
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
/// Loans in caller-supplied regions survive loop and nested-region exits.
969
@test unsafe fn testRegionalProjectionLoopExit() throws (testing::TestError) {
970
    for program in [
971
        "fn f 'r (p: &'r mut u32) { loop { let q = &mut *p; break; } set *p = 2; }",
972
        "fn f 'r (p: &'r mut u32, c: bool) { while c { let q = &*p; break; } else {} set *p = 2; }",
973
        "fn f 'r (p: &'r mut u32) { for i in 0..2 { let q = &*p; break; } else {} set *p = 2; }",
974
        "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; }",
975
    ] {
976
        let mut testArena33 = super::testArena();
977
        let testStorage33: 'test33 = &mut testArena33 in {
978
            let mut res = super::testResolver(testStorage33);
979
            let result = try super::resolveProgramStr(&mut res, program);
980
            let error = try super::expectError(&result);
981
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
982
        }
983
    }
984
}
985
986
/// Region erasure cannot merge distinct error alternatives in one signature.
987
@test unsafe fn testRegionalErrorAmbiguity() throws (testing::TestError) {
988
    for program in [
989
        "record E: 'r + Copy {} fn f 'a 'b () throws (E 'a, E 'b) {}",
990
        "record E: 'r + Copy {} unsafe fn f 'a 'b () throws (E 'a, E 'b) {}",
991
        "record E: 'r + Copy {} record Callback: 'a + 'b { f: fn() throws (E 'a, E 'b) }",
992
        "fn f 'a 'b () throws (&'a u32, &'b u32) {}",
993
    ] {
994
        let mut testArena34 = super::testArena();
995
        let testStorage34: 'test34 = &mut testArena34 in {
996
            let mut res = super::testResolver(testStorage34);
997
            let result = try super::resolveProgramStr(&mut res, program);
998
            try super::expectErrorKind(&result, resolver::ErrorKind::AmbiguousRegionalError);
999
        }
1000
    }
1001
}
1002
1003
/// Moving an exclusive reference into an aggregate transfers its ownership.
1004
@test unsafe fn testRegionalAggregateMove() throws (testing::TestError) {
1005
    for program in [
1006
        "record W: 'r { p: &'r mut u32 } fn f 'r (p: &'r mut u32) { let w = W 'r { p }; set *p = 1; }",
1007
        "record W: 'r { p: &'r mut u32 } unsafe fn f 'r (p: &'r mut u32) { let w = W 'r { p }; set *p = 1; }",
1008
        "record W: 'r { p: &'r mut u32 } fn f 'r (w: W 'r) { let case W { p } = w else panic; let again = w; }",
1009
        "union W: 'r { P { p: &'r mut u32 } } fn f 'r (p: &'r mut u32) { let w = W 'r::P { p }; set *p = 1; }",
1010
        "fn f 'r (p: &'r mut u32) { let a: [&'r mut u32; 1] = [p]; set *p = 1; }",
1011
        "fn f 'r (p: &'r mut u32) { let a: ?&'r mut u32 = p; set *p = 1; }",
1012
    ] {
1013
        let mut testArena35 = super::testArena();
1014
        let testStorage35: 'test35 = &mut testArena35 in {
1015
            let mut res = super::testResolver(testStorage35);
1016
            let result = try super::resolveProgramStr(&mut res, program);
1017
            let error = try super::expectError(&result);
1018
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
1019
        }
1020
    }
1021
}
1022
1023
/// Aggregate transfers do not end a projection loan on its source.
1024
@test unsafe fn testRegionalAggregateLoan() throws (testing::TestError) {
1025
    for program in [
1026
        "record W: 'r { p: &'r mut u32 } fn f 'r (p: &'r mut u32) { { let w = W 'r { p: &mut *p }; } set *p = 1; }",
1027
        "record R: 'r + Copy { p: &'r u32 } fn f 'r (p: &'r mut u32) { { let r = R 'r { p: &*p }; } set *p = 1; }",
1028
        "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; }",
1029
        "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; }",
1030
    ] {
1031
        let mut testArena36 = super::testArena();
1032
        let testStorage36: 'test36 = &mut testArena36 in {
1033
            let mut res = super::testResolver(testStorage36);
1034
            let result = try super::resolveProgramStr(&mut res, program);
1035
            let error = try super::expectError(&result);
1036
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1037
        }
1038
    }
1039
}
1040
1041
/// Local storage cannot acquire a caller region through returns or aggregate hints.
1042
@test unsafe fn testRegionalStorageEscape() throws (testing::TestError) {
1043
    for program in [
1044
        "fn f 'r () -> &'r u32 { let x: u32 = 1; return &x; }",
1045
        "unsafe fn f 'r () -> &'r u32 { let x: u32 = 1; return &x; }",
1046
        "record R: 'r + Copy { p: &'r u32 } fn f 'r () -> R 'r { let x: u32 = 1; return R 'r { p: &x }; }",
1047
        "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 }; } }",
1048
        "record R: 'r + Copy { p: &'r u32 } fn f 'r (p: &'r u32) -> &'r R 'r { let r = R 'r { p }; return &r; }",
1049
        "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 }; } }",
1050
    ] {
1051
        let mut testArena37 = super::testArena();
1052
        let testStorage37: 'test37 = &mut testArena37 in {
1053
            let mut res = super::testResolver(testStorage37);
1054
            let result = try super::resolveProgramStr(&mut res, program);
1055
            let error = try super::expectError(&result);
1056
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1057
        }
1058
    }
1059
}
1060
1061
/// Reference fields retain their ownership and storage restrictions.
1062
@test unsafe fn testRegionalFieldRestrictions() throws (testing::TestError) {
1063
    {
1064
        let mut testArena38 = super::testArena();
1065
        let testStorage38: 'test38 = &mut testArena38 in {
1066
            let mut res = super::testResolver(testStorage38);
1067
            let result = try super::resolveProgramStr(&mut res, "record W: 'r { p: &'r mut u32 } fn f 'r (w: W 'r) { let p = w.p; }");
1068
            try super::expectErrorKind(&result, resolver::ErrorKind::LinearPartialMove);
1069
        }
1070
    }
1071
    {
1072
        let mut testArena39 = super::testArena();
1073
        let testStorage39: 'test39 = &mut testArena39 in {
1074
            let mut res = super::testResolver(testStorage39);
1075
            let result = try super::resolveProgramStr(&mut res, "record R: 'r { p: &u32 }");
1076
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition);
1077
        }
1078
    }
1079
    {
1080
        let mut testArena40 = super::testArena();
1081
        let testStorage40: 'test40 = &mut testArena40 in {
1082
            let mut res = super::testResolver(testStorage40);
1083
            let result = try super::resolveProgramStr(&mut res, "fn f 'r (p: &'r u32) { static r: &'r u32 = undefined; }");
1084
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition);
1085
        }
1086
    }
1087
}
1088
1089
/// Call tracking includes all explicit arguments and the implicit receiver.
1090
@test unsafe fn testCallLoanScratchCapacity() throws (testing::TestError) {
1091
    let mut arena = super::testArena();
1092
    let storage: 'test = &mut arena in {
1093
        let mut res = super::testResolver(storage);
1094
        let result = try super::resolveProgramStr(&mut res,
1095
            "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; }"
1096
        );
1097
        try super::expectNoErrors(&result);
1098
    }
1099
    for program in [
1100
        "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); }",
1101
        "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); }",
1102
    ] {
1103
        let mut errorArena = super::testArena();
1104
        let errorStorage: 'error = &mut errorArena in {
1105
            let mut res = super::testResolver(errorStorage);
1106
            let result = try super::resolveProgramStr(&mut res, program);
1107
            let error = try super::expectError(&result);
1108
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1109
        }
1110
    }
1111
}
1112
1113
/// Loan compaction preserves outer-region conflicts after child slots expire.
1114
@test unsafe fn testRegionalLoanCompactionConflict() throws (testing::TestError) {
1115
    for program in [
1116
        "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; }",
1117
        "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; }",
1118
    ] {
1119
        let mut arena = super::testArena();
1120
        let storage: 'test = &mut arena in {
1121
            let mut res = super::testResolver(storage);
1122
            let result = try super::resolveProgramStr(&mut res, program);
1123
            let error = try super::expectError(&result);
1124
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1125
        }
1126
    }
1127
}
1128
1129
/// Regional projection tracking limits simultaneous live projections.
1130
@test unsafe fn testRegionalLoanCapacity() throws (testing::TestError) {
1131
    let mut reuseArena = super::testArena();
1132
    let reuseStorage: 'reuse = &mut reuseArena in {
1133
        let mut res = super::testResolver(reuseStorage);
1134
        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; } } }");
1135
        try super::expectNoErrors(&result);
1136
    }
1137
    let mut testArena41 = super::testArena();
1138
    let testStorage41: 'test41 = &mut testArena41 in {
1139
        let mut res = super::testResolver(testStorage41);
1140
        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]; }");
1141
        try super::expectErrorKind(&result, resolver::ErrorKind::RegionalLoanOverflow);
1142
    }
1143
}
1144
1145
/// Shared regional parameters consume exclusive arguments that can be retained.
1146
@test unsafe fn testRegionalSharedCallTransfer() throws (testing::TestError) {
1147
    for program in [
1148
        "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; }",
1149
        "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; }",
1150
        "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; }",
1151
        "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; }",
1152
    ] {
1153
        let mut testArena42 = super::testArena();
1154
        let testStorage42: 'test42 = &mut testArena42 in {
1155
            let mut res = super::testResolver(testStorage42);
1156
            let result = try super::resolveProgramStr(&mut res, program);
1157
            let error = try super::expectError(&result);
1158
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
1159
        }
1160
    }
1161
}
1162
1163
/// Values stored in a regional destination must cover its full lifetime.
1164
@test unsafe fn testRegionalStoreLifetime() throws (testing::TestError) {
1165
    for program in [
1166
        "fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) { set *dst = p; }",
1167
        "unsafe fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) { set *dst = p; }",
1168
        "fn f 'a 'b (dst: &'a mut ?&'b u32, p: &'b u32) where 'a: 'b { set *dst = p; }",
1169
        "record R: 'r + Copy { p: &'r u32 } fn f 'a 'b (dst: &'a mut R 'b, p: &'b u32) { set *dst = R 'b { p }; }",
1170
        "fn f 'a 'b (dst: &'a mut [&'b u32], p: &'b u32) { set dst[0] = p; }",
1171
        "fn f 'a 'b (dst: &'a mut [&'b u32], p: &'b u32) { set dst[..] = p; }",
1172
        "fn f 'a 'b (dst: &'a mut fn(&'b u32), callback: fn(&'b u32)) { set *dst = callback; }",
1173
    ] {
1174
        let mut testArena43 = super::testArena();
1175
        let testStorage43: 'test43 = &mut testArena43 in {
1176
            let mut res = super::testResolver(testStorage43);
1177
            let result = try super::resolveProgramStr(&mut res, program);
1178
            let error = try super::expectError(&result);
1179
            let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed;
1180
        }
1181
    }
1182
}
1183
1184
/// A session holds the arena loan after the interface is moved or discarded.
1185
@test unsafe fn testSessionArenaLoan() throws (testing::TestError) {
1186
    for program in [
1187
        "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { alloc::reset(arena); } }",
1188
        "use std::lang::alloc; unsafe fn f(arena: &mut alloc::Arena) { use *arena as s in { alloc::reset(arena); } }",
1189
        "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { let moved = s; alloc::reset(arena); } }",
1190
        "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { let _ = s; set arena.offset = 0; } }",
1191
        "use std::lang::alloc; fn f(arena: &mut alloc::Arena) { use *arena as s in { use *arena as t in {} } }",
1192
    ] {
1193
        let mut testArena44 = super::testArena();
1194
        let testStorage44: 'test44 = &mut testArena44 in {
1195
            let mut res = super::testResolver(testStorage44);
1196
            let result = try super::resolveSessionProgramStr(&mut res, program);
1197
            let error = try super::expectError(&result);
1198
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
1199
        }
1200
    }
1201
}
1202
1203
/// Session interfaces have affine ownership and invariant region arguments.
1204
@test unsafe fn testSessionOwnership() throws (testing::TestError) {
1205
    for program in [
1206
        "fn f 'r (s: Session 'r) { let moved = s; let again = s; }",
1207
        "unsafe fn f 'r (s: Session 'r) { let moved = s; let again = s; }",
1208
        "fn take 'r (s: Session 'r) {} fn f 'r (s: Session 'r) { take(s); take(s); }",
1209
    ] {
1210
        let mut testArena45 = super::testArena();
1211
        let testStorage45: 'test45 = &mut testArena45 in {
1212
            let mut res = super::testResolver(testStorage45);
1213
            let result = try super::resolveProgramStr(&mut res, program);
1214
            let error = try super::expectError(&result);
1215
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
1216
        }
1217
    }
1218
    {
1219
        let mut testArena46 = super::testArena();
1220
        let testStorage46: 'test46 = &mut testArena46 in {
1221
            let mut res = super::testResolver(testStorage46);
1222
            let result = try super::resolveProgramStr(&mut res,
1223
                "fn f 'r 's (s: Session 's) -> Session 'r where 'r: 's { return s; }");
1224
            let error = try super::expectError(&result);
1225
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1226
        }
1227
    }
1228
}
1229
1230
/// Regional `use` blocks require a mutable allocation trait implementer.
1231
@test unsafe fn testSessionSource() throws (testing::TestError) {
1232
    for program in [
1233
        "record Arena { data: *mut [u8], offset: u32 } fn f(arena: &mut Arena) { use *arena as s in {} }",
1234
        "fn f(value: &mut u32) { use *value as s in {} }",
1235
    ] {
1236
        let mut testArena47 = super::testArena();
1237
        let testStorage47: 'test47 = &mut testArena47 in {
1238
            let mut res = super::testResolver(testStorage47);
1239
            let result = try super::resolveSessionProgramStr(&mut res, program);
1240
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidSessionSource);
1241
        }
1242
    }
1243
    let mut customArena = super::testArena();
1244
    let customStorage: 'custom = &mut customArena in {
1245
        let mut res = super::testResolver(customStorage);
1246
        let result = try super::resolveSessionProgramStr(&mut res,
1247
            "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); } }");
1248
        try super::expectNoErrors(&result);
1249
    }
1250
}
1251
1252
/// Region-dependent values cannot be manufactured from uninitialized storage.
1253
@test unsafe fn testRegionalUndefined() throws (testing::TestError) {
1254
    for program in [
1255
        "unsafe fn f 'r () -> Session 'r { return undefined; }",
1256
        "record R: 'r { s: Session 'r } unsafe fn f 'r () -> R 'r { return undefined; }",
1257
        "unsafe fn f 'r () -> *unsafe Session 'r { return undefined; }",
1258
        "unsafe fn f 'r () -> &'r u32 { return undefined; }",
1259
    ] {
1260
        let mut testArena48 = super::testArena();
1261
        let testStorage48: 'test48 = &mut testArena48 in {
1262
            let mut res = super::testResolver(testStorage48);
1263
            let result = try super::resolveProgramStr(&mut res, program);
1264
            let error = try super::expectError(&result);
1265
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1266
        }
1267
    }
1268
}
1269
1270
/// Pointer casts cannot introduce session or aggregate region dependencies.
1271
@test unsafe fn testRegionalCastForgery() throws (testing::TestError) {
1272
    for program in [
1273
        "unsafe fn f 'r (p: *unsafe opaque) -> *unsafe Session 'r { return p as *unsafe Session 'r; }",
1274
        "unsafe fn f 'r (p: *unsafe [opaque]) -> *unsafe [Session 'r] { return p as *unsafe [Session 'r]; }",
1275
        "record R: 'r { s: Session 'r } unsafe fn f 'r (p: *unsafe opaque) -> *unsafe R 'r { return p as *unsafe R 'r; }",
1276
        "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; }",
1277
    ] {
1278
        let mut testArena49 = super::testArena();
1279
        let testStorage49: 'test49 = &mut testArena49 in {
1280
            let mut res = super::testResolver(testStorage49);
1281
            let result = try super::resolveProgramStr(&mut res, program);
1282
            let error = try super::expectError(&result);
1283
            let case resolver::ErrorKind::InvalidAsCast(_) = error.kind else throw testing::TestError::Failed;
1284
        }
1285
    }
1286
}
1287
1288
/// Bulk allocation rejects resources and values that need ownership cleanup.
1289
@test unsafe fn testSessionAllocationValue() throws (testing::TestError) {
1290
    for program in [
1291
        "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1292
        "record R: Once { n: u32 } unsafe fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1293
        "record R: Once { n: u32 } record Outer { value: R } fn f 'r (s: &Session 'r, value: Outer) { try! s.new(value); }",
1294
        "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: ?R) { try! s.new(value); }",
1295
        "fn f 'r (s: &Session 'r, value: Session 'r) { try! s.new(value); }",
1296
        "record R: Once { n: u32 } fn f 'r (s: &Session 'r, value: [R; 1]) { try! s.new(value); }",
1297
        "fn f 'r (s: &Session 'r, value: &'r mut u32) { try! s.fill(value, 2); }",
1298
        "fn f 'r (s: &Session 'r, value: &[&'r mut u32]) { try! s.copy(value); }",
1299
    ] {
1300
        let mut testArena50 = super::testArena();
1301
        let testStorage50: 'test50 = &mut testArena50 in {
1302
            let mut res = super::testResolver(testStorage50);
1303
            let result = try super::resolveSessionProgramStr(&mut res, program);
1304
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidAllocationValue);
1305
        }
1306
    }
1307
}
1308
1309
/// Allocated values must retain dependencies that cover the destination session.
1310
@test unsafe fn testSessionAllocationDependency() throws (testing::TestError) {
1311
    for program in [
1312
        "fn f 'r 's (a: &Session 'r, p: &'s u32) where 'r: 's { try! a.new(p); }",
1313
        "unsafe fn f 'r 's (a: &Session 'r, p: &'s u32) where 'r: 's { try! a.new(p); }",
1314
        "record R: 's + Copy { p: &'s u32 } fn f 'r 's (a: &Session 'r, p: R 's) where 'r: 's { try! a.new(p); }",
1315
        "fn f 'r 's (a: &Session 'r, p: &[&'s u32]) where 'r: 's { try! a.copy(p); }",
1316
    ] {
1317
        let mut testArena51 = super::testArena();
1318
        let testStorage51: 'test51 = &mut testArena51 in {
1319
            let mut res = super::testResolver(testStorage51);
1320
            let result = try super::resolveSessionProgramStr(&mut res, program);
1321
            let error = try super::expectError(&result);
1322
            let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed;
1323
        }
1324
    }
1325
}
1326
1327
/// Allocation operations require error handling and exact source region results.
1328
@test unsafe fn testSessionAllocationContract() throws (testing::TestError) {
1329
    {
1330
        let mut testArena52 = super::testArena();
1331
        let testStorage52: 'test52 = &mut testArena52 in {
1332
            let mut res = super::testResolver(testStorage52);
1333
            let result = try super::resolveSessionProgramStr(&mut res,
1334
                "fn f 'r (s: &Session 'r) { s.new(1 as u32); }");
1335
            try super::expectErrorKind(&result, resolver::ErrorKind::MissingTry);
1336
        }
1337
    }
1338
    {
1339
        let mut testArena53 = super::testArena();
1340
        let testStorage53: 'test53 = &mut testArena53 in {
1341
            let mut res = super::testResolver(testStorage53);
1342
            let result = try super::resolveSessionProgramStr(&mut res,
1343
                "fn f 'r 's (a: &Session 'r) -> &'s mut u32 { return try! a.new(1 as u32); }");
1344
            let error = try super::expectError(&result);
1345
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
1346
        }
1347
    }
1348
    {
1349
        let mut testArena54 = super::testArena();
1350
        let testStorage54: 'test54 = &mut testArena54 in {
1351
            let mut res = super::testResolver(testStorage54);
1352
            let result = try super::resolveSessionProgramStr(&mut res,
1353
                "fn f 'r (a: &Session 'r, p: &u32) { try! a.new(p); }");
1354
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidRefPosition);
1355
        }
1356
    }
1357
}
1358
1359
/// Typed reservations reject array products, aggregate sums, and field-offset overflow.
1360
@test unsafe fn testSessionAllocationLayout() throws (testing::TestError) {
1361
    for program in [
1362
        "fn f 'r (s: &Session 'r, value: [u64; 536870913]) { try! s.new(value); }",
1363
        "unsafe fn f 'r (s: &Session 'r, value: [u64; 536870913]) { try! s.new(value); }",
1364
        "record R { a: [u8; 4294967290], b: u64 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1365
        "record R { a: [u8; 2147483648], b: u8 } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1366
        "fn f 'r (s: &Session 'r, value: ?[u8; 4294967295]) { try! s.new(value); }",
1367
        "union R { Data([u8; 4294967295]) } fn f 'r (s: &Session 'r, value: R) { try! s.new(value); }",
1368
    ] {
1369
        let mut testArena55 = super::testArena();
1370
        let testStorage55: 'test55 = &mut testArena55 in {
1371
            let mut res = super::testResolver(testStorage55);
1372
            let result = try super::resolveSessionProgramStr(&mut res, program);
1373
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidAllocationLayout);
1374
        }
1375
    }
1376
}
1377
1378
/// Conditional bindings enforce moves through bodies and guards.
1379
@test unsafe fn testConditionalBindingMoves() throws (testing::TestError) {
1380
    for program in [
1381
        "record Token {} fn take(value: Token) {} fn f(value: ?Token) { if let item = value { take(item); take(item); } }",
1382
        "record Token {} fn take(value: Token) {} fn f(value: ?Token) { let item = value else return; take(item); take(item); }",
1383
        "record Token {} fn take(value: Token) {} fn next() -> ?Token { return Token {}; } fn f() { while let item = next() { take(item); take(item); } }",
1384
        "record Token {} fn take(value: Token) -> bool { return true; } fn f(value: ?Token) { if let item = value; take(item) { take(item); } }",
1385
        "record Token {} fn take(value: Token) {} unsafe fn f(value: ?Token) { if let item = value { take(item); take(item); } }",
1386
        "record Token {} record Box { item: Token } fn take(item: Token) -> bool { return true; } fn f(box: Box) { let case Box { item } = box if take(item) else return; take(item); }",
1387
        "record Token {} record Box { item: Token } fn take(item: Token) -> bool { return true; } unsafe fn f(box: Box) { let case Box { item } = box if take(item) else return; take(item); }",
1388
        "record Token {} union Box { Full(Token), Empty } fn take(item: Token) -> bool { return true; } fn f(box: Box) { let case Box::Full(item) = box if take(item) else return; take(item); }",
1389
    ] {
1390
        let mut storage = super::testArena();
1391
        let memory: 'test = &mut storage in {
1392
            let mut res = super::testResolver(memory);
1393
            let result = try super::resolveProgramStr(&mut res, program);
1394
            try super::expectErrorKind(&result, resolver::ErrorKind::AffineUseAfterMove("item"));
1395
        }
1396
    }
1397
}
1398
1399
/// Guard ownership distinguishes consumed fields, borrowed fields, and failure paths.
1400
@test unsafe fn testLetElseGuardOwnership() throws (testing::TestError) {
1401
    for program in [
1402
        "record Token {} record Box { item: Token } fn take(item: Token) -> bool { return true; } fn f(box: Box) { let case Box { item } = box if take(item) else return; }",
1403
        "record Token {} record Box { item: Token } fn read(item: &Token) -> bool { return true; } fn take(item: Token) {} fn f(box: Box) { let case Box { item } = box if read(&item) else return; take(item); }",
1404
        "union Box { Full(u32), Empty } fn f(box: Box) -> u32 { let case Box::Full(item) = box if item > 0 else return 0; return item; }",
1405
    ] {
1406
        let mut storage = super::testArena();
1407
        let memory: 'test = &mut storage in {
1408
            let mut res = super::testResolver(memory);
1409
            let result = try super::resolveProgramStr(&mut res, program);
1410
            try super::expectNoErrors(&result);
1411
        }
1412
    }
1413
    let mut storage = super::testArena();
1414
    let memory: 'test = &mut storage in {
1415
        let mut res = super::testResolver(memory);
1416
        let result = try super::resolveProgramStr(&mut res,
1417
            "record Token {} record Box { item: u32 } fn take(outer: Token) -> bool { return false; } fn f(box: Box, outer: Token) { let case Box { item } = box if take(outer) else { take(outer); return; }; }");
1418
        try super::expectErrorKind(&result, resolver::ErrorKind::AffineUseAfterMove("outer"));
1419
    }
1420
}
1421
1422
/// Fallback expressions cannot access their new binding before initialization.
1423
@test unsafe fn testLetElseFallbackBinding() throws (testing::TestError) {
1424
    for program in [
1425
        "fn f(input: ?u32) -> u32 { let value = input else value; return value; }",
1426
        "unsafe fn f(input: ?u32) -> u32 { let value = input else value; return value; }",
1427
        "fn f(input: ?u32) -> u32 { let mut value = input else { value }; return value; }",
1428
    ] {
1429
        let mut storage = super::testArena();
1430
        let memory: 'test = &mut storage in {
1431
            let mut res = super::testResolver(memory);
1432
            let result = try super::resolveProgramStr(&mut res, program);
1433
            try super::expectErrorKind(&result, resolver::ErrorKind::UnresolvedSymbol("value"));
1434
        }
1435
    }
1436
}
1437
1438
/// Each successful session allocation has distinct storage across loop iterations.
1439
@test unsafe fn testFreshAllocationLoopLoan() throws (testing::TestError) {
1440
    for program in [
1441
        "fn f 'r (s: &Session 'r) { for i in 0..3 { let p = try! s.fill(0 as u32, 2); set p[0] = i; let view: &'r [u32] = &p[..]; } }",
1442
        "fn f 'r (s: &Session 'r) { let mut i: u32 = 0; while i < 3 { let p = try! s.new(0 as u32); set *p = i; let view: &'r u32 = &*p; set i += 1; } }",
1443
        "fn f 'r (s: &Session 'r) { for i in 0..3 { if let p = try? s.fill(0 as u32, 2); p.len == 2 { set p[0] = i; let view: &'r [u32] = &p[..]; } } }",
1444
        "fn f 'r (s: &Session 'r) { while let p = try? s.new(0 as u32) { set *p = 1; let view: &'r u32 = &*p; } }",
1445
        "fn f 'r (s: &Session 'r) { loop { let p = try? s.new(0 as u32) else break; set *p = 1; let view: &'r u32 = &*p; } }",
1446
        "fn f 'r (s: &Session 'r) { for i in 0..3 { if let _ = try? s.new(0 as u32) {} let _ = try! s.new(0 as u32); } }",
1447
    ] {
1448
        let mut storage = super::testArena();
1449
        let memory: 'test = &mut storage in {
1450
            let mut res = super::testResolver(memory);
1451
            let result = try super::resolveSessionProgramStr(&mut res, program);
1452
            try super::expectNoErrors(&result);
1453
        }
1454
    }
1455
}
1456
1457
/// Fresh allocations preserve loans on aliases and existing storage.
1458
@test unsafe fn testFreshAllocationRetainsOtherLoans() throws (testing::TestError) {
1459
    for program in [
1460
        "fn f 'r (s: &Session 'r) { for i in 0..3 { let p = try! s.fill(0 as u32, 2); let view: &'r [u32] = &p[..]; set p[0] = i; } }",
1461
        "fn f 'r (s: &Session 'r) { let p = try! s.fill(0 as u32, 2); for i in 0..3 { set p[0] = i; let view: &'r [u32] = &p[..]; } }",
1462
        "fn f 'r (s: &Session 'r, p: &'r mut u32) { for i in 0..3 { let view: &'r u32 = &*p; let fresh = try! s.new(0 as u32); set *p = i; } }",
1463
        "fn f 'r (s: &Session 'r, p: &'r mut u32) { for i in 0..3 { let fresh = try! s.new(&*p); set *p = i; } }",
1464
        "fn f 'r (s: &Session 'r) { while let p = try? s.new(0 as u32) { let view: &'r u32 = &*p; set *p = 1; } }",
1465
        "fn f 'r (s: &Session 'r) { for i in 0..3 { if let p = try? s.new(0 as u32) { let view: &'r u32 = &*p; set *p = i; } } }",
1466
        "fn f 'r (s: &Session 'r) { loop { let p = try? s.new(0 as u32) else break; let view: &'r u32 = &*p; set *p = 1; } }",
1467
        "fn check 'r (p: &'r u32) -> bool { return *p == 0; } fn f 'r (s: &Session 'r) { while let p = try? s.new(0 as u32); check(&*p) { set *p = 1; } }",
1468
    ] {
1469
        let mut storage = super::testArena();
1470
        let memory: 'test = &mut storage in {
1471
            let mut res = super::testResolver(memory);
1472
            let result = try super::resolveSessionProgramStr(&mut res, program);
1473
            try super::expectErrorKind(&result, resolver::ErrorKind::BorrowConflict("p"));
1474
        }
1475
    }
1476
}
1477
1478
/// Cell references give indirect cycles finite layouts in each declaration order.
1479
@test unsafe fn testRecursiveCellLayout() throws (testing::TestError) {
1480
    for program in [
1481
        "record V: 'r + Copy { n: N 'r } record N: 'r + Copy { s: &'r cell S 'r } union S: 'r + Copy { Ready(V 'r), Pending }",
1482
        "union S: 'r + Copy { Ready(V 'r), Pending } record V: 'r + Copy { n: N 'r } record N: 'r + Copy { s: &'r cell S 'r }",
1483
        "record N: 'r + Copy { s: &'r cell S 'r } union S: 'r + Copy { Ready(V 'r), Pending } record V: 'r + Copy { n: N 'r }",
1484
        "record V: Copy { n: N } record N: Copy { s: *cell S } union S: Copy { Ready(V), Pending }",
1485
    ] {
1486
        let mut storage = super::testArena();
1487
        let memory: 'test = &mut storage in {
1488
            let mut res = super::testResolver(memory);
1489
            let result = try super::resolveProgramStr(&mut res, program);
1490
            try super::expectNoErrors(&result);
1491
        }
1492
    }
1493
}
1494
1495
/// Deferred cell checks reject invalid payloads without a payload access.
1496
@test unsafe fn testDeferredCellPayload() throws (testing::TestError) {
1497
    for program in [
1498
        "record N: 'r + Copy { s: &'r cell S 'r } union S: 'r { Ready(N 'r), Pending }",
1499
        "record N: Copy { s: *cell S } record S { value: u32 }",
1500
    ] {
1501
        let mut storage = super::testArena();
1502
        let memory: 'test = &mut storage in {
1503
            let mut res = super::testResolver(memory);
1504
            let result = try super::resolveProgramStr(&mut res, program);
1505
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload);
1506
        }
1507
    }
1508
    let mut storage = super::testArena();
1509
    let memory: 'test = &mut storage in {
1510
        let mut res = super::testResolver(memory);
1511
        let result = try super::resolveProgramStr(&mut res,
1512
            "record N: Copy { s: *cell S } record S: Copy { bytes: [u64; 536870913] }");
1513
        try super::expectErrorKind(&result, resolver::ErrorKind::InvalidAllocationLayout);
1514
    }
1515
}
1516
1517
/// Cell payloads must permit plain value copies.
1518
@test unsafe fn testCellPointerPayload() throws (testing::TestError) {
1519
    for program in [
1520
        "union State: 'r { Next(&'r cell State 'r) }",
1521
        "union State: 'r { Ready(&'r u32) } fn f 'r (state: &'r cell State 'r) {}",
1522
        "union State: 'r { Ready(&'r u32) } unsafe fn f 'r (state: &'r cell State 'r) {}",
1523
        "fn f(p: *cell *mut u32) {}",
1524
        "unsafe fn f(p: *cell *mut u32) {}",
1525
        "record R: Once { n: u32 } fn f(p: *cell R) {}",
1526
        "record R { n: u32 } fn f(p: *cell R) {}",
1527
        "fn f 'r (p: &'r cell &'r mut u32) {}",
1528
    ] {
1529
        let mut testArena56 = super::testArena();
1530
        let testStorage56: 'test56 = &mut testArena56 in {
1531
            let mut res = super::testResolver(testStorage56);
1532
            let result = try super::resolveProgramStr(&mut res, program);
1533
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload);
1534
        }
1535
    }
1536
}
1537
1538
/// Direct cell borrows support Copy values, scoped loans, and call arguments.
1539
@test unsafe fn testCellBorrow() throws (testing::TestError) {
1540
    for program in [
1541
        "fn f() -> u32 { let mut n: u32 = 0; { let c = &cell n; let alias = c; set *c = 1; set *alias += 1; } return n; }",
1542
        "fn read(c: &cell u32) { set *c = 1; } fn f(p: &mut u32) { read(&cell *p); set *p = 2; }",
1543
        "fn f() { let mut n: u32 = 0; let c: 'r = &cell n in { let alias = c; set *alias = 1; } set n = 2; }",
1544
        "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; }",
1545
        "fn f() { let mut a: [u32; 2] = [0, 0]; let c = &cell a; set *c = [1, 2]; let snapshot = *c; }",
1546
        "fn forward(p: *mut u32) -> *mut u32 { return p; } fn f(p: *mut u32) -> *cell u32 { return &cell *forward(p); }",
1547
        "record R: Copy { n: u32 } fn f(p: *mut R) -> *cell u32 { return &cell p.n; }",
1548
        "fn f(p: *mut [u32]) -> *cell u32 { return &cell p[0]; }",
1549
    ] {
1550
        let mut arena = super::testArena();
1551
        let storage: 'test = &mut arena in {
1552
            let mut res = super::testResolver(storage);
1553
            let result = try super::resolveProgramStr(&mut res, program);
1554
            try super::expectNoErrors(&result);
1555
        }
1556
    }
1557
}
1558
1559
/// Permission-associated cells support construction, direct access, and sequential mutation.
1560
@test unsafe fn testPermissionCellConstruction() throws (testing::TestError) {
1561
    for program in [
1562
        // Initialized exclusive Copy storage construction.
1563
        "record Permit {} fn f() { let mut owner = Permit {}; let permission: 'permission = &mut owner in { let mut value: u32 = 0; let cell: &cell 'permission u32 = &cell 'permission value; set *cell = 1; let copy = *cell; } }",
1564
        // Sequential mutation after each previous access has ended.
1565
        "record Permit {} fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { set *cell = 1; let first = *cell; set *cell = first + 1; let second = *cell; }",
1566
    ] {
1567
        let mut arena = super::testArena();
1568
        let storage: 'test = &mut arena in {
1569
            let mut res = super::testResolver(storage);
1570
            let result = try super::resolveProgramStr(&mut res, program);
1571
            try super::expectNoErrors(&result);
1572
        }
1573
    }
1574
}
1575
1576
/// Associated cell construction requires active authority for its permission region.
1577
@test unsafe fn testPermissionCellConstructionAuthority() throws (testing::TestError) {
1578
    let mut arena = super::testArena();
1579
    let storage: 'test = &mut arena in {
1580
        let mut res = super::testResolver(storage);
1581
        let result = try super::resolveProgramStr(&mut res,
1582
            "record Permit {} fn f 'permission (place: &mut u32, owner: Permit) { let cell: &cell 'permission u32 = &cell 'permission *place; }");
1583
        let error = try super::expectError(&result);
1584
        let case resolver::ErrorKind::CellPermissionRequired(_) = error.kind
1585
            else throw testing::TestError::Failed;
1586
    }
1587
}
1588
1589
/// Matching authority permits shared and mutable payload loans and ordinary helper calls.
1590
@test unsafe fn testPermissionCellPayloadLoans() throws (testing::TestError) {
1591
    for program in [
1592
        // A shared payload reference can be passed to an ordinary helper.
1593
        "record Permit {} fn observe(value: &u32) {} fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let authority: 'loan = &*permission, payload = &*cell in { observe(payload); } }",
1594
        // A mutable payload reference can be passed to an ordinary `&mut` helper.
1595
        "record Permit {} fn increment(value: &mut u32) { set *value += 1; } fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let authority: 'loan = &mut *permission, payload = &mut *cell in { increment(payload); } }",
1596
        // Cell aliases retain authority and may create multiple simultaneous readers.
1597
        "record Permit {} fn observe(value: &u32) {} fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let alias = cell; let authority: 'loan = &*permission, first = &*cell, second = &*alias in { observe(first); observe(second); } }",
1598
    ] {
1599
        let mut arena = super::testArena();
1600
        let storage: 'test = &mut arena in {
1601
            let mut res = super::testResolver(storage);
1602
            let result = try super::resolveProgramStr(&mut res, program);
1603
            try super::expectNoErrors(&result);
1604
        }
1605
    }
1606
}
1607
1608
/// Aliasing, generic substitution, and storage shortening preserve the permission association.
1609
@test unsafe fn testPermissionCellSubstitution() throws (testing::TestError) {
1610
    for program in [
1611
        // An inferred generic call substitutes both storage and permission regions.
1612
        "record Permit {} fn identity 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) -> &'storage cell 'permission u32 { return cell; } fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let alias = cell; let instantiated = identity(alias, permission); }",
1613
        // Shortening storage leaves the independent permission region unchanged.
1614
        "record Permit {} fn shorten 'storage 'short 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) -> &'short cell 'permission u32 where 'storage: 'short { return cell; }",
1615
    ] {
1616
        let mut arena = super::testArena();
1617
        let storage: 'test = &mut arena in {
1618
            let mut res = super::testResolver(storage);
1619
            let result = try super::resolveProgramStr(&mut res, program);
1620
            try super::expectNoErrors(&result);
1621
        }
1622
    }
1623
}
1624
1625
/// Calls may reuse authority when a helper's permission contract does not return it.
1626
@test unsafe fn testPermissionCellAuthorityCallReuse() throws (testing::TestError) {
1627
    {
1628
        let mut arena = super::testArena();
1629
        let storage: 'test = &mut arena in {
1630
            let mut res = super::testResolver(storage);
1631
            let result = try super::resolveProgramStr(&mut res,
1632
                "record Permit {} fn inspect 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) -> u32 { return *cell; } fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let first = inspect(cell, permission); let second = inspect(cell, permission); }");
1633
            try super::expectNoErrors(&result);
1634
        }
1635
    }
1636
    {
1637
        let mut arena = super::testArena();
1638
        let storage: 'test = &mut arena in {
1639
            let mut res = super::testResolver(storage);
1640
            let result = try super::resolveProgramStr(&mut res,
1641
                "record Permit {} fn retain 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) -> &'permission mut Permit { let value = *cell; return permission; } fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let retained = retain(cell, permission); retain(cell, permission); }");
1642
            let error = try super::expectError(&result);
1643
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind
1644
                else throw testing::TestError::Failed;
1645
        }
1646
    }
1647
    {
1648
        let mut arena = super::testArena();
1649
        let storage: 'test = &mut arena in {
1650
            let mut res = super::testResolver(storage);
1651
            let result = try super::resolveProgramStr(&mut res,
1652
                "record Permit {} fn retainIn 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit, out: &mut ?&'permission mut Permit) { let value = *cell; set *out = permission; } fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit, firstOut: &mut ?&'permission mut Permit, secondOut: &mut ?&'permission mut Permit) { retainIn(cell, permission, firstOut); retainIn(cell, permission, secondOut); }");
1653
            let error = try super::expectError(&result);
1654
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind
1655
                else throw testing::TestError::Failed;
1656
        }
1657
    }
1658
    {
1659
        let mut arena = super::testArena();
1660
        let storage: 'test = &mut arena in {
1661
            let mut res = super::testResolver(storage);
1662
            let result = try super::resolveProgramStr(&mut res,
1663
                "record Permit {} fn inspect 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) -> u32 { return *cell; } fn retainIn 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit, storage: &'permission mut ?&'permission mut Permit) { let value = *cell; set *storage = permission; } fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit, authorityStorage: &'permission mut ?&'permission mut Permit) { retainIn(cell, permission, authorityStorage); inspect(cell, permission); }");
1664
            let error = try super::expectError(&result);
1665
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind
1666
                else throw testing::TestError::Failed;
1667
        }
1668
    }
1669
}
1670
1671
/// Fresh allocation does not reclaim storage and remains valid during a shared payload loan.
1672
@test unsafe fn testPermissionCellFreshAllocation() throws (testing::TestError) {
1673
    let mut arena = super::testArena();
1674
    let storage: 'test = &mut arena in {
1675
        let mut res = super::testResolver(storage);
1676
        let result = try super::resolveSessionProgramStr(&mut res,
1677
            "record Permit {} fn f 'storage 'permission (session: &Session 'storage, cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let authority: 'loan = &*permission, payload = &*cell in { let fresh = try! session.new(2 as u32); set *fresh = *payload; } }");
1678
        try super::expectNoErrors(&result);
1679
    }
1680
}
1681
1682
/// Cell permission metadata does not make a session allocation depend on shorter authority.
1683
@test unsafe fn testPermissionCellSessionNominalDependency() throws (testing::TestError) {
1684
    let mut arena = super::testArena();
1685
    let storage: 'test = &mut arena in {
1686
        let mut res = super::testResolver(storage);
1687
        let result = try super::resolveSessionProgramStr(&mut res,
1688
            "record Permit {} record Block: 'storage + 'permission + Copy { cell: &'storage cell 'permission u32 } fn f 'storage (session: &Session 'storage) { let mut owner = Permit {}; let permission: 'permission = &mut owner in { let place = try! session.new(1 as u32); let cell: &'storage cell 'permission u32 = &cell 'permission *place; let block = try! session.new(Block 'storage 'permission { cell }); } }");
1689
        try super::expectNoErrors(&result);
1690
    }
1691
}
1692
1693
/// Associated Copy cells can form finite-layout cycles under one permission.
1694
@test unsafe fn testPermissionCellCycles() throws (testing::TestError) {
1695
    let mut arena = super::testArena();
1696
    let storage: 'test = &mut arena in {
1697
        let mut res = super::testResolver(storage);
1698
        let result = try super::resolveProgramStr(&mut res,
1699
            "record Left: 'storage + 'permission + Copy { right: &'storage cell 'permission Right 'storage 'permission } record Right: 'storage + 'permission + Copy { left: &'storage cell 'permission Left 'storage 'permission }");
1700
        try super::expectNoErrors(&result);
1701
    }
1702
}
1703
1704
/// Owned cell payloads ignore nested permission-only metadata but retain storage dependencies.
1705
@test unsafe fn testPermissionCellOwnedNestedPayloadRegions() throws (testing::TestError) {
1706
    {
1707
        let mut arena = super::testArena();
1708
        let storage: 'test = &mut arena in {
1709
            let mut res = super::testResolver(storage);
1710
            let result = try super::resolveProgramStr(&mut res,
1711
                "record Permit {} record Payload: 'permission + Copy { nested: *cell 'permission u32 } fn f 'permission (place: *mut Payload 'permission, permission: &'permission mut Permit) -> *cell Payload 'permission { return &cell *place; }");
1712
            try super::expectNoErrors(&result);
1713
        }
1714
    }
1715
    {
1716
        let mut arena = super::testArena();
1717
        let storage: 'test = &mut arena in {
1718
            let mut res = super::testResolver(storage);
1719
            let result = try super::resolveProgramStr(&mut res,
1720
                "record Payload: 'storage + Copy { nested: &'storage cell u32 } fn f 'storage (place: *mut Payload 'storage) -> *cell Payload 'storage { return &cell *place; }");
1721
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload);
1722
        }
1723
    }
1724
}
1725
1726
/// Resolved cell metadata keeps storage and permission identities distinct through substitution.
1727
@test unsafe fn testPermissionCellTypeMetadata() throws (testing::TestError) {
1728
    let mut arena = super::testArena();
1729
    let storage: 'test = &mut arena in {
1730
        let mut res = super::testResolver(storage);
1731
        let result = try super::resolveProgramStr(&mut res,
1732
            "record Permit {} fn identity 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) -> &'storage cell 'permission u32 { return cell; } fn inspect 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let alias = cell; let instantiated = identity(alias, permission); }");
1733
        try super::expectNoErrors(&result);
1734
1735
        let inspect = try super::getBlockStmt(result.root, 2);
1736
        let inspectType = resolver::typeFor(&res, inspect) else throw testing::TestError::Failed;
1737
        let case resolver::Type::Fn(info) = inspectType else throw testing::TestError::Failed;
1738
        let case resolver::Type::Cell {
1739
            class: types::PointerClass::Region(storageRegion),
1740
            permission: declaredPermission,
1741
            payload: declaredPayload,
1742
        } = *info.paramTypes[0] else throw testing::TestError::Failed;
1743
        let permissionRegion = declaredPermission else throw testing::TestError::Failed;
1744
        let case resolver::Type::Pointer {
1745
            class: types::PointerClass::Region(authorityRegion),
1746
            target: _,
1747
            mutable: true,
1748
        } = *info.paramTypes[1] else throw testing::TestError::Failed;
1749
        try testing::expect(storageRegion.id <> permissionRegion.id);
1750
        try testing::expect(authorityRegion.id == permissionRegion.id);
1751
        try testing::expect(*declaredPayload == resolver::Type::U32);
1752
1753
        let case ast::NodeValue::FnDecl(decl) = inspect.value else throw testing::TestError::Failed;
1754
        let body = decl.body else throw testing::TestError::Failed;
1755
        let case ast::NodeValue::Let(aliasDecl) =
1756
            (try super::getBlockStmt(body, 0)).value else throw testing::TestError::Failed;
1757
        let case ast::NodeValue::Let(instantiatedDecl) =
1758
            (try super::getBlockStmt(body, 1)).value else throw testing::TestError::Failed;
1759
        let aliasType = resolver::typeFor(&res, aliasDecl.value) else throw testing::TestError::Failed;
1760
        let instantiatedType = resolver::typeFor(&res, instantiatedDecl.value)
1761
            else throw testing::TestError::Failed;
1762
        let case resolver::Type::Cell {
1763
            class: types::PointerClass::Region(aliasStorage),
1764
            permission: aliasPermission,
1765
            ..
1766
        } = aliasType else throw testing::TestError::Failed;
1767
        let case resolver::Type::Cell {
1768
            class: types::PointerClass::Region(instantiatedStorage),
1769
            permission: instantiatedPermission,
1770
            ..
1771
        } = instantiatedType else throw testing::TestError::Failed;
1772
        let aliasPermissionRegion = aliasPermission else throw testing::TestError::Failed;
1773
        let instantiatedPermissionRegion = instantiatedPermission else throw testing::TestError::Failed;
1774
        try testing::expect(aliasStorage.id == storageRegion.id);
1775
        try testing::expect(instantiatedStorage.id == storageRegion.id);
1776
        try testing::expect(aliasPermissionRegion.id == permissionRegion.id);
1777
        try testing::expect(instantiatedPermissionRegion.id == permissionRegion.id);
1778
    }
1779
}
1780
1781
/// Permission-wide loans reject conflicting accesses through every cell alias.
1782
@test unsafe fn testPermissionCellAliasConflicts() throws (testing::TestError) {
1783
    for program in [
1784
        // Two aliases cannot produce overlapping mutable payload references.
1785
        "record Permit {} fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let alias = cell; let authority: 'loan = &mut *permission, first = &mut *cell, second = &mut *alias in {} }",
1786
        // A shared payload loan suspends mutation through another alias.
1787
        "record Permit {} fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let alias = cell; let authority: 'loan = &*permission, payload = &*cell in { set *alias = 1; let value = *payload; } }",
1788
    ] {
1789
        let mut arena = super::testArena();
1790
        let storage: 'test = &mut arena in {
1791
            let mut res = super::testResolver(storage);
1792
            let result = try super::resolveProgramStr(&mut res, program);
1793
            let error = try super::expectError(&result);
1794
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
1795
                else throw testing::TestError::Failed;
1796
        }
1797
    }
1798
}
1799
/// Call argument loans preserve permission identity across distinct cell handles.
1800
@test unsafe fn testPermissionCellCallArgumentAliasConflict() throws (testing::TestError) {
1801
    let mut arena = super::testArena();
1802
    let storage: 'test = &mut arena in {
1803
        let mut res = super::testResolver(storage);
1804
        let result = try super::resolveProgramStr(&mut res,
1805
            "record Permit {} fn both(first: &u32, second: &mut u32) {} fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let alias = cell; let authority: 'loan = &mut *permission where 'permission: 'loan in { both(&*cell, &mut *alias); } }");
1806
        try super::expectErrorKind(&result, resolver::ErrorKind::BorrowConflict("alias"));
1807
    }
1808
}
1809
1810
/// Wrapped local payload loans preserve permission identity.
1811
@test unsafe fn testPermissionCellWrappedLocalLoanConflict() throws (testing::TestError) {
1812
    let mut arena = super::testArena();
1813
    let storage: 'test = &mut arena in {
1814
        let mut res = super::testResolver(storage);
1815
        let result = try super::resolveProgramStr(&mut res,
1816
            "record Permit {} fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let alias = cell; let authority: 'loan = &*permission where 'permission: 'loan in { let payload = &*cell as &u32; set *alias = 1; let value = *payload; } }");
1817
        let error = try super::expectError(&result);
1818
        let case resolver::ErrorKind::BorrowConflict(_) = error.kind
1819
            else throw testing::TestError::Failed;
1820
    }
1821
}
1822
/// Sessions nested in cell payloads retain consumed permission authority.
1823
@test unsafe fn testPermissionCellNestedSessionRetention() throws (testing::TestError) {
1824
    let mut arena = super::testArena();
1825
    let storage: 'test = &mut arena in {
1826
        let mut res = super::testResolver(storage);
1827
        let result = try super::resolveSessionProgramStr(&mut res,
1828
            "record Permit {} fn retain 'storage 'session 'permission (holder: &'storage cell 'permission &'session mut Session 'permission, permission: &'permission mut Permit) { let stored = try! (*holder).new(permission); } fn f 'storage 'session 'permission (holder: &'storage cell 'permission &'session mut Session 'permission, permission: &'permission mut Permit) { retain(holder, permission); retain(holder, permission); }");
1829
        try super::expectErrorKind(
1830
            &result, resolver::ErrorKind::AffineUseAfterMove("permission"),
1831
        );
1832
    }
1833
}
1834
1835
1836
/// Associated cell projections support replacement under matching authority.
1837
@test unsafe fn testPermissionCellProjectedReplacement() throws (testing::TestError) {
1838
    for program in [
1839
        "record Permit {} record Payload { value: u32 } fn f 'storage 'permission (cell: &'storage cell 'permission Payload, permission: &'permission mut Permit) { set (*cell).value = 1; }",
1840
        "record Permit {} fn f 'storage 'permission (cell: &'storage cell 'permission [u32; 2], permission: &'permission mut Permit) { set (*cell)[0] = 1; }",
1841
        "record Permit {} fn f 'storage 'permission (cell: &'storage cell 'permission [u32; 2], permission: &'permission mut Permit) { set (*cell)[0..1] = 0; }",
1842
    ] {
1843
        let mut arena = super::testArena();
1844
        let storage: 'test = &mut arena in {
1845
            let mut res = super::testResolver(storage);
1846
            let result = try super::resolveProgramStr(&mut res, program);
1847
            try super::expectNoErrors(&result);
1848
        }
1849
    }
1850
}
1851
1852
1853
/// Permission identities are invariant across access, relabeling, and storage shortening.
1854
@test unsafe fn testPermissionCellAssociationMismatch() throws (testing::TestError) {
1855
    {
1856
        let mut arena = super::testArena();
1857
        let storage: 'test = &mut arena in {
1858
            let mut res = super::testResolver(storage);
1859
            // Cross-permission access fails generic region inference.
1860
            let result = try super::resolveProgramStr(&mut res,
1861
                "record Permit {} fn access 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) -> u32 { return *cell; } fn cross 'storage 'first 'second (cell: &'storage cell 'first u32, first: &'first mut Permit, second: &'second mut Permit) { access(cell, second); }");
1862
            let error = try super::expectError(&result);
1863
            let case resolver::ErrorKind::RegionInference(_) = error.kind
1864
                else throw testing::TestError::Failed;
1865
        }
1866
    }
1867
    for program in [
1868
        // An explicit annotation cannot relabel a permission.
1869
        "record Permit {} fn f 'storage 'first 'second (cell: &'storage cell 'first u32, first: &'first mut Permit, second: &'second mut Permit) { let relabeled: &'storage cell 'second u32 = cell; }",
1870
        // Storage shortening cannot change the permission association.
1871
        "record Permit {} fn f 'storage 'short 'first 'second (cell: &'storage cell 'first u32, first: &'first mut Permit, second: &'second mut Permit) where 'storage: 'short { let relabeled: &'short cell 'second u32 = cell; }",
1872
        // Storage shortening cannot drop the permission association.
1873
        "record Permit {} fn f 'storage 'short 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) where 'storage: 'short { let unassociated: &'short cell u32 = cell; }",
1874
    ] {
1875
        let mut arena = super::testArena();
1876
        let storage: 'test = &mut arena in {
1877
            let mut res = super::testResolver(storage);
1878
            let result = try super::resolveProgramStr(&mut res, program);
1879
            let error = try super::expectError(&result);
1880
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind
1881
                else throw testing::TestError::Failed;
1882
        }
1883
    }
1884
}
1885
1886
/// Distinct formal permissions cannot substitute the same actual permission identity.
1887
@test unsafe fn testPermissionCellDistinctGenericArguments() throws (testing::TestError) {
1888
    let mut arena = super::testArena();
1889
    let storage: 'test = &mut arena in {
1890
        let mut res = super::testResolver(storage);
1891
        let result = try super::resolveProgramStr(&mut res,
1892
            "record Permit {} fn separate 'storage 'left 'right (first: &'storage cell 'left u32, left: &'left mut Permit, second: &'storage cell 'right u32, right: &'right mut Permit) {} fn f 'storage 'permission (first: &'storage cell 'permission u32, second: &'storage cell 'permission u32, permission: &'permission mut Permit) { separate 'storage 'permission 'permission(first, permission, second, permission); }");
1893
        let error = try super::expectError(&result);
1894
        let case resolver::ErrorKind::RegionInference(_) = error.kind
1895
            else throw testing::TestError::Failed;
1896
    }
1897
}
1898
1899
/// Applied nominal fields preserve distinct formal permission identities at calls.
1900
@test unsafe fn testPermissionCellNominalGenericArguments() throws (testing::TestError) {
1901
    {
1902
        let mut arena = super::testArena();
1903
        let storage: 'test = &mut arena in {
1904
            let mut res = super::testResolver(storage);
1905
            let result = try super::resolveProgramStr(&mut res,
1906
                "record Permit {} record Wrapper: 'storage + 'permission + Copy { cell: &'storage cell 'permission u32 } fn separate 'storage 'left 'right (first: Wrapper 'storage 'left, left: &'left mut Permit, second: Wrapper 'storage 'right, right: &'right mut Permit) {} fn f 'storage 'left 'right (first: Wrapper 'storage 'left, left: &'left mut Permit, second: Wrapper 'storage 'right, right: &'right mut Permit) { separate(first, left, second, right); }");
1907
            try super::expectNoErrors(&result);
1908
        }
1909
    }
1910
    {
1911
        let mut arena = super::testArena();
1912
        let storage: 'test = &mut arena in {
1913
            let mut res = super::testResolver(storage);
1914
            let result = try super::resolveProgramStr(&mut res,
1915
                "record Permit {} record Wrapper: 'storage + 'permission + Copy { cell: &'storage cell 'permission u32 } fn separate 'storage 'left 'right (first: Wrapper 'storage 'left, left: &'left mut Permit, second: Wrapper 'storage 'right, right: &'right mut Permit) {} fn f 'storage 'permission (first: Wrapper 'storage 'permission, second: Wrapper 'storage 'permission, permission: &'permission mut Permit) { separate(first, permission, second, permission); }");
1916
            let error = try super::expectError(&result);
1917
            let case resolver::ErrorKind::RegionInference(_) = error.kind
1918
                else throw testing::TestError::Failed;
1919
        }
1920
    }
1921
}
1922
1923
/// Direct and callback cell accesses cannot conflict with a live payload loan.
1924
@test unsafe fn testPermissionCellCallConflicts() throws (testing::TestError) {
1925
    for program in [
1926
        // Direct call.
1927
        "record Permit {} fn mutate 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { set *cell = 1; } fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let authority: 'loan = &*permission, payload = &*cell in { mutate(cell, permission); let value = *payload; } }",
1928
        // Region-instantiated callback.
1929
        "record Permit {} fn mutate 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { set *cell = 1; } fn f 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let callback = mutate 'storage 'permission; let authority: 'loan = &*permission, payload = &*cell in { callback(cell, permission); let value = *payload; } }",
1930
    ] {
1931
        let mut arena = super::testArena();
1932
        let storage: 'test = &mut arena in {
1933
            let mut res = super::testResolver(storage);
1934
            let result = try super::resolveProgramStr(&mut res, program);
1935
            let error = try super::expectError(&result);
1936
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
1937
                else throw testing::TestError::Failed;
1938
        }
1939
    }
1940
}
1941
1942
/// Payload references cannot escape their matching permission loan.
1943
@test unsafe fn testPermissionCellLoanEscape() throws (testing::TestError) {
1944
    let mut arena = super::testArena();
1945
    let storage: 'test = &mut arena in {
1946
        let mut res = super::testResolver(storage);
1947
        let result = try super::resolveProgramStr(&mut res,
1948
            "record Permit {} fn escape 'storage 'permission (cell: &'storage cell 'permission u32, permission: &'permission mut Permit) -> &'storage u32 { let authority: 'loan = &*permission, payload = &*cell in { return payload; } }");
1949
        let error = try super::expectError(&result);
1950
        let case resolver::ErrorKind::RegionEscape(_) = error.kind
1951
            else throw testing::TestError::Failed;
1952
    }
1953
}
1954
1955
/// Allocation-session escape and reset remain invalid while an associated payload reference is live.
1956
@test unsafe fn testPermissionCellStorageLiveness() throws (testing::TestError) {
1957
    {
1958
        let mut arena = super::testArena();
1959
        let storage: 'test = &mut arena in {
1960
            let mut res = super::testResolver(storage);
1961
            // A payload reference cannot escape the allocation session that owns its cell storage.
1962
            let result = try super::resolveSessionProgramStr(&mut res,
1963
                "use std::lang::alloc; record Permit {} fn escape 'arena (arena: &'arena mut alloc::Arena) -> &'arena u32 { let mut owner = Permit {}; let permission: 'permission = &mut owner in { use *arena as session in { let place = try! session.new(1 as u32); let cell = &cell 'permission *place; let authority: 'loan = &*permission, payload = &*cell in { return payload; } } } }");
1964
            let error = try super::expectError(&result);
1965
            let case resolver::ErrorKind::RegionEscape(_) = error.kind
1966
                else throw testing::TestError::Failed;
1967
        }
1968
    }
1969
    {
1970
        let mut arena = super::testArena();
1971
        let storage: 'test = &mut arena in {
1972
            let mut res = super::testResolver(storage);
1973
            // Reset cannot reclaim a cell's storage while its payload reference is live.
1974
            let result = try super::resolveSessionProgramStr(&mut res,
1975
                "use std::lang::alloc; record Permit {} fn reset 'storage 'permission (arena: &'storage mut alloc::Arena, cell: &'storage cell 'permission u32, permission: &'permission mut Permit) { let authority: 'loan = &*permission, payload = &*cell in { alloc::reset(arena); let value = *payload; } }");
1976
            let error = try super::expectError(&result);
1977
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
1978
                else throw testing::TestError::Failed;
1979
        }
1980
    }
1981
}
1982
1983
/// Permission-associated cells admit affine values that are safe for bulk reclamation.
1984
@test unsafe fn testPermissionCellAffinePayload() throws (testing::TestError) {
1985
    for program in [
1986
        // Construction accepts an affine, bulk-discardable record.
1987
        "record Permit {} record Payload { value: u32 } fn f 'permission (place: &mut Payload, permission: &'permission mut Permit) { let cell: &cell 'permission Payload = &cell 'permission *place; }",
1988
        // Matching shared authority permits an ordinary shared payload loan.
1989
        "record Permit {} record Payload { value: u32 } fn observe(value: &Payload) {} fn f 'storage 'permission (cell: &'storage cell 'permission Payload, permission: &'permission mut Permit) { let authority: 'loan = &*permission, payload = &*cell in { observe(payload); } }",
1990
        // Matching mutable authority permits an ordinary mutable helper call.
1991
        "record Permit {} record Payload { value: u32 } fn increment(value: &mut Payload) { set value.value += 1; } fn f 'storage 'permission (cell: &'storage cell 'permission Payload, permission: &'permission mut Permit) { let authority: 'loan = &mut *permission, payload = &mut *cell in { increment(payload); } }",
1992
        // Replacement evaluates the new value from the old payload before overwriting it.
1993
        "record Permit {} record Payload { value: u32 } fn replacement(value: &Payload) -> Payload { return Payload { value: value.value + 1 }; } fn f 'storage 'permission (cell: &'storage cell 'permission Payload, permission: &'permission mut Permit) { set *cell = replacement(&*cell); }",
1994
    ] {
1995
        let mut arena = super::testArena();
1996
        let storage: 'test = &mut arena in {
1997
            let mut res = super::testResolver(storage);
1998
            let result = try super::resolveProgramStr(&mut res, program);
1999
            try super::expectNoErrors(&result);
2000
        }
2001
    }
2002
}
2003
2004
/// Cell payload eligibility remains narrow without a bulk-discardable permission association.
2005
@test unsafe fn testPermissionCellAffinePayloadEligibility() throws (testing::TestError) {
2006
    for program in [
2007
        // An unassociated cell still requires a Copy payload.
2008
        "record Payload { value: u32 } fn f(place: &mut Payload) { let cell = &cell *place; }",
2009
        // A linear payload cannot be discarded by replacement or arena reclamation.
2010
        "record Permit {} record Payload: Once { value: u32 } fn f 'permission (place: &mut Payload, permission: &'permission mut Permit) { let cell: &cell 'permission Payload = &cell 'permission *place; }",
2011
    ] {
2012
        let mut arena = super::testArena();
2013
        let storage: 'test = &mut arena in {
2014
            let mut res = super::testResolver(storage);
2015
            let result = try super::resolveProgramStr(&mut res, program);
2016
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload);
2017
        }
2018
    }
2019
}
2020
2021
/// Affine associated payloads can only be accessed through explicit borrows or replacement.
2022
@test unsafe fn testPermissionCellAffinePayloadMoves() throws (testing::TestError) {
2023
    for program in [
2024
        // A value-context dereference cannot move the whole payload out of shared storage.
2025
        "record Permit {} record Payload { value: u32 } fn f 'storage 'permission (cell: &'storage cell 'permission Payload, permission: &'permission mut Permit) { let moved = *cell; }",
2026
        // A shared payload loan cannot move an affine field out of the stored value.
2027
        "record Permit {} record Item { value: u32 } record Payload { item: Item } fn f 'storage 'permission (cell: &'storage cell 'permission Payload, permission: &'permission mut Permit) { let authority: 'loan = &*permission, payload = &*cell in { let moved = payload.item; } }",
2028
    ] {
2029
        let mut arena = super::testArena();
2030
        let storage: 'test = &mut arena in {
2031
            let mut res = super::testResolver(storage);
2032
            let result = try super::resolveProgramStr(&mut res, program);
2033
            try super::expectErrorKind(&result, resolver::ErrorKind::LinearPartialMove);
2034
        }
2035
    }
2036
}
2037
2038
/// Observing an affine payload value still requires an explicit shared reference.
2039
@test unsafe fn testPermissionCellAffinePayloadObserve() throws (testing::TestError) {
2040
    {
2041
        let mut arena = super::testArena();
2042
        let storage: 'test = &mut arena in {
2043
            let mut res = super::testResolver(storage);
2044
            let result = try super::resolveProgramStr(&mut res,
2045
                "record Permit {} record Payload { value: u32 } fn f 'storage 'permission (cell: &'storage cell 'permission Payload, permission: &'permission mut Permit) { let equal = *cell == *cell; }");
2046
            try super::expectErrorKind(&result, resolver::ErrorKind::LinearPartialMove);
2047
        }
2048
    }
2049
    {
2050
        let mut arena = super::testArena();
2051
        let storage: 'test = &mut arena in {
2052
            let mut res = super::testResolver(storage);
2053
            let result = try super::resolveProgramStr(&mut res,
2054
                "record Permit {} record Payload { value: u32 } fn f 'storage 'permission (cell: &'storage cell 'permission Payload, permission: &'permission mut Permit) { let authority: 'loan = &*permission, left = &*cell, right = &*cell in { let sameReference = left == right; let sameValue = left.value == right.value; } }");
2055
            try super::expectNoErrors(&result);
2056
        }
2057
    }
2058
}
2059
2060
/// Cell creation requires exclusive access for the full borrow duration.
2061
@test unsafe fn testCellBorrowConflicts() throws (testing::TestError) {
2062
    for program in [
2063
        "fn f() { let mut n: u32 = 0; let c = &cell n; let r = &n; }",
2064
        "unsafe fn f() { let mut n: u32 = 0; let c = &cell n; let r = &n; }",
2065
        "fn f() { let mut n: u32 = 0; let r = &n; let c = &cell n; }",
2066
        "fn f() { let mut n: u32 = 0; let c = &cell n; set n = 1; }",
2067
        "fn f() { let mut n: u32 = 0; let c = &cell n; let other = &cell n; }",
2068
        "fn f() { let mut n: u32 = 0; let c = &cell n as &cell u32; let r = &n; }",
2069
        "fn inspect(c: &cell u32, r: &u32) {} fn f() { let mut n: u32 = 0; inspect(&cell n, &n); }",
2070
        "fn inspect(r: &u32, c: &cell u32) {} fn f() { let mut n: u32 = 0; inspect(&n, &cell n); }",
2071
    ] {
2072
        let mut arena = super::testArena();
2073
        let storage: 'test = &mut arena in {
2074
            let mut res = super::testResolver(storage);
2075
            let result = try super::resolveProgramStr(&mut res, program);
2076
            let error = try super::expectError(&result);
2077
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
2078
        }
2079
    }
2080
}
2081
2082
/// Cell creation requires an exclusive initialized place.
2083
@test unsafe fn testCellBorrowPayload() throws (testing::TestError) {
2084
    for program in [
2085
        "fn f() { let n: u32 = 0; let c = &cell n; }",
2086
        "fn f(p: &u32) { let c = &cell *p; }",
2087
        "unsafe fn f(p: &u32) { let c = &cell *p; }",
2088
    ] {
2089
        let mut arena = super::testArena();
2090
        let storage: 'test = &mut arena in {
2091
            let mut res = super::testResolver(storage);
2092
            let result = try super::resolveProgramStr(&mut res, program);
2093
            try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding);
2094
        }
2095
    }
2096
    for program in [
2097
        "record R { n: u32 } fn f() { let mut r = R { n: 0 }; let c = &cell r; }",
2098
        "fn f(p: &mut *mut u32) { let c = &cell *p; }",
2099
        "fn f(p: &mut [u32]) { let c = &cell p[..]; }",
2100
    ] {
2101
        let mut arena = super::testArena();
2102
        let storage: 'test = &mut arena in {
2103
            let mut res = super::testResolver(storage);
2104
            let result = try super::resolveProgramStr(&mut res, program);
2105
            try super::expectErrorKind(&result, resolver::ErrorKind::InvalidCellPayload);
2106
        }
2107
    }
2108
}
2109
2110
/// Cell access cannot expose payload references or restore exclusive pointers.
2111
@test unsafe fn testCellPointerAccess() throws (testing::TestError) {
2112
    for program in [
2113
        "fn f(p: *cell u32) { let r = &*p; }",
2114
        "unsafe fn f(p: *cell u32) { let r = &*p; }",
2115
        "record R: Copy { n: u32 } fn f(p: *cell R) { let r = &(*p).n; }",
2116
        "fn f(p: *cell [u32; 2]) { let r = &(*p)[0]; }",
2117
    ] {
2118
        let mut testArena57 = super::testArena();
2119
        let testStorage57: 'test57 = &mut testArena57 in {
2120
            let mut res = super::testResolver(testStorage57);
2121
            let result = try super::resolveProgramStr(&mut res, program);
2122
            try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding);
2123
        }
2124
    }
2125
    for program in [
2126
        "fn f(p: *cell u32) -> *mut u32 { return p as *mut u32; }",
2127
        "unsafe fn f(p: *cell u32) -> *unsafe mut u32 { return p as *unsafe mut u32; }",
2128
        "fn f(p: *u32) -> *cell u32 { return p as *cell u32; }",
2129
        "unsafe fn f(p: *unsafe mut u32) -> *cell u32 { return p as *cell u32; }",
2130
        "fn f(p: *mut u64) -> *cell u32 { return p as *cell u32; }",
2131
        "fn f 'r (p: &'r mut u32) -> *cell u32 { return p as *cell u32; }",
2132
    ] {
2133
        let mut testArena58 = super::testArena();
2134
        let testStorage58: 'test58 = &mut testArena58 in {
2135
            let mut res = super::testResolver(testStorage58);
2136
            let result = try super::resolveProgramStr(&mut res, program);
2137
            let error = try super::expectError(&result);
2138
            let case resolver::ErrorKind::InvalidAsCast(_) = error.kind else throw testing::TestError::Failed;
2139
        }
2140
    }
2141
}
2142
2143
/// An exclusive payload borrow cannot be made from shared cell access.
2144
@test unsafe fn testCellPointerMutablePayload() throws (testing::TestError) {
2145
    let mut testArena59 = super::testArena();
2146
    let testStorage59: 'test59 = &mut testArena59 in {
2147
        let mut res = super::testResolver(testStorage59);
2148
        let result = try super::resolveProgramStr(&mut res,
2149
            "fn f(p: *cell u32) { let r = &mut *p; }");
2150
        try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding);
2151
    }
2152
}
2153
2154
/// Cell conversion consumes exclusive access, including call arguments.
2155
@test unsafe fn testCellPointerOwnership() throws (testing::TestError) {
2156
    for program in [
2157
        "fn f(p: *mut u32) { let c = &cell *p; set *p = 1; }",
2158
        "unsafe fn f(p: *mut u32) { let c = &cell *p; set *p = 1; }",
2159
        "record R: Copy { n: u32 } fn f(p: *mut R) { let c = &cell p.n; set p.n = 1; }",
2160
        "fn f(p: *mut [u32]) { let c = &cell p[0]; set p[0] = 1; }",
2161
        "fn f(p: *mut u32) { let c = p as *cell u32; set *p = 1; }",
2162
        "unsafe fn f(p: *mut u32) { let c = p as *cell u32; set *p = 1; }",
2163
        "fn read(p: &cell u32) {} fn f(p: &mut u32) { read(p as &cell u32); set *p = 1; }",
2164
    ] {
2165
        let mut testArena60 = super::testArena();
2166
        let testStorage60: 'test60 = &mut testArena60 in {
2167
            let mut res = super::testResolver(testStorage60);
2168
            let result = try super::resolveProgramStr(&mut res, program);
2169
            let error = try super::expectError(&result);
2170
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
2171
        }
2172
    }
2173
    for program in [
2174
        "fn f() { let mut n: u32 = 0; let c = &mut n as &cell u32; let r = &n; set *c = 1; }",
2175
        "unsafe fn f() { let mut n: u32 = 0; let c = &mut n as &cell u32; let r = &n; set *c = 1; }",
2176
    ] {
2177
        let mut testArena61 = super::testArena();
2178
        let testStorage61: 'test61 = &mut testArena61 in {
2179
            let mut res = super::testResolver(testStorage61);
2180
            let result = try super::resolveProgramStr(&mut res, program);
2181
            let error = try super::expectError(&result);
2182
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
2183
        }
2184
    }
2185
}
2186
2187
/// Cell writes preserve exact payload regions and destination lifetimes.
2188
@test unsafe fn testCellPointerRegion() throws (testing::TestError) {
2189
    for program in [
2190
        "fn f 'r 's (p: &'r cell &'r u32, value: &'s u32) { set *p = value; }",
2191
        "unsafe fn f 'r 's (p: &'r cell &'r u32, value: &'s u32) { set *p = value; }",
2192
        "fn f 'r 's (p: &'r cell u32) -> &'s cell u32 { return p; }",
2193
    ] {
2194
        let mut testArena62 = super::testArena();
2195
        let testStorage62: 'test62 = &mut testArena62 in {
2196
            let mut res = super::testResolver(testStorage62);
2197
            let result = try super::resolveProgramStr(&mut res, program);
2198
            let error = try super::expectError(&result);
2199
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
2200
        }
2201
    }
2202
    for program in [
2203
        "fn f 'r 's (p: &'r cell &'s u32, value: &'s u32) where 'r: 's { set *p = value; }",
2204
        "unsafe fn f 'r 's (p: &'r cell &'s u32, value: &'s u32) where 'r: 's { set *p = value; }",
2205
    ] {
2206
        let mut testArena63 = super::testArena();
2207
        let testStorage63: 'test63 = &mut testArena63 in {
2208
            let mut res = super::testResolver(testStorage63);
2209
            let result = try super::resolveProgramStr(&mut res, program);
2210
            let error = try super::expectError(&result);
2211
            let case resolver::ErrorKind::RegionEscape(_) = error.kind else throw testing::TestError::Failed;
2212
        }
2213
    }
2214
}
2215
2216
/// Raw cell operations require an unsafe execution context.
2217
@test unsafe fn testCellPointerRawAccess() throws (testing::TestError) {
2218
    for program in [
2219
        "fn f(p: *unsafe cell u32) -> u32 { return *p; }",
2220
        "fn f(p: *unsafe cell u32) { set *p = 1; }",
2221
        "fn f(p: &*unsafe cell u32) { set **p = 1; }",
2222
    ] {
2223
        let mut testArena64 = super::testArena();
2224
        let testStorage64: 'test64 = &mut testArena64 in {
2225
            let mut res = super::testResolver(testStorage64);
2226
            let result = try super::resolveProgramStr(&mut res, program);
2227
            try super::expectErrorKind(&result, resolver::ErrorKind::UnsafeOperation);
2228
        }
2229
    }
2230
}
2231
2232
/// A checked buffer context cannot be copied while its exclusive storage is live.
2233
@test unsafe fn testCheckedBufferOwnership() throws (testing::TestError) {
2234
    for program in [
2235
        "record Buffer: 'r { words: &'r mut [u32] } fn observe 'r (b: &Buffer 'r) {} fn f 'r (b: Buffer 'r) { let moved = b; observe(&b); }",
2236
        "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); }",
2237
    ] {
2238
        let mut testArena65 = super::testArena();
2239
        let testStorage65: 'test65 = &mut testArena65 in {
2240
            let mut res = super::testResolver(testStorage65);
2241
            let result = try super::resolveProgramStr(&mut res, program);
2242
            let error = try super::expectError(&result);
2243
            let case resolver::ErrorKind::AffineUseAfterMove(_) = error.kind else throw testing::TestError::Failed;
2244
        }
2245
    }
2246
}
2247
2248
/// An iterator's stored shared borrow excludes writes through the buffer owner.
2249
@test unsafe fn testCheckedIteratorLoan() throws (testing::TestError) {
2250
    for program in [
2251
        "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; } }",
2252
        "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; } }",
2253
    ] {
2254
        let mut testArena66 = super::testArena();
2255
        let testStorage66: 'test66 = &mut testArena66 in {
2256
            let mut res = super::testResolver(testStorage66);
2257
            let result = try super::resolveProgramStr(&mut res, program);
2258
            let error = try super::expectError(&result);
2259
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind else throw testing::TestError::Failed;
2260
        }
2261
    }
2262
}
2263
2264
/// An inferred raw pointer argument requires an unsafe address operation.
2265
@test unsafe fn testRegionCallRawAddress() throws (testing::TestError) {
2266
    let mut arena = super::testArena();
2267
    let storage: 'arena = &mut arena in {
2268
        let mut res = super::testResolver(storage);
2269
        let result = try super::resolveProgramStr(&mut res,
2270
            "record View: 'r + Copy { value: &'r u32 } fn read 'r (view: *unsafe View 'r) {} fn f 'r (view: View 'r) { read(&view); }");
2271
        try super::expectErrorKind(&result, resolver::ErrorKind::UnsafeOperation);
2272
    }
2273
}
2274
2275
/// Shared aggregate access cannot expose mutable access to an exclusive field.
2276
@test unsafe fn testSharedExclusiveFieldAccess() throws (testing::TestError) {
2277
    for program in [
2278
        "record H: 'r { items: &'r mut [u32] } fn f 'r (h: &H 'r) { set h.items[0] = 42; }",
2279
        "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r (h: &H 'r) { set h.items[0] = 42; }",
2280
        "record H: 'r { items: &'r mut [u32] } fn f 'r (h: &'r H 'r) { let p = &mut h.items[0]; }",
2281
        "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r (h: &'r H 'r) { let p = &mut h.items[0]; }",
2282
        "record H: 'r { items: &'r mut [u32] } fn write(p: &mut [u32]) {} fn f 'r (h: &H 'r) { write(h.items); }",
2283
        "record H: 'r { items: &'r mut [u32] } fn write(p: &mut [u32]) {} unsafe fn f 'r (h: &H 'r) { write(h.items); }",
2284
        "record H: 'r { item: &'r mut u32 } fn f 'r (h: &H 'r) { let p: &mut u32 = h.item; }",
2285
        "record H: 'r { item: &'r mut u32 } unsafe fn f 'r (h: &H 'r) { let p: &mut u32 = h.item; }",
2286
        "record H { item: *mut u32 } fn f(h: &H) { set *h.item = 42; }",
2287
        "record H { item: *mut u32 } unsafe fn f(h: &H) { set *h.item = 42; }",
2288
        "record H: 'r { items: [&'r mut u32; 1] } fn f 'r (h: &H 'r) { set *h.items[0] = 42; }",
2289
        "record H: 'r { items: [&'r mut u32; 1] } unsafe fn f 'r (h: &H 'r) { set *h.items[0] = 42; }",
2290
        "fn f 'r (items: &'r [&'r mut u32]) { set *items[0] = 42; }",
2291
        "unsafe fn f 'r (items: &'r [&'r mut u32]) { set *items[0] = 42; }",
2292
        "fn f 'r (p: &'r &'r mut u32) { set **p = 42; }",
2293
        "unsafe fn f 'r (p: &'r &'r mut u32) { set **p = 42; }",
2294
        "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); }",
2295
        "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); }",
2296
        "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(); }",
2297
        "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(); }",
2298
        "trait W { fn (&mut W) write(); } record H: 'r { object: &'r mut opaque W } fn f 'r (h: &H 'r) { h.object.write(); }",
2299
        "trait W { fn (&mut W) write(); } record H: 'r { object: &'r mut opaque W } unsafe fn f 'r (h: &H 'r) { h.object.write(); }",
2300
    ] {
2301
        let mut arena = super::testArena();
2302
        let storage: 'test = &mut arena in {
2303
            let mut res = super::testResolver(storage);
2304
            let result = try super::resolveProgramStr(&mut res, program);
2305
            try super::expectErrorKind(&result, resolver::ErrorKind::ImmutableBinding);
2306
        }
2307
    }
2308
}
2309
2310
/// Named shared pattern bindings retain the subject reference region.
2311
@test unsafe fn testNamedPatternBorrowRegions() throws (testing::TestError) {
2312
    for program in [
2313
        "record B: 'r { values: &'r mut [u32] } fn f 'r (b: &'r B 'r) -> &'r [u32] { return &b.values[..]; }",
2314
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn f 'r (u: &'r U 'r) -> &'r [u32] { match u { case U::Some(b) => return &b.values[..], else => panic, } }",
2315
        "record B: 'r { values: &'r mut [u32] } record S: 'r { items: [?B 'r; 1] } fn f 'r (s: &'r S 'r) -> &'r [u32] { match &s.items[0] { case nil => panic, b => return &b.values[..], } }",
2316
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn values 'r (b: &'r B 'r) -> &'r [u32] { return &b.values[..]; } fn f 'r (u: &'r U 'r) -> &'r [u32] { match u { case U::Some(b) => return values(b), else => panic, } }",
2317
        "record B: 'r { values: &'r mut [u32] } record S: 'r { items: [?B 'r; 1] } fn values 'r (b: &'r B 'r) -> &'r [u32] { return &b.values[..]; } fn f 'r (s: &'r S 'r) -> &'r [u32] { let mut found: ?&'r B 'r = nil; match &s.items[0] { case nil => panic, b => set found = b, } let b = found else panic; return values(b); }",
2318
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn f 'r (u: &'r U 'r) -> &'r [u32] { if let case U::Some(b) = u { return &b.values[..]; } panic; }",
2319
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn f 'r (u: &'r U 'r) -> &'r [u32] { let case U::Some(b) = u else panic; return &b.values[..]; }",
2320
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn f 'r (u: &'r U 'r) -> &'r [u32] { while let case U::Some(b) = u { return &b.values[..]; } panic; }",
2321
    ] {
2322
        let mut arena = super::testArena();
2323
        let storage: 'test = &mut arena in {
2324
            let mut res = super::testResolver(storage);
2325
            let result = try super::resolveProgramStr(&mut res, program);
2326
            try super::expectNoErrors(&result);
2327
        }
2328
    }
2329
}
2330
2331
/// Owned and raw pattern subjects produce ordinary shared bindings.
2332
@test unsafe fn testPointerPatternBindingClasses() throws (testing::TestError) {
2333
    for program in [
2334
        "record B { value: u32 } union U { Some(B), None } fn f(u: *U) { match u { case U::Some(b) => { assert b.value == 0; }, else => {}, } }",
2335
        "record B { value: u32 } union U { Some(B), None } unsafe fn f(u: *unsafe U) { match u { case U::Some(b) => { assert b.value == 0; }, else => {}, } }",
2336
    ] {
2337
        let mut arena = super::testArena();
2338
        let storage: 'test = &mut arena in {
2339
            let mut res = super::testResolver(storage);
2340
            let result = try super::resolveProgramStr(&mut res, program);
2341
            try super::expectNoErrors(&result);
2342
            let func = try super::getBlockStmt(result.root, 2);
2343
            let fnType = resolver::typeFor(&res, func) else throw testing::TestError::Failed;
2344
            let case resolver::Type::Fn(info) = fnType else throw testing::TestError::Failed;
2345
            let subject = resolver::unwrapMatchSubject(*info.paramTypes[0]);
2346
            let case resolver::MatchBy::Ref(types::PointerClass::Ref) = subject.by
2347
                else throw testing::TestError::Failed;
2348
            let case ast::NodeValue::FnDecl(decl) = func.value else throw testing::TestError::Failed;
2349
            let body = decl.body else throw testing::TestError::Failed;
2350
            let statement = try super::getBlockStmt(body, 0);
2351
            let case ast::NodeValue::Match(matchStmt) = statement.value else throw testing::TestError::Failed;
2352
            let case ast::NodeValue::MatchProng(prong) = matchStmt.prongs[0].value
2353
                else throw testing::TestError::Failed;
2354
            let case ast::ProngArm::Case(patterns) = prong.arm else throw testing::TestError::Failed;
2355
            let case ast::NodeValue::Call(call) = patterns[0].value else throw testing::TestError::Failed;
2356
            let bindingType = resolver::typeFor(&res, call.args[0]) else throw testing::TestError::Failed;
2357
            let case resolver::Type::Pointer { class: types::PointerClass::Ref, .. } = bindingType
2358
                else throw testing::TestError::Failed;
2359
        }
2360
    }
2361
}
2362
2363
/// Mutable pattern payload bindings cannot escape or overlap source mutation.
2364
@test unsafe fn testMutablePatternBindingEscape() throws (testing::TestError) {
2365
    let programs = [
2366
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn f 'r (u: &'r mut U 'r) -> &'r [u32] { match u { case U::Some(b) => return &b.values[..], else => panic, } }",
2367
    ];
2368
    for program in programs {
2369
        let mut arena = super::testArena();
2370
        let storage: 'test = &mut arena in {
2371
            let mut res = super::testResolver(storage);
2372
            let result = try super::resolveProgramStr(&mut res, program);
2373
            let error = try super::expectError(&result);
2374
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind
2375
                else throw testing::TestError::Failed;
2376
        }
2377
    }
2378
    for program in [
2379
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn f 'r (u: &'r mut U 'r) { match u { case U::Some(b) => { let held = &b.values[..]; set *u = U::None; assert held.len == 0; }, else => {}, } }",
2380
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn f 'r (u: &'r mut U 'r) { let mut held: ?&'r B 'r = nil; match &*u { case U::Some(b) => set held = b, else => {}, } set *u = U::None; let b = held else return; assert b.values.len == 0; }",
2381
    ] {
2382
        let mut arena = super::testArena();
2383
        let storage: 'test = &mut arena in {
2384
            let mut res = super::testResolver(storage);
2385
            let result = try super::resolveProgramStr(&mut res, program);
2386
            let error = try super::expectError(&result);
2387
            let case resolver::ErrorKind::BorrowConflict(_) = error.kind
2388
                else throw testing::TestError::Failed;
2389
        }
2390
    }
2391
}
2392
2393
/// Named shared pattern bindings cannot outlive a shorter subject reference.
2394
@test unsafe fn testNamedPatternBorrowRejectsShortOwner() throws (testing::TestError) {
2395
    for program in [
2396
        "record B: 'r { values: &'r mut [u32] } union U: 'r { Some(B 'r), None } fn f 'r 's (u: &'s U 'r) -> &'r [u32] where 'r: 's { match u { case U::Some(b) => return &b.values[..], else => panic, } }",
2397
        "record B: 'r { values: &'r mut [u32] } record S: 'r { items: [?B 'r; 1] } fn f 'r 's (s: &'s S 'r) -> &'r [u32] where 'r: 's { match &s.items[0] { case nil => panic, b => return &b.values[..], } }",
2398
    ] {
2399
        let mut arena = super::testArena();
2400
        let storage: 'test = &mut arena in {
2401
            let mut res = super::testResolver(storage);
2402
            let result = try super::resolveProgramStr(&mut res, program);
2403
            let error = try super::expectError(&result);
2404
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind
2405
                else throw testing::TestError::Failed;
2406
        }
2407
    }
2408
}
2409
2410
/// A reference through an exclusive field cannot outlive the owner's borrow.
2411
@test unsafe fn testExclusiveOwnerBorrowLifetimes() throws (testing::TestError) {
2412
    for program in [
2413
        "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; }",
2414
        "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; }",
2415
        "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; }",
2416
        "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; }",
2417
        "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; }",
2418
        "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; }",
2419
        "record H: 'r { item: &'r mut u32 } fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &*h.item; }",
2420
        "record H: 'r { item: &'r mut u32 } unsafe fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &*h.item; }",
2421
        "record H: 'r { items: &'r mut [u32] } fn f 'r 's (h: &'s H 'r) -> &'r u32 where 'r: 's { return &h.items[0]; }",
2422
        "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]; }",
2423
        "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; }",
2424
        "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; }",
2425
        "record H { item: *mut u32 } fn f(h: &H) -> *u32 { return &*h.item; }",
2426
        "record H { item: *mut u32 } unsafe fn f(h: &H) -> *u32 { return &*h.item; }",
2427
        "record H: 'r { items: &'r mut [u32] } fn f 'r 's (h: &'s H 'r) -> &'r [u32] where 'r: 's { return &h.items[..]; }",
2428
        "record H: 'r { items: &'r mut [u32] } unsafe fn f 'r 's (h: &'s H 'r) -> &'r [u32] where 'r: 's { return &h.items[..]; }",
2429
    ] {
2430
        let mut arena = super::testArena();
2431
        let storage: 'test = &mut arena in {
2432
            let mut res = super::testResolver(storage);
2433
            let result = try super::resolveProgramStr(&mut res, program);
2434
            let error = try super::expectError(&result);
2435
            let case resolver::ErrorKind::TypeMismatch(_) = error.kind else throw testing::TestError::Failed;
2436
        }
2437
    }
2438
}
2439
2440
/// A shared binding cannot hide a move from an exclusive field.
2441
@test unsafe fn testSharedBindingPreservesSourceOwnership() throws (testing::TestError) {
2442
    for program in [
2443
        "record H { item: *mut u32 } fn f(h: H) -> *u32 { let p: *u32 = h.item; return p; }",
2444
        "record H { item: ?*mut u32 } fn f(h: H) -> ?*u32 { let p: ?*u32 = h.item; return p; }",
2445
        "record H: 'r { item: &'r mut u32 } fn f 'r (h: &'r H 'r) -> &'r u32 { let p: &'r u32 = h.item; return p; }",
2446
        "record H { item: *mut u32 } unsafe fn f(h: H) -> *u32 { let p: *u32 = h.item; return p; }",
2447
        "record H { item: ?*mut u32 } unsafe fn f(h: H) -> ?*u32 { let p: ?*u32 = h.item; return p; }",
2448
        "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; }",
2449
    ] {
2450
        let mut arena = super::testArena();
2451
        let storage: 'test = &mut arena in {
2452
            let mut res = super::testResolver(storage);
2453
            let result = try super::resolveProgramStr(&mut res, program);
2454
            try super::expectErrorKind(&result, resolver::ErrorKind::LinearPartialMove);
2455
        }
2456
    }
2457
}
2458
2459
/// Methods and trait instances resolve declaration region parameters.
2460
@test unsafe fn testRegionalMethods() throws (testing::TestError) {
2461
    for program in [
2462
        "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(); }",
2463
        "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); }",
2464
        "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); }",
2465
    ] {
2466
        let mut arena = super::testArena();
2467
        let storage: 'method = &mut arena in {
2468
            let mut res = super::testResolver(storage);
2469
            let result = try super::resolveProgramStr(&mut res, program);
2470
            try super::expectNoErrors(&result);
2471
        }
2472
    }
2473
}