lib/std/lang/resolver/tests.rad 410.1 KiB raw
1
//! Resolver tests.
2
3
/// Region identity, borrowing, and nominal application tests.
4
@test mod regions;
5
/// Placeholder binding, pattern, and expression tests.
6
@test mod placeholderTests;
7
8
use std::mem;
9
use std::testing;
10
use std::lang::alloc;
11
use std::lang::ast;
12
use std::lang::types;
13
use std::lang::parser;
14
use std::lang::scanner;
15
use std::lang::module;
16
use std::lang::strings;
17
18
/// Interning preserves exact identity across populated collision chains.
19
@test unsafe fn testTypeInterningIdentity() throws (testing::TestError) {
20
    let mut arena = testArena();
21
    let storage: 'test = &mut arena in {
22
        let mut res = testResolver(storage);
23
        let item = super::allocType(&mut res, super::Type::U32);
24
        let mut entries: [?*super::Type; 2048] = [nil; 2048];
25
        for i in 0..entries.len {
26
            let ty = super::Type::Array(super::ArrayType { item, length: i });
27
            set entries[i] = super::allocType(&mut res, ty);
28
        }
29
        for i in 0..entries.len {
30
            let ty = super::Type::Array(super::ArrayType { item, length: i });
31
            let entry = entries[i] else throw testing::TestError::Failed;
32
            assert super::allocType(&mut res, ty) == entry;
33
            assert *entry == ty;
34
        }
35
        let values = [
36
            super::Type::U32, super::Type::U64,
37
            super::Type::Optional(item),
38
            super::Type::Range { start: nil, end: nil },
39
            super::Type::Range { start: item, end: nil },
40
            super::Type::Range { start: nil, end: item },
41
            super::Type::Range { start: item, end: item },
42
            super::Type::Cell {
43
                class: types::PointerClass::Ref, permission: nil, payload: item,
44
            },
45
            super::Type::Pointer { class: types::PointerClass::Ref, target: item, mutable: false },
46
            super::Type::Pointer { class: types::PointerClass::Ref, target: item, mutable: true },
47
            super::Type::Pointer { class: types::PointerClass::Owned, target: item, mutable: false },
48
            super::Type::Pointer { class: types::PointerClass::Unsafe, target: item, mutable: false },
49
            super::Type::Slice { class: types::PointerClass::Ref, item, mutable: false },
50
            super::Type::Slice { class: types::PointerClass::Ref, item, mutable: true },
51
        ];
52
        for ty, i in values {
53
            let entry = super::allocType(&mut res, ty);
54
            assert super::allocType(&mut res, ty) == entry;
55
            for other, j in values {
56
                assert (entry == super::allocType(&mut res, other)) == (i == j);
57
            }
58
        }
59
    }
60
}
61
62
/// Reused ownership slots retain the current binding's exact-use diagnostics.
63
@test unsafe fn testLinearScratchSlotReuse() throws (testing::TestError) {
64
    let mut arena = testArena();
65
    let storage: 'test = &mut arena in {
66
        let mut res = testResolver(storage);
67
        let result = try resolveProgramStr(&mut res,
68
            "union Token: Once { Value(u32) } fn consume(t: Token) { match t { case Token::Value(_) => {} } } fn f() { { let first = Token::Value(1); consume(first); } let second = Token::Value(2); consume(second); consume(second); }"
69
        );
70
        try expectErrorKind(&result, super::ErrorKind::LinearUseAfterConsume("second"));
71
    }
72
    let mut branchArena = testArena();
73
    let branchStorage: 'branch = &mut branchArena in {
74
        let mut res = testResolver(branchStorage);
75
        let result = try resolveProgramStr(&mut res,
76
            "union Token: Once { Value(u32) } fn consume(t: Token) { match t { case Token::Value(_) => {} } } fn f(choice: bool) { { let first = Token::Value(1); consume(first); } let second = Token::Value(2); if choice { consume(second); } }"
77
        );
78
        try expectErrorKind(&result, super::ErrorKind::LinearBranchMismatch("second"));
79
    }
80
}
81
82
/// Nested loops keep separate break state and restore the stack after errors.
83
@test unsafe fn testLoopContextState() throws (testing::TestError) {
84
    for program, index in [
85
        "fn f() { loop { break; } loop { loop { break; } continue; } }",
86
        "fn f() { loop { loop { missing; } } }",
87
        "fn f() { loop { break; } break; }",
88
        "fn f() { loop { break; } continue; }",
89
        "break;",
90
        "continue;",
91
        "loop { break }",
92
        "while true { continue }",
93
    ] {
94
        let mut arena = testArena();
95
        let storage: 'test = &mut arena in {
96
            let mut res = testResolver(storage);
97
            let result = try resolveProgramStr(&mut res, program);
98
            assert res.loopDepth == 0;
99
            if index == 0 {
100
                try expectNoErrors(&result);
101
                let body = try getFnBody(&res, result.root, "f");
102
                let first = super::typeFor(&res, body.statements[0]) else throw testing::TestError::Failed;
103
                let second = super::typeFor(&res, body.statements[1]) else throw testing::TestError::Failed;
104
                let case super::Type::Void = first else throw testing::TestError::Failed;
105
                let case super::Type::Never = second else throw testing::TestError::Failed;
106
            } else if index == 1 {
107
                try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("missing"));
108
            } else if index < 6 {
109
                try expectErrorKind(&result, super::ErrorKind::InvalidLoopControl);
110
            } else {
111
                try expectNoErrors(&result);
112
            }
113
        }
114
    }
115
}
116
117
/// Loop bindings and lowering metadata retain the same item type and names.
118
@test unsafe fn testForLoopMetadata() throws (testing::TestError) {
119
    let mut arena = testArena();
120
    let storage: 'test = &mut arena in {
121
        let mut res = testResolver(storage);
122
        let result = try resolveProgramStr(&mut res,
123
            "fn f(s: &[u8], start: u64, end: u64) { let xs: [u16; 2] = [1, 2]; for value, idx in xs {} for byte in s {} for _, idx in start..end {} }"
124
        );
125
        try expectNoErrors(&result);
126
        let body = try getFnBody(&res, result.root, "f");
127
        for index in [1 as u32, 2, 3] {
128
            let node = body.statements[index];
129
            let case ast::NodeValue::For(loopNode) = node.value else throw testing::TestError::Failed;
130
            let info = super::forLoopInfoFor(&res, node) else throw testing::TestError::Failed;
131
            let bindingType = super::typeFor(&res, loopNode.binding) else throw testing::TestError::Failed;
132
            match info {
133
                case super::ForLoopInfo::Collection { elemType, length, bindingName, indexName } => {
134
                    assert bindingType == *elemType;
135
                    let name = bindingName else throw testing::TestError::Failed;
136
                    if index == 1 {
137
                        assert *elemType == super::Type::U16;
138
                        let count = length else throw testing::TestError::Failed;
139
                        assert count == 2;
140
                        assert mem::eq(name, "value");
141
                        let name = indexName else throw testing::TestError::Failed;
142
                        assert mem::eq(name, "idx");
143
                    } else {
144
                        assert index == 2;
145
                        assert *elemType == super::Type::U8;
146
                        assert length == nil;
147
                        assert mem::eq(name, "byte");
148
                        assert indexName == nil;
149
                    }
150
                }
151
                case super::ForLoopInfo::Range { valType, range, bindingName, indexName } => {
152
                    assert index == 3;
153
                    assert bindingType == *valType;
154
                    assert *valType == super::Type::U64;
155
                    assert bindingName == nil;
156
                    let name = indexName else throw testing::TestError::Failed;
157
                    assert mem::eq(name, "idx");
158
                    let case ast::NodeValue::Range(source) = loopNode.iterable.value else throw testing::TestError::Failed;
159
                    assert range == source;
160
                }
161
            }
162
            if let binding = loopNode.index {
163
                let ty = super::typeFor(&res, binding) else throw testing::TestError::Failed;
164
                assert ty == super::Type::U32;
165
            }
166
        }
167
    }
168
}
169
170
/// Invalid iterables and unsafe slice iteration retain their diagnostics.
171
@test unsafe fn testForLoopMetadataErrors() throws (testing::TestError) {
172
    for program in [
173
        "fn f() { for x in true {} }",
174
        "fn f(end: u32) { for x in ..end {} }",
175
        "fn f(start: u32, end: u32) { let range = start..end; for x in range {} }",
176
    ] {
177
        let mut arena = testArena();
178
        let storage: 'test = &mut arena in {
179
            let mut res = testResolver(storage);
180
            let result = try resolveProgramStr(&mut res, program);
181
            try expectErrorKind(&result, super::ErrorKind::ExpectedIterable);
182
        }
183
    }
184
    let mut arena = testArena();
185
    let storage: 'test = &mut arena in {
186
        let mut res = testResolver(storage);
187
        let result = try resolveProgramStr(&mut res, "fn f(s: *unsafe [u32]) { for x in s {} }");
188
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
189
    }
190
    try expectAnalyzeOk("unsafe fn f(s: *unsafe [u32]) { for x in s {} }");
191
}
192
193
/// Slice operations retain initialized element, capacity, and access metadata.
194
@test unsafe fn testSliceRangeMetadata() throws (testing::TestError) {
195
    let mut arena = testArena();
196
    let storage: 'test = &mut arena in {
197
        let mut res = testResolver(storage);
198
        let result = try resolveProgramStr(&mut res,
199
            "fn f() { let mut xs: [u32; 4] = [1, 2, 3, 4]; set xs[1..3] = 7; let view = &mut xs[1..3]; set view[..] = 3; let shared = &view[..]; }"
200
        );
201
        try expectNoErrors(&result);
202
        let body = try getFnBody(&res, result.root, "f");
203
        for index in [1 as u32, 3] {
204
            let stmt = body.statements[index];
205
            let case ast::NodeValue::Assign(_) = stmt.value else throw testing::TestError::Failed;
206
            let info = super::sliceRangeInfoFor(&res, stmt) else throw testing::TestError::Failed;
207
            assert *info.itemType == super::Type::U32;
208
            assert info.mutable;
209
            let capacity: ?u32 = 4 if index == 1 else nil;
210
            assert info.capacity == capacity;
211
        }
212
        for index in [2 as u32, 4] {
213
            let stmt = body.statements[index];
214
            let case ast::NodeValue::Let(binding) = stmt.value else throw testing::TestError::Failed;
215
            let case ast::NodeValue::AddressOf(_) = binding.value.value else throw testing::TestError::Failed;
216
            let info = super::sliceRangeInfoFor(&res, binding.value) else throw testing::TestError::Failed;
217
            assert *info.itemType == super::Type::U32;
218
            assert info.mutable == (index == 2);
219
            let capacity: ?u32 = 4 if index == 2 else nil;
220
            assert info.capacity == capacity;
221
        }
222
    }
223
}
224
225
/// Slice assignment and borrowing enforce static bounds and source access.
226
@test unsafe fn testSliceRangeErrors() throws (testing::TestError) {
227
    for program in [
228
        "fn f() { let mut xs: [u32; 2] = [1, 2]; set xs[..3] = 0; }",
229
        "fn f() { let mut xs: [u32; 2] = [1, 2]; set xs[2..1] = 0; }",
230
        "fn f() { let mut xs: [u32; 2] = [1, 2]; let view = &mut xs[..3]; }",
231
    ] {
232
        let mut arena = testArena();
233
        let storage: 'test = &mut arena in {
234
            let mut res = testResolver(storage);
235
            let result = try resolveProgramStr(&mut res, program);
236
            let err = try expectError(&result);
237
            assert err.kind == super::ErrorKind::SliceRangeOutOfBounds, program;
238
        }
239
    }
240
    for program in [
241
        "fn f() { let mut value: u32 = 1; set value[..] = 0; }",
242
        "fn f() { let mut value: u32 = 1; let view = &value[..]; }",
243
    ] {
244
        let mut arena = testArena();
245
        let storage: 'test = &mut arena in {
246
            let mut res = testResolver(storage);
247
            let result = try resolveProgramStr(&mut res, program);
248
            let err = try expectError(&result);
249
            assert err.kind == super::ErrorKind::ExpectedIndexable, program;
250
        }
251
    }
252
    for program in [
253
        "fn f() { let xs: [u32; 2] = [1, 2]; let view = &xs[..]; set view[..] = 0; }",
254
        "fn f() { let xs: [u32; 2] = [1, 2]; let view = &xs[..]; let other = &mut view[..]; }",
255
    ] {
256
        let mut arena = testArena();
257
        let storage: 'test = &mut arena in {
258
            let mut res = testResolver(storage);
259
            let result = try resolveProgramStr(&mut res, program);
260
            let err = try expectError(&result);
261
            assert err.kind == super::ErrorKind::ImmutableBinding, program;
262
        }
263
    }
264
}
265
266
/// Fixed and result layouts cover primitive and pointer-like representations.
267
@test unsafe fn testFixedTypeLayouts() throws (testing::TestError) {
268
    for ty in [super::Type::Void, super::Type::Never] {
269
        checkFixedTypeLayout(ty, 0, 0);
270
    }
271
    for ty in [super::Type::Bool, super::Type::U8, super::Type::I8] {
272
        checkFixedTypeLayout(ty, 1, 1);
273
    }
274
    for ty in [super::Type::U16, super::Type::I16] { checkFixedTypeLayout(ty, 2, 2); }
275
    for ty in [super::Type::U32, super::Type::I32] { checkFixedTypeLayout(ty, 4, 4); }
276
    for ty in [super::Type::Int, super::Type::U64, super::Type::I64] { checkFixedTypeLayout(ty, 8, 8); }
277
    let mut arena = testArena();
278
    let itemStorage = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type;
279
    set *itemStorage = super::Type::U32;
280
    let item: *super::Type = itemStorage;
281
    let region = types::Region { id: 1, origin: types::RegionOrigin::Block, name: "r", parent: nil };
282
    let traitInfo = super::TraitType { name: "T", moduleId: 0, methods: &mut [], supertraits: &mut [] };
283
    let signature = try! alloc::alloc(&mut arena, @sizeOf(super::FnType), @alignOf(super::FnType)) as *mut super::FnType;
284
    set *signature = super::FnType {
285
        regions: nil, paramTypes: &[], returnType: item, throwList: &[], isUnsafe: false,
286
    };
287
    checkFixedTypeLayout(super::Type::Fn(signature), 8, 8);
288
    checkFixedTypeLayout(super::Type::Session(&region), 16, 8);
289
    for class in [types::PointerClass::Owned, types::PointerClass::Ref,
290
                  types::PointerClass::Unsafe, types::PointerClass::Region(&region)] {
291
        checkFixedTypeLayout(super::Type::Cell {
292
            class, permission: nil, payload: item,
293
        }, 8, 8);
294
        for mutable in [false, true] {
295
            checkFixedTypeLayout(super::Type::Pointer { class, target: item, mutable }, 8, 8);
296
            checkFixedTypeLayout(super::Type::Slice { class, item, mutable }, 16, 8);
297
            checkFixedTypeLayout(super::Type::TraitObject { class, traitInfo: &traitInfo, mutable }, 16, 8);
298
        }
299
    }
300
    /// Result layouts retain the tag and the largest success or error payload.
301
    let errors = try! alloc::allocSlice(&mut arena, @sizeOf(*super::Type), @alignOf(*super::Type), 3)
302
        as *mut [*super::Type];
303
    for ty, i in [super::Type::Void, super::Type::U8, super::Type::U64] {
304
        let slot = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type;
305
        set *slot = ty;
306
        set errors[i] = slot;
307
    }
308
    let throwList: *[*super::Type] = errors;
309
    let payloads = [super::Type::Void, super::Type::U8,
310
        super::Type::Array(super::ArrayType { item: throwList[2], length: 3 })];
311
    let emptySizes: [u32; 3] = [8, 9, 32];
312
    let errorSizes: [u32; 3] = [16, 16, 32];
313
    for payload, i in payloads {
314
        let empty = super::getResultLayout(payload, &[]);
315
        assert empty.size == emptySizes[i] and empty.alignment == 8;
316
        let result = super::getResultLayout(payload, throwList);
317
        assert result.size == errorSizes[i] and result.alignment == 8;
318
    }
319
}
320
321
/// Check a fixed layout through direct, array, and optional type traversal.
322
unsafe fn checkFixedTypeLayout(ty: super::Type, size: u32, alignment: u32) {
323
    let layout = super::getTypeLayout(ty);
324
    assert layout.size == size and layout.alignment == alignment;
325
    let mut arena = alloc::new(&mut FIXED_LAYOUT_STORAGE[..]);
326
    let itemStorage = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type;
327
    set *itemStorage = ty;
328
    let item: *super::Type = itemStorage;
329
    for length in [0 as u32, 1, 3] {
330
        let array = super::getTypeLayout(super::Type::Array(super::ArrayType { item, length }));
331
        assert array.size == size * length and array.alignment == alignment;
332
    }
333
    let optional = super::getTypeLayout(super::Type::Optional(item));
334
    let expected = layout if super::isNullableType(ty) else super::getOptionalAggregateLayout(layout);
335
    assert optional.size == expected.size and optional.alignment == expected.alignment;
336
    let optionalStorage = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type;
337
    set *optionalStorage = super::Type::Optional(item);
338
    let optionalItem: *super::Type = optionalStorage;
339
    for length in [0 as u32, 1, 3] {
340
        let array = super::getTypeLayout(super::Type::Array(super::ArrayType { item: optionalItem, length }));
341
        assert array.size == optional.size * length and array.alignment == optional.alignment;
342
    }
343
    let nested = super::getTypeLayout(super::Type::Optional(optionalItem));
344
    let nestedExpected = super::getOptionalAggregateLayout(optional);
345
    assert nested.size == nestedExpected.size and nested.alignment == nestedExpected.alignment;
346
}
347
348
/// Storage for owned types used by array and optional layout fixtures.
349
static FIXED_LAYOUT_STORAGE: [u8; 256] = [0; 256];
350
351
/// Array layouts retain element alignment for empty and populated arrays.
352
@test fn testArrayLayoutFromElementLayout() throws (testing::TestError) {
353
    for alignment in [1 as u32, 2, 4, 8, 16] {
354
        let item = super::Layout { size: alignment, alignment };
355
        for count in [0 as u32, 1, 3] {
356
            let result = super::getArrayLayout(item, count);
357
            assert result.size == alignment * count;
358
            assert result.alignment == alignment;
359
        }
360
    }
361
}
362
363
/// Synthetic file path used for resolver tests.
364
constant MODULE_PATH: *[u8] = "/dev/test.rad";
365
366
/// Optional aggregate layouts align the tag and payload for safe callers.
367
@test fn testOptionalAggregateLayouts() throws (testing::TestError) {
368
    for alignment in [1 as u32, 2, 4, 8, 16] {
369
        for length in [0 as u32, 1, 3] {
370
            let payload = super::Layout { size: length * alignment, alignment };
371
            let layout = super::getOptionalAggregateLayout(payload);
372
            assert layout.size == (length + 1) * alignment;
373
            assert layout.alignment == alignment;
374
        }
375
    }
376
}
377
378
/// AST arena storage used by resolver tests.
379
export static AST_ARENA: [u8; 2097152] = [0; 2097152];
380
381
/// Resolver arena storage used by resolver tests.
382
static ARENA_STORAGE: [u8; 2097152] = [0; 2097152];
383
384
/// Node metadata storage used by resolver tests.
385
unsafe static NODE_DATA_STORAGE: [super::NodeData; 256] = undefined;
386
387
/// Diagnostic storage used by resolver tests.
388
unsafe static ERROR_STORAGE: [super::Error; 16] = undefined;
389
390
/// Package scope used by resolver tests.
391
unsafe static PKG_SCOPE: super::Scope = undefined;
392
393
/// One parsed module staged for permission-checked graph construction.
394
record TestModule: Copy {
395
    /// Parent identity, or nil for a package root.
396
    parentId: ?u16,
397
    /// Source module name.
398
    name: *[u8],
399
    /// Parsed module root.
400
    root: *ast::Node,
401
    /// Source text used to parse the root.
402
    source: *[u8],
403
}
404
405
/// Permission-independent module fixture populated by resolver tests.
406
export opaque record TestModuleGraph {
407
    /// Staged modules in identifier order.
408
    entries: [?TestModule; 8],
409
    /// Number of initialized staged modules.
410
    entriesLen: u32,
411
}
412
413
/// Module entries used when materializing resolver test graphs.
414
unsafe static MODULE_ENTRIES: [?*module::ModuleEntry; 8] = [nil; 8];
415
416
/// Staged module graph used by resolver tests.
417
export unsafe static MODULE_GRAPH: TestModuleGraph = TestModuleGraph {
418
    entries: [nil; 8],
419
    entriesLen: 0,
420
};
421
422
/// Module AST arena storage used by resolver tests.
423
static MODULE_ARENA_STORAGE: [u8; 16384] = [0; 16384];
424
425
/// Module AST arena used by resolver tests.
426
unsafe static MODULE_ARENA: ast::NodeArena = undefined;
427
428
/// Interned string pool used by resolver tests.
429
unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
430
431
/// String literals used in tests.
432
constant LITERALS: [*[u8]; 15] = [
433
    "Ok", "Error", "R", "S",
434
    "f", "Status", "Pending",
435
    "Some", "None", "First",
436
    "Second", "Opt", "x",
437
    "value", "idx"
438
];
439
440
/// Resolver result with AST, used by test helpers.
441
export record TestResult: Copy {
442
    /// Diagnostics from semantic analysis.
443
    diagnostics: super::Diagnostics,
444
    /// Root of the parsed test program.
445
    root: *ast::Node,
446
}
447
448
/// Create isolated storage for tests to avoid conflicts with global resolver storage.
449
unsafe fn testStorage() -> super::ResolverStorage {
450
    return super::ResolverStorage {
451
        nodeData: &mut NODE_DATA_STORAGE[..],
452
        pkgScope: &mut PKG_SCOPE,
453
        errors: &mut ERROR_STORAGE[..],
454
    };
455
}
456
457
/// Create an arena owner for one resolver test scope.
458
export unsafe fn testArena() -> alloc::Arena {
459
    return alloc::new(&mut ARENA_STORAGE[..]);
460
}
461
462
/// Construct a resolver backed by test storage.
463
export unsafe fn testResolver 'arena (arena: &'arena mut alloc::Arena) -> super::Resolver 'arena {
464
    // TODO: This should be initialized only once.
465
    for i in 0..LITERALS.len {
466
        strings::intern(&mut STRING_POOL, LITERALS[i]);
467
    }
468
    set MODULE_GRAPH.entriesLen = 0;
469
    let config = super::Config { buildTest: true };
470
    let res = super::resolver(arena, testStorage(), config);
471
472
    return res;
473
}
474
475
/// Resolve a block of statements by wrapping them in a synthetic function.
476
unsafe fn resolveStatements 'arena (
477
    self: &mut super::Resolver 'arena, block: ast::Block, arena: &mut ast::NodeArena
478
) -> TestResult throws (super::ResolveError) {
479
    let module = ast::synthFnModule(arena, super::ANALYZE_BLOCK_FN_NAME, block.statements);
480
    let diagnostics = try super::resolveModuleRoot(self, module.modBody) catch {
481
        return TestResult { diagnostics: super::diagnostics(self), root: module.modBody };
482
    };
483
    return TestResult { diagnostics, root: module.fnBody };
484
}
485
486
/// Parse and analyze an expression string for testing.
487
unsafe fn resolveExprStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
488
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
489
    let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in {
490
        let mut p = parser::mkParser(scanner::SourceLoc::String, stmt, arenaRef, poolRef);
491
        parser::advance(&mut p);
492
493
        let expr = try parser::parseExpr(&mut p) catch {
494
            panic "resolveExprStr: parsing failed";
495
        };
496
        let diagnostics = try super::resolveExpr(self, expr, p.arena) catch {
497
            throw testing::TestError::Failed;
498
        };
499
        return TestResult { diagnostics, root: expr };
500
    }
501
}
502
503
/// Parse and analyze a module string for testing.
504
/// Use this for code with `fn`, `record`, `union`, etc. at the top level.
505
export unsafe fn resolveProgramStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
506
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
507
    let stmt: *ast::Node = try parser::parse(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL) catch {
508
        panic "resolveProgramStr: parsing failed";
509
    };
510
    let diagnostics = try super::resolveModuleRoot(self, stmt) catch {
511
        throw testing::TestError::Failed;
512
    };
513
    return TestResult { diagnostics, root: stmt };
514
}
515
516
/// Resolve session diagnostics against the standard allocator declaration contract.
517
export unsafe fn resolveSessionProgramStr 'arena (
518
    self: &mut super::Resolver 'arena,
519
    program: *[u8]
520
) -> TestResult throws (testing::TestError) {
521
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
522
    let root = try registerModule(
523
        &mut MODULE_GRAPH, nil, "std", "export mod lang; mod app;", &mut arena
524
    );
525
    let lang = try registerModule(
526
        &mut MODULE_GRAPH, root, "lang", "export mod alloc;", &mut arena
527
    );
528
    let allocator = try registerModule(&mut MODULE_GRAPH, lang, "alloc",
529
        "export record Arena { data: *mut [u8], offset: u32 } export fn reset(arena: &mut Arena) { set arena.offset = 0; } export union AllocError: Copy { OutOfMemory } export trait Alloc { unsafe fn (&mut Alloc) reserve(size: u32, alignment: u32) -> *unsafe mut opaque throws (AllocError); unsafe fn (&mut Alloc) reserveSlice(itemSize: u32, itemAlignment: u32, count: u32) -> *unsafe mut [opaque] throws (AllocError); } instance Alloc for Arena { unsafe fn (arena: &mut Arena) reserve(size: u32, alignment: u32) -> *unsafe mut opaque throws (AllocError) { panic; } unsafe fn (arena: &mut Arena) reserveSlice(size: u32, alignment: u32, count: u32) -> *unsafe mut [opaque] throws (AllocError) { panic; } }",
530
        &mut arena);
531
    let app = try registerModule(&mut MODULE_GRAPH, root, "app", program, &mut arena);
532
    return try resolveModuleTree(self, root);
533
}
534
535
/// Parse and analyze a block of statements (eg. inside a function body) for testing.
536
/// Use this for code with `let` bindings and expressions, not module-level declarations.
537
unsafe fn resolveBlockStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
538
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
539
    let parsed = try parser::parse(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL) catch {
540
        panic "resolveBlockStr: parsing failed";
541
    };
542
    let case ast::NodeValue::Block(block) = parsed.value
543
        else panic "resolveBlockStr: expected block root";
544
545
    let analysis = try resolveStatements(self, block, &mut arena) catch {
546
        throw testing::TestError::Failed;
547
    };
548
    return TestResult {
549
        diagnostics: analysis.diagnostics,
550
        root: analysis.root,
551
    };
552
}
553
554
/// Materialize staged modules under one externally owned permission.
555
unsafe fn materializeModuleGraph 'permission (
556
    fixture: &TestModuleGraph,
557
    permission: &'permission mut module::Permission
558
) -> module::ModuleGraph 'permission throws (testing::TestError) {
559
    set MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]);
560
    let mut graph = module::moduleGraph(
561
        &mut MODULE_ENTRIES[..], &mut MODULE_ARENA, permission
562
    );
563
    for i in 0..fixture.entriesLen {
564
        let staged = fixture.entries[i] else throw testing::TestError::Failed;
565
        let id = if let parentId = staged.parentId {
566
            try module::registerChild(
567
                &mut graph, &mut STRING_POOL, parentId, staged.name, "<test>"
568
            ) catch {
569
                throw testing::TestError::Failed;
570
            }
571
        } else {
572
            try module::registerRootWithName(
573
                &mut graph, &mut STRING_POOL, 0, staged.name, "<test>"
574
            ) catch {
575
                throw testing::TestError::Failed;
576
            }
577
        };
578
        if id as u32 != i {
579
            throw testing::TestError::Failed;
580
        }
581
        try module::setAst(&mut graph, id, staged.root) catch {
582
            throw testing::TestError::Failed;
583
        };
584
        try module::setSource(&mut graph, id, staged.source) catch {
585
            throw testing::TestError::Failed;
586
        };
587
    }
588
    return graph;
589
}
590
591
/// Print module diagnostics using a freshly materialized permission-checked graph.
592
export unsafe fn printDiagnostics 'arena (
593
    diagnostics: &super::Diagnostics,
594
    res: &super::Resolver 'arena
595
) {
596
    let mut owner = module::Permission {};
597
    let permission: 'permission = &mut owner in {
598
        let graph = try! materializeModuleGraph(&MODULE_GRAPH, permission);
599
        super::printer::printDiagnostics(diagnostics, res, &graph);
600
    }
601
}
602
603
/// Resolve a staged module tree with the full resolution process.
604
export unsafe fn resolveModuleTree 'arena (
605
    res: &mut super::Resolver 'arena,
606
    rootId: u16
607
) -> TestResult throws (testing::TestError) {
608
    let mut owner = module::Permission {};
609
    let permission: 'permission = &mut owner in {
610
        let graph = try materializeModuleGraph(&MODULE_GRAPH, permission);
611
        let root = module::get(&graph, rootId)
612
            else throw testing::TestError::Failed;
613
        let rootAst = module::astFor(&graph, root)
614
            else throw testing::TestError::Failed;
615
        let packages = [super::Pkg {
616
            rootEntry: root,
617
            rootAst,
618
        }];
619
        let diagnostics = try super::resolve(
620
            res, &graph, &packages[..]
621
        ) catch {
622
            throw testing::TestError::Failed;
623
        };
624
        return TestResult { diagnostics, root: rootAst };
625
    }
626
}
627
628
/// Register a parsed module in the permission-independent test fixture.
629
/// If `parentId` is nil, registers a root module.
630
export unsafe fn registerModule(
631
    graph: &mut TestModuleGraph,
632
    parentId: ?u16,
633
    name: *[u8],
634
    code: *[u8],
635
    arena: &mut ast::NodeArena
636
) -> u16 throws (testing::TestError) {
637
    if graph.entriesLen >= graph.entries.len {
638
        throw testing::TestError::Failed;
639
    }
640
    let root = try parser::parse(
641
        scanner::SourceLoc::String, code, arena, &mut STRING_POOL
642
    ) catch {
643
        panic "registerModule: parsing failed";
644
    };
645
    let id = graph.entriesLen as u16;
646
    set graph.entries[graph.entriesLen] = TestModule {
647
        parentId,
648
        name,
649
        root,
650
        source: code,
651
    };
652
    set graph.entriesLen += 1;
653
    return id;
654
}
655
656
/// Ensure an expression statement produces the expected type and return the expression node.
657
fn expectExprStmtType 'arena (self: &super::Resolver 'arena, node: *ast::Node, expected: super::Type) -> *ast::Node
658
    throws (testing::TestError)
659
{
660
    let case ast::NodeValue::ExprStmt(expr) = node.value
661
        else throw testing::TestError::Failed;
662
    try expectType(self, expr, expected);
663
664
    return expr;
665
}
666
667
/// Assert that the test result contains no diagnostic errors.
668
export fn expectNoErrors(r: &TestResult) throws (testing::TestError) {
669
    try testing::expect(super::success(&r.diagnostics));
670
}
671
672
/// Extract the first error from a test result, failing if none exists.
673
export fn expectError(result: &TestResult) -> super::Error throws (testing::TestError) {
674
    let err = super::errorAt(&result.diagnostics.errors[..], 0)
675
        else throw testing::TestError::Failed;
676
    return err;
677
}
678
679
/// Check if two error kinds match.
680
fn errorKindMatches(actual: &super::ErrorKind, expected: super::ErrorKind) -> bool {
681
    if let case super::ErrorKind::DuplicateBinding(expectedName) = expected {
682
        if let case super::ErrorKind::DuplicateBinding(actualName) = *actual {
683
            return mem::eq(actualName, expectedName);
684
        }
685
        return false;
686
    }
687
    if let case super::ErrorKind::UnresolvedSymbol(expectedName) = expected {
688
        if let case super::ErrorKind::UnresolvedSymbol(actualName) = *actual {
689
            return mem::eq(actualName, expectedName);
690
        }
691
        return false;
692
    }
693
    if let case super::ErrorKind::RecordFieldMissing(expectedName) = expected {
694
        if let case super::ErrorKind::RecordFieldMissing(actualName) = *actual {
695
            return mem::eq(actualName, expectedName);
696
        }
697
        return false;
698
    }
699
    if let case super::ErrorKind::RecordFieldUnknown(expectedName) = expected {
700
        if let case super::ErrorKind::RecordFieldUnknown(actualName) = *actual {
701
            return mem::eq(actualName, expectedName);
702
        }
703
        return false;
704
    }
705
    if let case super::ErrorKind::ArrayFieldUnknown(expectedName) = expected {
706
        if let case super::ErrorKind::ArrayFieldUnknown(actualName) = *actual {
707
            return mem::eq(actualName, expectedName);
708
        }
709
        return false;
710
    }
711
    if let case super::ErrorKind::SliceFieldUnknown(expectedName) = expected {
712
        if let case super::ErrorKind::SliceFieldUnknown(actualName) = *actual {
713
            return mem::eq(actualName, expectedName);
714
        }
715
        return false;
716
    }
717
    if let case super::ErrorKind::UnionVariantPayloadMissing(expectedName) = expected {
718
        if let case super::ErrorKind::UnionVariantPayloadMissing(actualName) = *actual {
719
            return mem::eq(actualName, expectedName);
720
        }
721
        return false;
722
    }
723
    if let case super::ErrorKind::UnionVariantPayloadUnexpected(expectedName) = expected {
724
        if let case super::ErrorKind::UnionVariantPayloadUnexpected(actualName) = *actual {
725
            return mem::eq(actualName, expectedName);
726
        }
727
        return false;
728
    }
729
    if let case super::ErrorKind::UnionMatchNonExhaustive(expectedName) = expected {
730
        if let case super::ErrorKind::UnionMatchNonExhaustive(actualName) = *actual {
731
            return mem::eq(actualName, expectedName);
732
        }
733
        return false;
734
    }
735
    if let case super::ErrorKind::MissingTraitMethod(expectedName) = expected {
736
        if let case super::ErrorKind::MissingTraitMethod(actualName) = *actual {
737
            return mem::eq(actualName, expectedName);
738
        }
739
        return false;
740
    }
741
    if let case super::ErrorKind::MissingSupertraitInstance(expectedName) = expected {
742
        if let case super::ErrorKind::MissingSupertraitInstance(actualName) = *actual {
743
            return mem::eq(actualName, expectedName);
744
        }
745
        return false;
746
    }
747
    if let case super::ErrorKind::AffineUseAfterMove(expectedName) = expected {
748
        if let case super::ErrorKind::AffineUseAfterMove(actualName) = *actual {
749
            return mem::eq(actualName, expectedName);
750
        }
751
        return false;
752
    }
753
    if let case super::ErrorKind::LinearUseAfterConsume(expectedName) = expected {
754
        if let case super::ErrorKind::LinearUseAfterConsume(actualName) = *actual {
755
            return mem::eq(actualName, expectedName);
756
        }
757
        return false;
758
    }
759
    if let case super::ErrorKind::LinearNotConsumed(expectedName) = expected {
760
        if let case super::ErrorKind::LinearNotConsumed(actualName) = *actual {
761
            return mem::eq(actualName, expectedName);
762
        }
763
        return false;
764
    }
765
    if let case super::ErrorKind::LinearBranchMismatch(expectedName) = expected {
766
        if let case super::ErrorKind::LinearBranchMismatch(actualName) = *actual {
767
            return mem::eq(actualName, expectedName);
768
        }
769
        return false;
770
    }
771
    if let case super::ErrorKind::BorrowConflict(expectedName) = expected {
772
        if let case super::ErrorKind::BorrowConflict(actualName) = *actual {
773
            return mem::eq(actualName, expectedName);
774
        }
775
        return false;
776
    }
777
    return *actual == expected;
778
}
779
780
/// Extract the first error and ensure it has the expected kind.
781
export fn expectErrorKind(result: &TestResult, kind: super::ErrorKind) -> super::Error
782
    throws (testing::TestError)
783
{
784
    let err = try expectError(result);
785
    try testing::expect(errorKindMatches(&err.kind, kind));
786
    return err;
787
}
788
789
/// Ensure an expression resolves to the expected type annotation.
790
fn expectType 'arena (self: &super::Resolver 'arena, expr: *ast::Node, expected: super::Type)
791
    throws (testing::TestError)
792
{
793
    let actual = super::typeFor(self, expr)
794
        else throw testing::TestError::Failed;
795
796
    if actual <> expected {
797
        throw testing::TestError::Failed;
798
    }
799
}
800
801
/// Verify that an error represents a specific type mismatch.
802
fn expectTypeMismatch(err: super::Error, expected: super::Type, actual: super::Type)
803
    throws (testing::TestError)
804
{
805
    let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
806
        else throw testing::TestError::Failed;
807
    try testing::expect(mismatch.expected == expected);
808
    try testing::expect(mismatch.actual == actual);
809
}
810
811
/// Resolve a program and require successful analysis.
812
unsafe fn expectAnalyzeOk(program: *[u8]) throws (testing::TestError) {
813
    let mut testArena1 = testArena();
814
    let testStorage1: 'test1 = &mut testArena1 in {
815
        let mut a = testResolver(testStorage1);
816
        let result = try resolveProgramStr(&mut a, program);
817
        try expectNoErrors(&result);
818
    }
819
}
820
821
/// Require an inferred integer type mismatch.
822
unsafe fn expectIntMismatch(program: *[u8], expected: super::Type)
823
    throws (testing::TestError)
824
{
825
    let mut testArena2 = testArena();
826
    let testStorage2: 'test2 = &mut testArena2 in {
827
        let mut a = testResolver(testStorage2);
828
        let result = try resolveProgramStr(&mut a, program);
829
        let err = try expectError(&result);
830
        try expectTypeMismatch(err, expected, super::Type::Int);
831
    }
832
}
833
834
/// Retrieve the nth statement from a block node.
835
export fn getBlockStmt(block: *ast::Node, index: u32) -> *ast::Node
836
    throws (testing::TestError)
837
{
838
    let case ast::NodeValue::Block(body) = block.value
839
        else throw testing::TestError::Failed;
840
841
    if index >= body.statements.len {
842
        throw testing::TestError::Failed;
843
    }
844
    return body.statements[index];
845
}
846
847
/// Retrieve a function body block by function name from the program scope.
848
unsafe fn getFnBody 'arena (a: &super::Resolver 'arena, root: *ast::Node, name: *[u8]) -> ast::Block
849
    throws (testing::TestError)
850
{
851
    let scope = super::scopeFor(a, root)
852
        else throw testing::TestError::Failed;
853
    let sym = super::findSymbolInScope(scope, name)
854
        else throw testing::TestError::Failed;
855
    // Verify it's a value symbol by pattern matching.
856
    let case super::SymbolData::Value { .. } = sym.data
857
        else throw testing::TestError::Failed;
858
859
    let case ast::NodeValue::FnDecl(fnDecl) = sym.node.value
860
        else throw testing::TestError::Failed;
861
862
    let body = fnDecl.body
863
        else throw testing::TestError::Failed;
864
    let case ast::NodeValue::Block(blk) = body.value
865
        else throw testing::TestError::Failed;
866
867
    return blk;
868
}
869
870
/// Get the payload type of a union variant, if it has one.
871
/// For single-field unlabeled variants like `Variant(i32)`, unwraps to return the inner type.
872
unsafe fn getUnionVariantPayload(nominalTy: *unsafe super::NominalType, variantName: *[u8]) -> super::Type {
873
    let case super::NominalType::Union(unionType) = *nominalTy
874
        else panic "getUnionVariantPayload: not a union";
875
    for i in 0..unionType.variants.len {
876
        if mem::eq(unionType.variants[i].name, variantName) {
877
            let payloadType = unionType.variants[i].valueType;
878
            // Unwrap single-field unlabeled records to get the inner type.
879
            if let case super::Type::Nominal(super::NominalType::Record(recInfo)) = payloadType {
880
                if not recInfo.labeled and recInfo.fields.len == 1 {
881
                    return recInfo.fields[0].fieldType;
882
                }
883
            }
884
            return payloadType;
885
        }
886
    }
887
    panic "getUnionVariantPayload: variant not found";
888
}
889
890
/// Get a nominal type by name, in the scope of the given block node.
891
unsafe fn getTypeInScopeOf 'arena (a: &super::Resolver 'arena, blk: *ast::Node, name: *[u8]) -> *unsafe super::NominalType
892
    throws (testing::TestError)
893
{
894
    let scope = super::scopeFor(a, blk)
895
        else throw testing::TestError::Failed;
896
    let sym = super::findSymbolInScope(scope, name)
897
        else throw testing::TestError::Failed;
898
    let case super::SymbolData::Type(ty) = sym.data
899
        else throw testing::TestError::Failed;
900
    return ty;
901
}
902
903
/// Return the resolved type of a syntax node.
904
fn typeOf 'arena (a: &super::Resolver 'arena, node: *ast::Node) -> super::Type
905
    throws (testing::TestError)
906
{
907
    let ty = super::typeFor(a, node)
908
        else throw testing::TestError::Failed;
909
    return ty;
910
}
911
912
/// Require an array type and return its element type.
913
fn expectArrayType(ty: super::Type, length: u32) -> super::Type
914
    throws (testing::TestError)
915
{
916
    let case super::Type::Array(info) = ty
917
        else throw testing::TestError::Failed;
918
    try testing::expect(info.length == length);
919
920
    return *info.item;
921
}
922
923
/// Require a slice type and return its element type.
924
fn expectSliceType(ty: super::Type, mutable: bool) -> super::Type
925
    throws (testing::TestError)
926
{
927
    let case super::Type::Slice { item, mutable: sliceMut, .. } = ty
928
        else throw testing::TestError::Failed;
929
    try testing::expect(sliceMut == mutable);
930
931
    return *item;
932
}
933
934
/// Require a pointer type and return its target type.
935
fn expectPointerType(ty: super::Type, mutable: bool) -> super::Type
936
    throws (testing::TestError)
937
{
938
    let case super::Type::Pointer { target, mutable: ptrMut, .. } = ty
939
        else throw testing::TestError::Failed;
940
    try testing::expect(ptrMut == mutable);
941
942
    return *target;
943
}
944
945
/// Verify that a node has a constant integer value with the expected magnitude.
946
fn expectConstInt 'arena (a: &super::Resolver 'arena, node: *ast::Node, expected: u32)
947
    throws (testing::TestError)
948
{
949
    let constVal = super::constValueEntry(a, node)
950
        else throw testing::TestError::Failed;
951
952
    let case super::ConstValue::Int(int) = constVal
953
        else throw testing::TestError::Failed;
954
955
    try testing::expect(int.magnitude == expected);
956
}
957
958
/// Resolve an expression that should evaluate to a constant, and verify it equals the expected value.
959
unsafe fn resolveAndExpectConstExpr(expr: *[u8], expected: u32)
960
    throws (testing::TestError)
961
{
962
    let mut testArena3 = testArena();
963
    let testStorage3: 'test3 = &mut testArena3 in {
964
        let mut a = testResolver(testStorage3);
965
        let result = try resolveExprStr(&mut a, expr);
966
        try expectNoErrors(&result);
967
        try expectType(&a, result.root, super::Type::U32);
968
        try expectConstInt(&a, result.root, expected);
969
    }
970
}
971
972
/// Resolve a statement that should evaluate to a constant, and verify it equals the expected value.
973
unsafe fn resolveAndExpectConstStmt(expr: *[u8], expected: u32)
974
    throws (testing::TestError)
975
{
976
    let mut testArena4 = testArena();
977
    let testStorage4: 'test4 = &mut testArena4 in {
978
        let mut a = testResolver(testStorage4);
979
        let result = try resolveProgramStr(&mut a, expr);
980
        try expectNoErrors(&result);
981
        let stmt = try getBlockStmt(result.root, 1);
982
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
983
        try expectConstInt(&a, expr, expected);
984
    }
985
}
986
987
// Tests ///////////////////////////////////////////////////////////////////////
988
989
@test unsafe fn testResolveLit() throws (testing::TestError) {
990
    let mut testArena5 = testArena();
991
    let testStorage5: 'test5 = &mut testArena5 in {
992
        let mut a = testResolver(testStorage5);
993
        let result = try resolveExprStr(&mut a, "true");
994
995
        try expectNoErrors(&result);
996
        try expectType(&a, result.root, super::Type::Bool);
997
    }
998
}
999
1000
@test unsafe fn testResolveStringLiteralType() throws (testing::TestError) {
1001
    let mut testArena6 = testArena();
1002
    let testStorage6: 'test6 = &mut testArena6 in {
1003
        let mut a = testResolver(testStorage6);
1004
        let result = try resolveExprStr(&mut a, "\"hello\"");
1005
1006
        try expectNoErrors(&result);
1007
        let ty = try typeOf(&a, result.root);
1008
        let elemTy = try expectSliceType(ty, false);
1009
        try testing::expect(elemTy == super::Type::U8);
1010
    }
1011
}
1012
1013
@test unsafe fn testResolveAsNumeric() throws (testing::TestError) {
1014
    {
1015
        let mut testArena7 = testArena();
1016
        let testStorage7: 'test7 = &mut testArena7 in {
1017
            let mut a = testResolver(testStorage7);
1018
            let result = try resolveExprStr(&mut a, "1 as u32");
1019
            try expectNoErrors(&result);
1020
            try expectType(&a, result.root, super::Type::U32);
1021
        }
1022
    } {
1023
        let mut testArena8 = testArena();
1024
        let testStorage8: 'test8 = &mut testArena8 in {
1025
            let mut a = testResolver(testStorage8);
1026
            let result = try resolveBlockStr(&mut a, "let x: u32 = 913; x as u8;");
1027
            try expectNoErrors(&result);
1028
1029
            let x = try getBlockStmt(result.root, 1);
1030
            try expectExprStmtType(&a, x, super::Type::U8);
1031
        }
1032
    }
1033
}
1034
1035
@test unsafe fn testResolveAsInvalid() throws (testing::TestError) {
1036
    let mut testArena9 = testArena();
1037
    let testStorage9: 'test9 = &mut testArena9 in {
1038
        let mut a = testResolver(testStorage9);
1039
        let result = try resolveProgramStr(&mut a, "true as u32");
1040
1041
        try expectErrorKind(
1042
            &result,
1043
            super::ErrorKind::InvalidAsCast(super::InvalidAsCast {
1044
                from: super::Type::Bool,
1045
                to: super::Type::U32,
1046
        })
1047
        );
1048
    }
1049
}
1050
1051
@test unsafe fn testResolveAsUnionToInt() throws (testing::TestError) {
1052
    let mut testArena10 = testArena();
1053
    let testStorage10: 'test10 = &mut testArena10 in {
1054
        let mut a = testResolver(testStorage10);
1055
        let program = "union Color { Red } Color::Red as u32;";
1056
        let result = try resolveProgramStr(&mut a, program);
1057
        try expectNoErrors(&result);
1058
1059
        let red = try getBlockStmt(result.root, 1);
1060
        try expectExprStmtType(&a, red, super::Type::U32);
1061
    }
1062
}
1063
1064
@test unsafe fn testResolveBinding() throws (testing::TestError) {
1065
    let mut testArena11 = testArena();
1066
    let testStorage11: 'test11 = &mut testArena11 in {
1067
        let mut a = testResolver(testStorage11);
1068
        let result = try resolveBlockStr(&mut a, "let x: bool = true; x;");
1069
        let stmt = try parser::tests::getBlockLastStmt(result.root);
1070
1071
        try expectNoErrors(&result);
1072
        try expectType(&a, stmt, super::Type::Void);
1073
        try expectExprStmtType(&a, stmt, super::Type::Bool);
1074
1075
        let case ast::NodeValue::ExprStmt(x) = stmt.value
1076
            else throw testing::TestError::Failed;
1077
1078
        let sym = super::symbolFor(&a, x)
1079
            else throw testing::TestError::Failed;
1080
        let case super::SymbolData::Value { type: valType, .. } = sym.data
1081
            else throw testing::TestError::Failed;
1082
        try testing::expect(valType == super::Type::Bool);
1083
    }
1084
}
1085
1086
@test unsafe fn testResolveBindingInvalid() throws (testing::TestError) {
1087
    let mut testArena12 = testArena();
1088
    let testStorage12: 'test12 = &mut testArena12 in {
1089
        let mut a = testResolver(testStorage12);
1090
        let result = try resolveBlockStr(&mut a, "let x: i32 = true;");
1091
        let err = try expectError(&result);
1092
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
1093
    }
1094
}
1095
1096
@test unsafe fn testResolveDuplicateBinding() throws (testing::TestError) {
1097
    let mut testArena13 = testArena();
1098
    let testStorage13: 'test13 = &mut testArena13 in {
1099
        let mut a = testResolver(testStorage13);
1100
        let result = try resolveBlockStr(&mut a, "let x: bool = true; let x: u8 = 1;");
1101
        let stmt = try parser::tests::getBlockLastStmt(result.root);
1102
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("x"));
1103
    }
1104
}
1105
1106
@test unsafe fn testResolveConstLiteralValue() throws (testing::TestError) {
1107
    let mut testArena14 = testArena();
1108
    let testStorage14: 'test14 = &mut testArena14 in {
1109
        let mut a = testResolver(testStorage14);
1110
        let program = "constant ANSWER: i32 = 42;";
1111
        let result = try resolveProgramStr(&mut a, program);
1112
        try expectNoErrors(&result);
1113
1114
        let constNode = try getBlockStmt(result.root, 0);
1115
        let sym = super::symbolFor(&a, constNode)
1116
            else throw testing::TestError::Failed;
1117
        let case super::SymbolData::Constant { type: constType, .. } = sym.data
1118
            else throw testing::TestError::Failed;
1119
        try testing::expect(constType == super::Type::I32);
1120
    }
1121
}
1122
1123
@test unsafe fn testResolveConstRequiresConstantExpr() throws (testing::TestError) {
1124
    let mut testArena15 = testArena();
1125
    let testStorage15: 'test15 = &mut testArena15 in {
1126
        let mut a = testResolver(testStorage15);
1127
        let program = "fn value() -> i32 { return 1 } fn main() { constant ANSWER: i32 = value(); }";
1128
        let result = try resolveProgramStr(&mut a, program);
1129
        let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
1130
1131
        let errNode = err.node
1132
            else throw testing::TestError::Failed;
1133
        let case ast::NodeValue::Call(_) = errNode.value
1134
            else throw testing::TestError::Failed;
1135
    }
1136
}
1137
1138
@test unsafe fn testResolveStaticLiteralValue() throws (testing::TestError) {
1139
    let mut testArena16 = testArena();
1140
    let testStorage16: 'test16 = &mut testArena16 in {
1141
        let mut a = testResolver(testStorage16);
1142
        let program = "static COUNTER: i32 = 0;";
1143
        let result = try resolveProgramStr(&mut a, program);
1144
        try expectNoErrors(&result);
1145
1146
        let staticNode = try getBlockStmt(result.root, 0);
1147
        let sym = super::symbolFor(&a, staticNode)
1148
            else throw testing::TestError::Failed;
1149
        let case super::SymbolData::Value { type: valType, .. } = sym.data
1150
            else throw testing::TestError::Failed;
1151
        try testing::expect(valType == super::Type::I32);
1152
    }
1153
}
1154
1155
@test unsafe fn testResolveStaticRequiresConstantExpr() throws (testing::TestError) {
1156
    let mut testArena17 = testArena();
1157
    let testStorage17: 'test17 = &mut testArena17 in {
1158
        let mut a = testResolver(testStorage17);
1159
        let program = "fn seed() -> i32 { return 1; } static COUNTER: i32 = seed();";
1160
        let result = try resolveProgramStr(&mut a, program);
1161
        let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
1162
1163
        let errNode = err.node
1164
            else throw testing::TestError::Failed;
1165
        let case ast::NodeValue::Call(_) = errNode.value
1166
            else throw testing::TestError::Failed;
1167
    }
1168
}
1169
1170
@test unsafe fn testSymbolStoresFnAttributes() throws (testing::TestError) {
1171
    let mut testArena18 = testArena();
1172
    let testStorage18: 'test18 = &mut testArena18 in {
1173
        let mut a = testResolver(testStorage18);
1174
        let program = "@default export fn f() { return; }";
1175
        let result = try resolveProgramStr(&mut a, program);
1176
        try expectNoErrors(&result);
1177
1178
        let scope = super::scopeFor(&a, result.root)
1179
            else throw testing::TestError::Failed;
1180
        let sym = super::findSymbolInScope(scope, "f")
1181
            else throw testing::TestError::Failed;
1182
1183
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Export));
1184
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Default));
1185
        try testing::expectNot(ast::hasAttribute(sym.attrs, ast::Attribute::Extern));
1186
    }
1187
}
1188
1189
@test unsafe fn testSymbolStoresRecordAttributes() throws (testing::TestError) {
1190
    let mut testArena19 = testArena();
1191
    let testStorage19: 'test19 = &mut testArena19 in {
1192
        let mut a = testResolver(testStorage19);
1193
        let program = "export record S { value: i32 }";
1194
        let result = try resolveProgramStr(&mut a, program);
1195
        try expectNoErrors(&result);
1196
1197
        let scope = super::scopeFor(&a, result.root)
1198
            else throw testing::TestError::Failed;
1199
        let sym = super::findSymbolInScope(scope, "S")
1200
            else throw testing::TestError::Failed;
1201
1202
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Export));
1203
        try testing::expectNot(ast::hasAttribute(sym.attrs, ast::Attribute::Default));
1204
    }
1205
}
1206
1207
@test unsafe fn testDefaultAttributeRejectedOnRecord() throws (testing::TestError) {
1208
    let mut testArena20 = testArena();
1209
    let testStorage20: 'test20 = &mut testArena20 in {
1210
        let mut a = testResolver(testStorage20);
1211
        let program = "@default record T { value: i32 }";
1212
        let result = try resolveProgramStr(&mut a, program);
1213
        try expectErrorKind(&result, super::ErrorKind::DefaultAttrOnlyOnFn);
1214
    }
1215
}
1216
1217
@test unsafe fn testDefaultAttributeRejectedOnUnion() throws (testing::TestError) {
1218
    let mut testArena21 = testArena();
1219
    let testStorage21: 'test21 = &mut testArena21 in {
1220
        let mut a = testResolver(testStorage21);
1221
        let program = "@default union Result { Ok, Err }";
1222
        let result = try resolveProgramStr(&mut a, program);
1223
        try expectErrorKind(&result, super::ErrorKind::DefaultAttrOnlyOnFn);
1224
    }
1225
}
1226
1227
@test unsafe fn testResolveArrayLiteralTyped() throws (testing::TestError) {
1228
    let mut testArena22 = testArena();
1229
    let testStorage22: 'test22 = &mut testArena22 in {
1230
        let mut a = testResolver(testStorage22);
1231
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1, 2];");
1232
        try expectNoErrors(&result);
1233
1234
        let stmt = try getBlockStmt(result.root, 0);
1235
        let case ast::NodeValue::Let(decl) = stmt.value
1236
            else throw testing::TestError::Failed;
1237
        let arrayTy = try typeOf(&a, decl.value);
1238
        let elemTy = try expectArrayType(arrayTy, 2);
1239
        try testing::expect(elemTy == super::Type::I32);
1240
    }
1241
}
1242
1243
@test unsafe fn testResolveArrayLiteralElementMismatch() throws (testing::TestError) {
1244
    let mut testArena23 = testArena();
1245
    let testStorage23: 'test23 = &mut testArena23 in {
1246
        let mut a = testResolver(testStorage23);
1247
        let result = try resolveProgramStr(&mut a, "let xs: [bool; 2] = [true, 1];");
1248
        let err = try expectError(&result);
1249
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1250
    }
1251
}
1252
1253
@test unsafe fn testResolveArrayLiteralCannotInfer() throws (testing::TestError) {
1254
    let mut testArena24 = testArena();
1255
    let testStorage24: 'test24 = &mut testArena24 in {
1256
        let mut a = testResolver(testStorage24);
1257
        let result = try resolveProgramStr(&mut a, "let xs = [1, 2];");
1258
        try expectErrorKind(&result, super::ErrorKind::CannotInferType);
1259
    }
1260
}
1261
1262
@test unsafe fn testResolveArrayLiteralOverflow() throws (testing::TestError) {
1263
    let mut testArena25 = testArena();
1264
    let testStorage25: 'test25 = &mut testArena25 in {
1265
        let mut a = testResolver(testStorage25);
1266
        let result = try resolveProgramStr(&mut a, "let xs: [u8; 2] = [1, 256];");
1267
        let err = try expectError(&result);
1268
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1269
            else throw testing::TestError::Failed;
1270
    }
1271
}
1272
1273
@test unsafe fn testResolveArrayLiteralTooFewElements() throws (testing::TestError) {
1274
    let mut testArena26 = testArena();
1275
    let testStorage26: 'test26 = &mut testArena26 in {
1276
        let mut a = testResolver(testStorage26);
1277
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1];");
1278
        let err = try expectError(&result);
1279
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1280
            else throw testing::TestError::Failed;
1281
    }
1282
}
1283
1284
@test unsafe fn testResolveArrayLiteralTooManyElements() throws (testing::TestError) {
1285
    let mut testArena27 = testArena();
1286
    let testStorage27: 'test27 = &mut testArena27 in {
1287
        let mut a = testResolver(testStorage27);
1288
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1, 2, 3];");
1289
        let err = try expectError(&result);
1290
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1291
            else throw testing::TestError::Failed;
1292
    }
1293
}
1294
1295
@test unsafe fn testResolveArrayLiteralEmptyWithAnnotation() throws (testing::TestError) {
1296
    let mut testArena28 = testArena();
1297
    let testStorage28: 'test28 = &mut testArena28 in {
1298
        let mut a = testResolver(testStorage28);
1299
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 0] = [];");
1300
        try expectNoErrors(&result);
1301
    }
1302
}
1303
1304
@test unsafe fn testResolveNestedArrayLiteralTyped() throws (testing::TestError) {
1305
    let mut testArena29 = testArena();
1306
    let testStorage29: 'test29 = &mut testArena29 in {
1307
        let mut a = testResolver(testStorage29);
1308
        let result = try resolveProgramStr(&mut a, "let grid: [[i32; 2]; 2] = [[1, 2], [3, 4]];");
1309
        try expectNoErrors(&result);
1310
1311
        let stmt = try getBlockStmt(result.root, 0);
1312
        let case ast::NodeValue::Let(decl) = stmt.value
1313
            else throw testing::TestError::Failed;
1314
        let gridTy = try typeOf(&a, decl.value);
1315
        let rowTy = try expectArrayType(gridTy, 2);
1316
        let elemTy = try expectArrayType(rowTy, 2);
1317
        try testing::expect(elemTy == super::Type::I32);
1318
    }
1319
}
1320
1321
@test unsafe fn testResolveArrayLiteralWithOptionalElems() throws (testing::TestError) {
1322
    let mut testArena30 = testArena();
1323
    let testStorage30: 'test30 = &mut testArena30 in {
1324
        let mut a = testResolver(testStorage30);
1325
        let result = try resolveProgramStr(&mut a, "let xs: [?i32; 2] = [1, 2];");
1326
        try expectNoErrors(&result);
1327
1328
        let stmt = try getBlockStmt(result.root, 0);
1329
        let case ast::NodeValue::Let(decl) = stmt.value
1330
            else throw testing::TestError::Failed;
1331
        let arrayTy = try typeOf(&a, decl.value);
1332
        let elemTy = try expectArrayType(arrayTy, 2);
1333
        let case super::Type::Optional(inner) = elemTy
1334
            else throw testing::TestError::Failed;
1335
        try testing::expect(*inner == super::Type::I32);
1336
    }
1337
}
1338
1339
@test unsafe fn testResolveArrayLiteralOptionalMismatch() throws (testing::TestError) {
1340
    let mut testArena31 = testArena();
1341
    let testStorage31: 'test31 = &mut testArena31 in {
1342
        let mut a = testResolver(testStorage31);
1343
        let result = try resolveProgramStr(&mut a, "let xs: [?bool; 2] = [1, 2];");
1344
        let err = try expectError(&result);
1345
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1346
            else throw testing::TestError::Failed;
1347
    }
1348
}
1349
1350
@test unsafe fn testResolveArrayRepeatBasic() throws (testing::TestError) {
1351
    let mut testArena32 = testArena();
1352
    let testStorage32: 'test32 = &mut testArena32 in {
1353
        let mut a = testResolver(testStorage32);
1354
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 3] = [42; 3];");
1355
        try expectNoErrors(&result);
1356
1357
        let stmt = try getBlockStmt(result.root, 0);
1358
        let case ast::NodeValue::Let(decl) = stmt.value
1359
            else throw testing::TestError::Failed;
1360
        let arrayTy = try typeOf(&a, decl.value);
1361
        let elemTy = try expectArrayType(arrayTy, 3);
1362
        try testing::expect(elemTy == super::Type::I32);
1363
    }
1364
}
1365
1366
@test unsafe fn testResolveArrayRepeatWithExpression() throws (testing::TestError) {
1367
    let mut testArena33 = testArena();
1368
    let testStorage33: 'test33 = &mut testArena33 in {
1369
        let mut a = testResolver(testStorage33);
1370
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 5] = [3 + 2; 5];");
1371
        try expectNoErrors(&result);
1372
1373
        let stmt = try getBlockStmt(result.root, 0);
1374
        let case ast::NodeValue::Let(decl) = stmt.value
1375
            else throw testing::TestError::Failed;
1376
        let arrayTy = try typeOf(&a, decl.value);
1377
        let elemTy = try expectArrayType(arrayTy, 5);
1378
        try testing::expect(elemTy == super::Type::I32);
1379
    }
1380
}
1381
1382
@test unsafe fn testResolveArrayRepeatLiteralArithmetic() throws (testing::TestError) {
1383
    let mut testArena34 = testArena();
1384
    let testStorage34: 'test34 = &mut testArena34 in {
1385
        let mut a = testResolver(testStorage34);
1386
        // `3 * 1` folds to a compile-time constant, so the repeat count is valid.
1387
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 3] = [42; 3 * 1];");
1388
        try expectNoErrors(&result);
1389
    }
1390
}
1391
1392
@test unsafe fn testResolveArrayRepeatNonConstCount() throws (testing::TestError) {
1393
    let mut testArena35 = testArena();
1394
    let testStorage35: 'test35 = &mut testArena35 in {
1395
        let mut a = testResolver(testStorage35);
1396
        // A function call is not a constant expression.
1397
        let result = try resolveProgramStr(&mut a, "fn f() -> u32 { return 3; } let xs: [i32; 3] = [42; f()];");
1398
        try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
1399
    }
1400
}
1401
1402
@test unsafe fn testResolveArrayRepeatCountMismatch() throws (testing::TestError) {
1403
    let mut testArena36 = testArena();
1404
    let testStorage36: 'test36 = &mut testArena36 in {
1405
        let mut a = testResolver(testStorage36);
1406
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 4] = [1; 3];");
1407
        let err = try expectError(&result);
1408
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1409
            else throw testing::TestError::Failed;
1410
    }
1411
}
1412
1413
@test unsafe fn testResolveArrayIndex() throws (testing::TestError) {
1414
    let mut testArena37 = testArena();
1415
    let testStorage37: 'test37 = &mut testArena37 in {
1416
        let mut a = testResolver(testStorage37);
1417
        let program = "let xs: [i32; 3] = [1, 2, 3]; xs[1];";
1418
        let result = try resolveProgramStr(&mut a, program);
1419
        try expectNoErrors(&result);
1420
1421
        let stmt = try getBlockStmt(result.root, 1);
1422
        try expectExprStmtType(&a, stmt, super::Type::I32);
1423
    }
1424
}
1425
1426
@test unsafe fn testResolveSliceIndex() throws (testing::TestError) {
1427
    let mut testArena38 = testArena();
1428
    let testStorage38: 'test38 = &mut testArena38 in {
1429
        let mut a = testResolver(testStorage38);
1430
        let program = "static xs: [i32; 4] = [1, 2, 3, 4]; let slice = &xs[1..]; slice[1];";
1431
        let result = try resolveProgramStr(&mut a, program);
1432
        try expectNoErrors(&result);
1433
1434
        let sliceStmt = try getBlockStmt(result.root, 1);
1435
        let case ast::NodeValue::Let(sliceDecl) = sliceStmt.value
1436
            else throw testing::TestError::Failed;
1437
        let sliceTy = try typeOf(&a, sliceDecl.value);
1438
        let elemTy = try expectSliceType(sliceTy, false);
1439
        try testing::expect(elemTy == super::Type::I32);
1440
1441
        let indexStmt = try getBlockStmt(result.root, 2);
1442
        try expectExprStmtType(&a, indexStmt, super::Type::I32);
1443
    }
1444
}
1445
1446
@test unsafe fn testResolveSliceFields() throws (testing::TestError) {
1447
    let mut testArena39 = testArena();
1448
    let testStorage39: 'test39 = &mut testArena39 in {
1449
        let mut a = testResolver(testStorage39);
1450
        let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[1..]; slice.len; unsafe { slice.ptr; }";
1451
        let result = try resolveProgramStr(&mut a, program);
1452
        try expectNoErrors(&result);
1453
1454
        let lenStmt = try getBlockStmt(result.root, 2);
1455
        let case ast::NodeValue::ExprStmt(lenExpr) = lenStmt.value
1456
            else throw testing::TestError::Failed;
1457
        let lenTy = try typeOf(&a, lenExpr);
1458
        try testing::expect(lenTy == super::Type::U32);
1459
1460
        let ptrStmt = try getBlockStmt(result.root, 3);
1461
        let case ast::NodeValue::Block(ptrBlock) = ptrStmt.value
1462
            else throw testing::TestError::Failed;
1463
        let case ast::NodeValue::ExprStmt(ptrExpr) = ptrBlock.statements[0].value
1464
            else throw testing::TestError::Failed;
1465
        let ptrTy = try typeOf(&a, ptrExpr);
1466
        let targetTy = try expectPointerType(ptrTy, false);
1467
        try testing::expect(targetTy == super::Type::I32);
1468
    }
1469
}
1470
1471
@test unsafe fn testResolveSliceLiteralImmutable() throws (testing::TestError) {
1472
    let mut testArena40 = testArena();
1473
    let testStorage40: 'test40 = &mut testArena40 in {
1474
        let mut a = testResolver(testStorage40);
1475
        let program = "let slice: *[i32] = &[1, 2, 3];";
1476
        let result = try resolveProgramStr(&mut a, program);
1477
        try expectNoErrors(&result);
1478
    }
1479
}
1480
1481
/// Empty array literal infers element type from slice annotation.
1482
@test unsafe fn testResolveSliceLiteralEmpty() throws (testing::TestError) {
1483
    let mut testArena41 = testArena();
1484
    let testStorage41: 'test41 = &mut testArena41 in {
1485
        let mut a = testResolver(testStorage41);
1486
        let program = "let slice: *[i32] = &[];";
1487
        let result = try resolveProgramStr(&mut a, program);
1488
        try expectNoErrors(&result);
1489
    }
1490
}
1491
1492
/// Nested array literal should infer inner element type from slice annotation.
1493
@test unsafe fn testResolveSliceLiteralNestedArray() throws (testing::TestError) {
1494
    let mut testArena42 = testArena();
1495
    let testStorage42: 'test42 = &mut testArena42 in {
1496
        let mut a = testResolver(testStorage42);
1497
        let program = "let slice: *[[i32; 2]] = &[[1, 2], [3, 4]];";
1498
        let result = try resolveProgramStr(&mut a, program);
1499
        try expectNoErrors(&result);
1500
    }
1501
}
1502
1503
@test unsafe fn testResolveSliceFromArray() throws (testing::TestError) {
1504
    {
1505
        let mut testArena43 = testArena();
1506
        let testStorage43: 'test43 = &mut testArena43 in {
1507
            let mut a = testResolver(testStorage43);
1508
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[..];";
1509
            let result = try resolveProgramStr(&mut a, program);
1510
            try expectNoErrors(&result);
1511
        }
1512
    } {
1513
        let mut testArena44 = testArena();
1514
        let testStorage44: 'test44 = &mut testArena44 in {
1515
            let mut a = testResolver(testStorage44);
1516
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[0..3];";
1517
            let result = try resolveProgramStr(&mut a, program);
1518
            try expectNoErrors(&result);
1519
        }
1520
    } {
1521
        let mut testArena45 = testArena();
1522
        let testStorage45: 'test45 = &mut testArena45 in {
1523
            let mut a = testResolver(testStorage45);
1524
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[..3];";
1525
            let result = try resolveProgramStr(&mut a, program);
1526
            try expectNoErrors(&result);
1527
        }
1528
    } {
1529
        let mut testArena46 = testArena();
1530
        let testStorage46: 'test46 = &mut testArena46 in {
1531
            let mut a = testResolver(testStorage46);
1532
            let program = "static xs: [u8; 2] = [1, 2]; let slice = &xs[1..1];";
1533
            let result = try resolveProgramStr(&mut a, program);
1534
            try expectNoErrors(&result);
1535
        }
1536
    }
1537
}
1538
1539
@test unsafe fn testResolveSliceLiteralMutableRequiresMut() throws (testing::TestError) {
1540
    let mut testArena47 = testArena();
1541
    let testStorage47: 'test47 = &mut testArena47 in {
1542
        let mut a = testResolver(testStorage47);
1543
        let program = "let slice: *mut [i32] = &[1, 2, 3];";
1544
        let result = try resolveProgramStr(&mut a, program);
1545
        let err = try expectError(&result);
1546
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1547
            else throw testing::TestError::Failed;
1548
    }
1549
}
1550
1551
@test unsafe fn testResolveSliceLiteralMutable() throws (testing::TestError) {
1552
    let mut testArena48 = testArena();
1553
    let testStorage48: 'test48 = &mut testArena48 in {
1554
        let mut a = testResolver(testStorage48);
1555
        let program = "let slice: *mut [i32] = &mut [1, 2, 3];";
1556
        let result = try resolveProgramStr(&mut a, program);
1557
        try expectNoErrors(&result);
1558
    }
1559
}
1560
1561
@test unsafe fn testResolvePointerMutableAssignmentRequiresMut() throws (testing::TestError) {
1562
    let mut testArena49 = testArena();
1563
    let testStorage49: 'test49 = &mut testArena49 in {
1564
        let mut a = testResolver(testStorage49);
1565
        let program = "let x: i32 = 0; let ptr: *mut i32 = &x;";
1566
        let result = try resolveProgramStr(&mut a, program);
1567
        let err = try expectError(&result);
1568
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1569
            else throw testing::TestError::Failed;
1570
    }
1571
}
1572
1573
@test unsafe fn testResolvePointerMutableToImmutableAssignment() throws (testing::TestError) {
1574
    let mut testArena50 = testArena();
1575
    let testStorage50: 'test50 = &mut testArena50 in {
1576
        let mut a = testResolver(testStorage50);
1577
        let program = "static x: i32 = 0; let mptr: *mut i32 = &mut x; let ptr: *i32 = mptr;";
1578
        let result = try resolveProgramStr(&mut a, program);
1579
        try expectNoErrors(&result);
1580
    }
1581
}
1582
1583
@test unsafe fn testResolveAddressOfRequiresMutableBinding() throws (testing::TestError) {
1584
    {
1585
        let mut testArena51 = testArena();
1586
        let testStorage51: 'test51 = &mut testArena51 in {
1587
            let mut a = testResolver(testStorage51);
1588
            let program = "let x: i32 = 0; let ptr = &mut x;";
1589
            let result = try resolveProgramStr(&mut a, program);
1590
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1591
        }
1592
    } {
1593
        let mut testArena52 = testArena();
1594
        let testStorage52: 'test52 = &mut testArena52 in {
1595
            let mut a = testResolver(testStorage52);
1596
            let program = "let mut x: i32 = 0; &mut x;";
1597
            let result = try resolveProgramStr(&mut a, program);
1598
            try expectNoErrors(&result);
1599
        }
1600
    }
1601
}
1602
1603
@test unsafe fn testResolveAddressOfSliceRequiresMutableBinding() throws (testing::TestError) {
1604
    {
1605
        let mut testArena53 = testArena();
1606
        let testStorage53: 'test53 = &mut testArena53 in {
1607
            let mut a = testResolver(testStorage53);
1608
            let program = "let xs: [i32; 3] = [1, 2, 3]; let slice = &mut xs[..];";
1609
            let result = try resolveProgramStr(&mut a, program);
1610
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1611
        }
1612
    } {
1613
        let mut testArena54 = testArena();
1614
        let testStorage54: 'test54 = &mut testArena54 in {
1615
            let mut a = testResolver(testStorage54);
1616
            let program = "let mut xs: [i32; 3] = [1, 2, 3]; &mut xs[..];";
1617
            let result = try resolveProgramStr(&mut a, program);
1618
            try expectNoErrors(&result);
1619
        }
1620
    }
1621
}
1622
1623
@test unsafe fn testResolveSliceCannotAssignToArray() throws (testing::TestError) {
1624
    let mut testArena55 = testArena();
1625
    let testStorage55: 'test55 = &mut testArena55 in {
1626
        let mut a = testResolver(testStorage55);
1627
        let program = "let xs: *[u8] = &[1, 2]; let ys: [u8; 2] = xs;";
1628
        let result = try resolveProgramStr(&mut a, program);
1629
        let err = try expectError(&result);
1630
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1631
            else throw testing::TestError::Failed;
1632
    }
1633
}
1634
1635
@test unsafe fn testResolveSliceSyntaxRequiresAddressOf() throws (testing::TestError) {
1636
    let mut testArena56 = testArena();
1637
    let testStorage56: 'test56 = &mut testArena56 in {
1638
        let mut a = testResolver(testStorage56);
1639
        let program = "let xs: [u8; 2] = [1, 2]; xs[..];";
1640
        let result = try resolveProgramStr(&mut a, program);
1641
        try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
1642
    }
1643
}
1644
1645
@test unsafe fn testResolveSliceResliceRequiresAddressOf() throws (testing::TestError) {
1646
    let mut testArena57 = testArena();
1647
    let testStorage57: 'test57 = &mut testArena57 in {
1648
        let mut a = testResolver(testStorage57);
1649
        let program = "fn f(s: *[u8]) -> *[u8] { return s[..]; }";
1650
        let result = try resolveProgramStr(&mut a, program);
1651
        try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
1652
    }
1653
}
1654
1655
@test unsafe fn testResolveSliceRangeOutOfBounds() throws (testing::TestError) {
1656
    {
1657
        let mut testArena58 = testArena();
1658
        let testStorage58: 'test58 = &mut testArena58 in {
1659
            let mut a = testResolver(testStorage58);
1660
            let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[..3];";
1661
            let result = try resolveProgramStr(&mut a, program);
1662
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1663
        }
1664
    } {
1665
        let mut testArena59 = testArena();
1666
        let testStorage59: 'test59 = &mut testArena59 in {
1667
            let mut a = testResolver(testStorage59);
1668
            let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[3..];";
1669
            let result = try resolveProgramStr(&mut a, program);
1670
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1671
        }
1672
    } {
1673
        let mut testArena60 = testArena();
1674
        let testStorage60: 'test60 = &mut testArena60 in {
1675
            let mut a = testResolver(testStorage60);
1676
            let program = "let xs: [u8; 4] = [1, 2, 3, 4]; let slice = &xs[3..2];";
1677
            let result = try resolveProgramStr(&mut a, program);
1678
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1679
        }
1680
    }
1681
}
1682
1683
@test unsafe fn testResolveArrayLenConstValue() throws (testing::TestError) {
1684
    let mut testArena61 = testArena();
1685
    let testStorage61: 'test61 = &mut testArena61 in {
1686
        let mut a = testResolver(testStorage61);
1687
        let program = "let xs: [i32; 3] = [1, 2, 3]; constant LEN: u32 = xs.len;";
1688
        let result = try resolveBlockStr(&mut a, program);
1689
        try expectNoErrors(&result);
1690
1691
        let constStmt = try getBlockStmt(result.root, 1);
1692
        let case ast::NodeValue::ConstDecl(decl) = constStmt.value
1693
            else throw testing::TestError::Failed;
1694
        let valueConst = super::constValueEntry(&a, decl.value)
1695
            else throw testing::TestError::Failed;
1696
        let case super::ConstValue::Int(lenVal) = valueConst
1697
            else throw testing::TestError::Failed;
1698
        try testing::expect(lenVal.magnitude == 3);
1699
        try testing::expect(not lenVal.negative);
1700
    }
1701
}
1702
1703
@test unsafe fn testResolveIndexNonIndexable() throws (testing::TestError) {
1704
    let mut testArena62 = testArena();
1705
    let testStorage62: 'test62 = &mut testArena62 in {
1706
        let mut a = testResolver(testStorage62);
1707
        let program = "let flag: bool = true; flag[0];";
1708
        let result = try resolveProgramStr(&mut a, program);
1709
        try expectErrorKind(&result, super::ErrorKind::ExpectedIndexable);
1710
    }
1711
}
1712
1713
@test unsafe fn testResolveSliceFieldUnknown() throws (testing::TestError) {
1714
    let mut testArena63 = testArena();
1715
    let testStorage63: 'test63 = &mut testArena63 in {
1716
        let mut a = testResolver(testStorage63);
1717
        let program = "let xs: [i32; 2] = [1, 2]; (&xs[0..]).unknown;";
1718
        let result = try resolveProgramStr(&mut a, program);
1719
        try expectErrorKind(&result, super::ErrorKind::SliceFieldUnknown("unknown"));
1720
    }
1721
}
1722
1723
@test unsafe fn testResolveArrayFieldUnknown() throws (testing::TestError) {
1724
    let mut testArena64 = testArena();
1725
    let testStorage64: 'test64 = &mut testArena64 in {
1726
        let mut a = testResolver(testStorage64);
1727
        let program = "let xs: [i32; 2] = [1, 2]; xs.field;";
1728
        let result = try resolveProgramStr(&mut a, program);
1729
        try expectErrorKind(&result, super::ErrorKind::ArrayFieldUnknown("field"));
1730
    }
1731
}
1732
1733
@test unsafe fn testResolveIfConditionRequiresBool() throws (testing::TestError) {
1734
    {
1735
        let mut testArena65 = testArena();
1736
        let testStorage65: 'test65 = &mut testArena65 in {
1737
            let mut a = testResolver(testStorage65);
1738
            let result = try resolveProgramStr(&mut a, "if 42 {}");
1739
            let err = try expectError(&result);
1740
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1741
        }
1742
    } {
1743
        let mut testArena66 = testArena();
1744
        let testStorage66: 'test66 = &mut testArena66 in {
1745
            let mut a = testResolver(testStorage66);
1746
            let result = try resolveProgramStr(&mut a, "if true {}");
1747
            try expectNoErrors(&result);
1748
        }
1749
    }
1750
}
1751
1752
@test unsafe fn testResolveIfLetScopeBinding() throws (testing::TestError) {
1753
    let mut testArena67 = testArena();
1754
    let testStorage67: 'test67 = &mut testArena67 in {
1755
        let mut a = testResolver(testStorage67);
1756
        let result = try resolveProgramStr(&mut a, "let opt: ?i32 = 42; if let x = opt { x }");
1757
        try expectNoErrors(&result);
1758
1759
        // Get the if-let statement and verify `x` has type `i32`.
1760
        let ifLetStmt = try parser::tests::getBlockLastStmt(result.root);
1761
        let case ast::NodeValue::IfLet(ifLet) = ifLetStmt.value
1762
            else throw testing::TestError::Failed;
1763
1764
        let thenStmt = try parser::tests::getBlockLastStmt(ifLet.thenBranch);
1765
        let case ast::NodeValue::ExprStmt(xExpr) = thenStmt.value
1766
            else throw testing::TestError::Failed;
1767
1768
        try expectType(&a, xExpr, super::Type::I32);
1769
1770
        let scope = super::scopeFor(&a, ifLetStmt)
1771
            else throw testing::TestError::Failed;
1772
        let xSym = super::findSymbolInScope(scope, "x")
1773
            else throw testing::TestError::Failed;
1774
        let case super::SymbolData::Value { type: valType, .. } = xSym.data
1775
            else throw testing::TestError::Failed;
1776
1777
        try testing::expect(valType == super::Type::I32);
1778
    }
1779
}
1780
1781
@test unsafe fn testResolveIfLetScopeBindingError() throws (testing::TestError) {
1782
    let mut testArena68 = testArena();
1783
    let testStorage68: 'test68 = &mut testArena68 in {
1784
        let mut a = testResolver(testStorage68);
1785
        let result = try resolveProgramStr(&mut a, "let opt: ?i32 = 42; if let x = opt { x } else { x }");
1786
        let err = try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1787
1788
        // Verify the error comes from the else branch (offset 48).
1789
        let errNode = err.node
1790
            else throw testing::TestError::Failed;
1791
        try testing::expect(errNode.span.offset == 48);
1792
    }
1793
}
1794
1795
/// Tests that `if let` with a condition expression binds the variable in scope.
1796
@test unsafe fn testResolveIfLetConditionBindsVariable() throws (testing::TestError) {
1797
    let mut testArena69 = testArena();
1798
    let testStorage69: 'test69 = &mut testArena69 in {
1799
        let mut a = testResolver(testStorage69);
1800
        let program = "let opt: ?i32 = 42; if let x = opt; x == 1 { x }";
1801
        let result = try resolveProgramStr(&mut a, program);
1802
        try expectNoErrors(&result);
1803
    }
1804
}
1805
1806
@test unsafe fn testResolveWhileConditionRequiresBool() throws (testing::TestError) {
1807
    {
1808
        let mut testArena70 = testArena();
1809
        let testStorage70: 'test70 = &mut testArena70 in {
1810
            let mut a = testResolver(testStorage70);
1811
            let result = try resolveProgramStr(&mut a, "while 1 {}");
1812
            let err = try expectError(&result);
1813
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1814
        }
1815
    } {
1816
        let mut testArena71 = testArena();
1817
        let testStorage71: 'test71 = &mut testArena71 in {
1818
            let mut a = testResolver(testStorage71);
1819
            let result = try resolveProgramStr(&mut a, "while true {}");
1820
            try expectNoErrors(&result);
1821
        }
1822
    }
1823
}
1824
1825
@test unsafe fn testResolveWhileLetBindingScope() throws (testing::TestError) {
1826
    {
1827
        let mut testArena72 = testArena();
1828
        let testStorage72: 'test72 = &mut testArena72 in {
1829
            let mut a = testResolver(testStorage72);
1830
            let program = "let mut opt: ?i32 = 42; while let x = opt; x > 0 { x; opt; }";
1831
            let result = try resolveProgramStr(&mut a, program);
1832
            try expectNoErrors(&result);
1833
1834
            let whileStmt = try parser::tests::getBlockLastStmt(result.root);
1835
            let case ast::NodeValue::WhileLet(loopNode) = whileStmt.value
1836
                else throw testing::TestError::Failed;
1837
1838
            let bodyStmt = try parser::tests::getBlockFirstStmt(loopNode.body);
1839
            try expectExprStmtType(&a, bodyStmt, super::Type::I32);
1840
1841
            let scope = super::scopeFor(&a, whileStmt)
1842
                else throw testing::TestError::Failed;
1843
            let xSym = super::findSymbolInScope(scope, "x")
1844
                else throw testing::TestError::Failed;
1845
            let case super::SymbolData::Value { type: valType, .. } = xSym.data
1846
                else throw testing::TestError::Failed;
1847
            try testing::expect(valType == super::Type::I32);
1848
        }
1849
    } {
1850
        let mut testArena73 = testArena();
1851
        let testStorage73: 'test73 = &mut testArena73 in {
1852
            let mut a = testResolver(testStorage73);
1853
            let program = "let opt: ?i32 = nil; while let x = opt; true { break } else { x }";
1854
            let result = try resolveProgramStr(&mut a, program);
1855
            try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1856
        }
1857
    }
1858
}
1859
1860
@test unsafe fn testResolveForArrayBindsElementType() throws (testing::TestError) {
1861
    let mut testArena74 = testArena();
1862
    let testStorage74: 'test74 = &mut testArena74 in {
1863
        let mut a = testResolver(testStorage74);
1864
        let program = "let xs: [i32; 2] = [1, 2]; for x in xs { x; }";
1865
        let result = try resolveProgramStr(&mut a, program);
1866
        try expectNoErrors(&result);
1867
1868
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1869
        let case ast::NodeValue::For(loopNode) = forStmt.value
1870
            else throw testing::TestError::Failed;
1871
1872
        let scope = super::scopeFor(&a, forStmt)
1873
            else throw testing::TestError::Failed;
1874
        let sym = super::findSymbolInScope(scope, "x")
1875
            else throw testing::TestError::Failed;
1876
        let case super::SymbolData::Value { type: valType, .. } = sym.data
1877
            else throw testing::TestError::Failed;
1878
        try testing::expect(valType == super::Type::I32);
1879
1880
        let bindingTy = super::typeFor(&a, loopNode.binding)
1881
            else throw testing::TestError::Failed;
1882
        try testing::expect(bindingTy == super::Type::I32);
1883
    }
1884
}
1885
1886
@test unsafe fn testResolveForIndexedLoopBindsIndex() throws (testing::TestError) {
1887
    let mut testArena75 = testArena();
1888
    let testStorage75: 'test75 = &mut testArena75 in {
1889
        let mut a = testResolver(testStorage75);
1890
        let program = "let xs: [bool; 3] = [true; 3]; for value, idx in xs { value; idx; }";
1891
        let result = try resolveProgramStr(&mut a, program);
1892
        try expectNoErrors(&result);
1893
1894
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1895
        let case ast::NodeValue::For(loopNode) = forStmt.value
1896
            else throw testing::TestError::Failed;
1897
1898
        let scope = super::scopeFor(&a, forStmt)
1899
            else throw testing::TestError::Failed;
1900
        let valueSym = super::findSymbolInScope(scope, "value")
1901
            else throw testing::TestError::Failed;
1902
        let case super::SymbolData::Value { type: valueValType, .. } = valueSym.data
1903
            else throw testing::TestError::Failed;
1904
        try testing::expect(valueValType == super::Type::Bool);
1905
        let indexSym = super::findSymbolInScope(scope, "idx")
1906
            else throw testing::TestError::Failed;
1907
        let case super::SymbolData::Value { type: indexValType, .. } = indexSym.data
1908
            else throw testing::TestError::Failed;
1909
        try testing::expect(indexValType == super::Type::U32);
1910
1911
        let indexNode = loopNode.index
1912
            else throw testing::TestError::Failed;
1913
        let indexTy = super::typeFor(&a, indexNode)
1914
            else throw testing::TestError::Failed;
1915
        try testing::expect(indexTy == super::Type::U32);
1916
    }
1917
}
1918
1919
@test unsafe fn testResolveForSliceIterable() throws (testing::TestError) {
1920
    let mut testArena76 = testArena();
1921
    let testStorage76: 'test76 = &mut testArena76 in {
1922
        let mut a = testResolver(testStorage76);
1923
        let program = "let xs: [i32; 3] = [1, 2, 3]; for x in &xs[..] { x; }";
1924
        let result = try resolveProgramStr(&mut a, program);
1925
        try expectNoErrors(&result);
1926
1927
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1928
        let case ast::NodeValue::For(loopNode) = forStmt.value
1929
            else throw testing::TestError::Failed;
1930
1931
        let bindingTy = super::typeFor(&a, loopNode.binding)
1932
            else throw testing::TestError::Failed;
1933
        try testing::expect(bindingTy == super::Type::I32);
1934
    }
1935
}
1936
1937
@test unsafe fn testResolveForRequiresIterable() throws (testing::TestError) {
1938
    let mut testArena77 = testArena();
1939
    let testStorage77: 'test77 = &mut testArena77 in {
1940
        let mut a = testResolver(testStorage77);
1941
        let result = try resolveProgramStr(&mut a, "for x in true { x; }");
1942
        try expectErrorKind(&result, super::ErrorKind::ExpectedIterable);
1943
    }
1944
}
1945
1946
@test unsafe fn testResolveForRangeBoundsMustNumeric() throws (testing::TestError) {
1947
    let mut testArena78 = testArena();
1948
    let testStorage78: 'test78 = &mut testArena78 in {
1949
        let mut a = testResolver(testStorage78);
1950
        let result = try resolveBlockStr(&mut a, "for i in 0..true { i; }");
1951
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
1952
    }
1953
}
1954
1955
@test unsafe fn testResolveMatchPatternTypeMismatch() throws (testing::TestError) {
1956
    let mut testArena79 = testArena();
1957
    let testStorage79: 'test79 = &mut testArena79 in {
1958
        let mut a = testResolver(testStorage79);
1959
        let program = "let val: i32 = 0; match val { case true => {} }";
1960
        let result = try resolveProgramStr(&mut a, program);
1961
        let err = try expectError(&result);
1962
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
1963
    }
1964
}
1965
1966
@test unsafe fn testResolveMatchUnionVariantTypeMismatch() throws (testing::TestError) {
1967
    let mut testArena80 = testArena();
1968
    let testStorage80: 'test80 = &mut testArena80 in {
1969
        let mut a = testResolver(testStorage80);
1970
        let program = "union First { A }  union Second { B } fn run(val: First) { match val { case Second::B => {} } }";
1971
        let result = try resolveProgramStr(&mut a, program);
1972
        let err = try expectError(&result);
1973
1974
        let firstTy = try getTypeInScopeOf(&a, result.root, "First");
1975
        let secondTy = try getTypeInScopeOf(&a, result.root, "Second");
1976
        try expectTypeMismatch(err, super::Type::Nominal(firstTy), super::Type::Nominal(secondTy));
1977
    }
1978
}
1979
1980
@test unsafe fn testResolveMatchUnionPayloadMissing() throws (testing::TestError) {
1981
    let mut testArena81 = testArena();
1982
    let testStorage81: 'test81 = &mut testArena81 in {
1983
        let mut a = testResolver(testStorage81);
1984
        let program = "union Opt { Some(i32) } fn run(val: Opt) { match val { case Opt::Some => {} } }";
1985
        let result = try resolveProgramStr(&mut a, program);
1986
        try expectErrorKind(&result, super::ErrorKind::UnionVariantPayloadMissing("Some"));
1987
    }
1988
}
1989
1990
@test unsafe fn testResolveMatchUnionVoidVariantExplicitDiscriminant() throws (testing::TestError) {
1991
    let mut testArena82 = testArena();
1992
    let testStorage82: 'test82 = &mut testArena82 in {
1993
        let mut a = testResolver(testStorage82);
1994
        let program = "union Opt { Some = 5 } fn run(val: Opt) { match val { case Opt::Some => {} } }";
1995
        let result = try resolveProgramStr(&mut a, program);
1996
        try expectNoErrors(&result);
1997
    }
1998
}
1999
2000
@test unsafe fn testResolveMatchUnionPayloadUnexpected() throws (testing::TestError) {
2001
    let mut testArena83 = testArena();
2002
    let testStorage83: 'test83 = &mut testArena83 in {
2003
        let mut a = testResolver(testStorage83);
2004
        let program = "union Opt { None } fn run(val: Opt) { match val { case Opt::None(x) => {} } }";
2005
        let result = try resolveProgramStr(&mut a, program);
2006
        try expectErrorKind(&result, super::ErrorKind::UnionVariantPayloadUnexpected("None"));
2007
    }
2008
}
2009
2010
@test unsafe fn testResolveMatchUnionUnknownVariant() throws (testing::TestError) {
2011
    let mut testArena84 = testArena();
2012
    let testStorage84: 'test84 = &mut testArena84 in {
2013
        let mut a = testResolver(testStorage84);
2014
        let program = "union Opt { Some, None } fn run(value: Opt) { match value { case Opt::Unknown => {} } }";
2015
        let result = try resolveProgramStr(&mut a, program);
2016
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
2017
    }
2018
}
2019
2020
@test unsafe fn testResolveMatchUnionNonExhaustive() throws (testing::TestError) {
2021
    {
2022
        let mut testArena85 = testArena();
2023
        let testStorage85: 'test85 = &mut testArena85 in {
2024
            let mut a = testResolver(testStorage85);
2025
            let program = "union Opt { Some, None } fn run(value: Opt) { match value { case Opt::Some => {} } }";
2026
            let result = try resolveProgramStr(&mut a, program);
2027
            try expectErrorKind(&result, super::ErrorKind::UnionMatchNonExhaustive("None"));
2028
        }
2029
    } {
2030
        let mut testArena86 = testArena();
2031
        let testStorage86: 'test86 = &mut testArena86 in {
2032
            let mut a = testResolver(testStorage86);
2033
            let program = "union Opt { Some, None } fn run(value: Opt) { match value { else => {} } }";
2034
            let result = try resolveProgramStr(&mut a, program);
2035
            try expectNoErrors(&result);
2036
        }
2037
    }
2038
}
2039
2040
@test unsafe fn testResolveMatchUnionNonExhaustiveExplicitDiscriminants() throws (testing::TestError) {
2041
    let mut testArena87 = testArena();
2042
    let testStorage87: 'test87 = &mut testArena87 in {
2043
        let mut a = testResolver(testStorage87);
2044
        let program = "union U { A = 3, B = 9 } fn run(value: U) { match value { case U::A => {}, case U::B => {} } }";
2045
        let result = try resolveProgramStr(&mut a, program);
2046
        try expectNoErrors(&result);
2047
    }
2048
}
2049
2050
@test unsafe fn testResolveMatchUnionBindingScope() throws (testing::TestError) {
2051
    let mut testArena88 = testArena();
2052
    let testStorage88: 'test88 = &mut testArena88 in {
2053
        let mut a = testResolver(testStorage88);
2054
        let program = "union Opt { Some(i32), None } fn f(value: Opt) { match value { case Opt::Some(x) if x > 0 => { x; } else => {} } }";
2055
        let result = try resolveProgramStr(&mut a, program);
2056
        try expectNoErrors(&result);
2057
2058
        let fnBlock = try getFnBody(&a, result.root, "f");
2059
        try testing::expect(fnBlock.statements.len > 0);
2060
2061
        let matchNode = fnBlock.statements[0];
2062
        let case ast::NodeValue::Match(sw) = matchNode.value
2063
            else throw testing::TestError::Failed;
2064
        let caseNode = sw.prongs[0];
2065
2066
        let scope = super::scopeFor(&a, caseNode)
2067
            else throw testing::TestError::Failed;
2068
        let payloadSym = super::findSymbolInScope(scope, "x")
2069
            else throw testing::TestError::Failed;
2070
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
2071
            else throw testing::TestError::Failed;
2072
        try testing::expect(payloadValType == super::Type::I32);
2073
    }
2074
}
2075
2076
@test unsafe fn testResolveMatchUnionPatternNonUnionType() throws (testing::TestError) {
2077
    let mut testArena89 = testArena();
2078
    let testStorage89: 'test89 = &mut testArena89 in {
2079
        let mut a = testResolver(testStorage89);
2080
        let program = "union Opt { Some, None } fn f(value: Opt) { match value { case true => {} } }";
2081
        let result = try resolveProgramStr(&mut a, program);
2082
        let err = try expectError(&result);
2083
        let optionTy = try getTypeInScopeOf(&a, result.root, "Opt");
2084
        try expectTypeMismatch(err, super::Type::Nominal(optionTy), super::Type::Bool);
2085
    }
2086
}
2087
2088
@test unsafe fn testResolveMatchGuardForms() throws (testing::TestError) {
2089
    for program in [
2090
        "fn first(value: i32) { match value { case _ if true => {}, else => {} } }",
2091
        "fn f(x: u32) { match x { case _ if x > 0 => {}, case 1 => {}, else => {} } }",
2092
        "union U: Copy { A, B } fn f(x: U) { match x { value if false => {}, case U::A => {}, case U::B => {} } }",
2093
    ] {
2094
        let mut testArena90 = testArena();
2095
        let testStorage90: 'test90 = &mut testArena90 in {
2096
            let mut a = testResolver(testStorage90);
2097
            let result = try resolveProgramStr(&mut a, program);
2098
            try expectNoErrors(&result);
2099
        }
2100
    }
2101
}
2102
2103
/// Expected lowering metadata for a resolved match.
2104
record MatchMetadataCase: Copy {
2105
    /// Complete source program with a function named f.
2106
    source: *[u8],
2107
    /// Bit set when lowering can omit a prong's pattern test.
2108
    catchAllMask: u32,
2109
    /// Whether scalar cases can use switch lowering.
2110
    isConst: bool,
2111
}
2112
2113
/// Guards and subject types determine unconditional-prong metadata.
2114
@test unsafe fn testMatchCatchAllMetadata() throws (testing::TestError) {
2115
    let cases = [
2116
        MatchMetadataCase { source: "fn f(x: u32) { match x { case 1 => {}, else => {} } }", catchAllMask: 2, isConst: true },
2117
        MatchMetadataCase { source: "fn f(x: u32) { match x { n if n > 0 => {}, case _ => {} } }", catchAllMask: 2, isConst: false },
2118
        MatchMetadataCase { source: "fn f(x: u32) { match x { case _ if x > 0 => {}, n => {} } }", catchAllMask: 2, isConst: false },
2119
        MatchMetadataCase { source: "fn f(x: u32) { match x { n => {} } }", catchAllMask: 1, isConst: false },
2120
        MatchMetadataCase { source: "fn f(x: [[u32; 2]; 2]) { match x { case [[1, a], [b, c]] => {}, case [[a, b], [c, d]] => {} } }", catchAllMask: 2, isConst: false },
2121
        MatchMetadataCase { source: "union U: Copy { A, B } fn f(x: U) { match x { case U::A => {}, else => {} } }", catchAllMask: 2, isConst: false },
2122
        MatchMetadataCase { source: "fn f(x: ?u32) { match x { n => {}, case nil => {} } }", catchAllMask: 2, isConst: false },
2123
        MatchMetadataCase { source: "fn f(x: ?u32) { match x { case _ if false => {}, else => {} } }", catchAllMask: 2, isConst: false },
2124
        MatchMetadataCase { source: "fn f(x: ?u32) { match x { case _ => {} } }", catchAllMask: 1, isConst: false },
2125
        MatchMetadataCase { source: "fn f(x: bool) { match x { case true => {}, case false => {} } }", catchAllMask: 2, isConst: true },
2126
    ];
2127
    for item in cases {
2128
        let mut arena = testArena();
2129
        let storage: 'test = &mut arena in {
2130
            let mut res = testResolver(storage);
2131
            let result = try resolveProgramStr(&mut res, item.source);
2132
            try expectNoErrors(&result);
2133
            let body = try getFnBody(&res, result.root, "f");
2134
            let node = body.statements[0];
2135
            let case ast::NodeValue::Match(sw) = node.value else throw testing::TestError::Failed;
2136
            for prong, i in sw.prongs {
2137
                assert super::isProngCatchAll(&res, prong) == ((item.catchAllMask & (1 << i)) <> 0);
2138
            }
2139
            assert super::isMatchConst(&res, node) == item.isConst;
2140
        }
2141
    }
2142
}
2143
2144
/// Duplicate unconditional arms are rejected for each match subject category.
2145
@test unsafe fn testMatchDuplicateCatchAll() throws (testing::TestError) {
2146
    for source in [
2147
        "fn f(x: u32) { match x { case _ => {}, else => {} } }",
2148
        "fn f(x: u32) { match x { n => {}, case _ => {} } }",
2149
        "fn f(x: [[u32; 2]; 2]) { match x { case [[a, b], [c, d]] => {}, else => {} } }",
2150
        "union U: Copy { A, B } fn f(x: U) { match x { n => {}, else => {} } }",
2151
        "fn f(x: ?u32) { match x { case _ => {}, else => {} } }",
2152
    ] {
2153
        let mut arena = testArena();
2154
        let storage: 'test = &mut arena in {
2155
            let mut res = testResolver(storage);
2156
            let result = try resolveProgramStr(&mut res, source);
2157
            try expectErrorKind(&result, super::ErrorKind::DuplicateCatchAll);
2158
        }
2159
    }
2160
2161
    // Any prong after an unguarded catch-all is unreachable.
2162
    for source in [
2163
        "fn f(x: u32) { match x { else => {}, case 1 => {} } }",
2164
        "fn f(x: u32) { match x { case _ => {}, case 1 if true => {} } }",
2165
        "fn f(x: [u32; 2]) { match x { case [a, b] => {}, case [1, 2] => {} } }",
2166
        "union U: Copy { A, B } fn f(x: U) { match x { value => {}, case U::A => {} } }",
2167
        "fn f(x: ?u32) { match x { else => {}, case nil => {} } }",
2168
        "fn f(x: ?u32) { match x { case _ => {}, value => {} } }",
2169
    ] {
2170
        let mut arena = testArena();
2171
        let storage: 'test = &mut arena in {
2172
            let mut res = testResolver(storage);
2173
            let result = try resolveProgramStr(&mut res, source);
2174
            try expectErrorKind(&result, super::ErrorKind::CatchAllMustBeLast);
2175
        }
2176
    }
2177
}
2178
2179
/// Test that a binding prong binds the subject to the identifier.
2180
@test unsafe fn testResolveMatchBindingProng() throws (testing::TestError) {
2181
    let mut testArena91 = testArena();
2182
    let testStorage91: 'test91 = &mut testArena91 in {
2183
        let mut a = testResolver(testStorage91);
2184
        let program = "fn f(value: i32) -> i32 { match value { x => return x } }";
2185
        let result = try resolveProgramStr(&mut a, program);
2186
        try expectNoErrors(&result);
2187
    }
2188
}
2189
2190
/// Test that a binding prong with guard can use the bound variable.
2191
@test unsafe fn testResolveMatchBindingProngGuard() throws (testing::TestError) {
2192
    let mut testArena92 = testArena();
2193
    let testStorage92: 'test92 = &mut testArena92 in {
2194
        let mut a = testResolver(testStorage92);
2195
        let program = "fn f(value: i32) -> i32 { match value { x if x > 0 => return x, _ => return 0 } }";
2196
        let result = try resolveProgramStr(&mut a, program);
2197
        try expectNoErrors(&result);
2198
    }
2199
}
2200
2201
/// Test that a binding prong covers all union variants for exhaustiveness.
2202
@test unsafe fn testResolveMatchBindingProngExhaustive() throws (testing::TestError) {
2203
    let mut testArena93 = testArena();
2204
    let testStorage93: 'test93 = &mut testArena93 in {
2205
        let mut a = testResolver(testStorage93);
2206
        let program = "union U { A, B, C } fn f(u: U) -> i32 { match u { x => return 0 } }";
2207
        let result = try resolveProgramStr(&mut a, program);
2208
        try expectNoErrors(&result);
2209
    }
2210
}
2211
2212
/// Test that `case x =>` fails if `x` is not in scope, since bare identifiers
2213
/// in case patterns are values to compare against, not bindings.
2214
@test unsafe fn testResolveMatchCaseUndefinedIdent() throws (testing::TestError) {
2215
    let mut testArena94 = testArena();
2216
    let testStorage94: 'test94 = &mut testArena94 in {
2217
        let mut a = testResolver(testStorage94);
2218
        let program = "fn f(n: i32) -> i32 { match n { case x => return 0 } }";
2219
        let result = try resolveProgramStr(&mut a, program);
2220
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
2221
    }
2222
}
2223
2224
/// Test matching on optionals: exhaustiveness and type unwrapping.
2225
@test unsafe fn testResolveMatchOptional() throws (testing::TestError) {
2226
    {
2227
        // Exhaustive: binding + nil case.
2228
        let mut testArena95 = testArena();
2229
        let testStorage95: 'test95 = &mut testArena95 in {
2230
            let mut a = testResolver(testStorage95);
2231
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {} } }";
2232
            let result = try resolveProgramStr(&mut a, program);
2233
            try expectNoErrors(&result);
2234
        }
2235
    } {
2236
        // Missing nil case.
2237
        let mut testArena96 = testArena();
2238
        let testStorage96: 'test96 = &mut testArena96 in {
2239
            let mut a = testResolver(testStorage96);
2240
            let program = "fn f(opt: ?i32) { match opt { v => {} } }";
2241
            let result = try resolveProgramStr(&mut a, program);
2242
            try expectErrorKind(&result, super::ErrorKind::OptionalMatchMissingNil);
2243
        }
2244
    } {
2245
        // Missing value case.
2246
        let mut testArena97 = testArena();
2247
        let testStorage97: 'test97 = &mut testArena97 in {
2248
            let mut a = testResolver(testStorage97);
2249
            let program = "fn f(opt: ?i32) { match opt { case nil => {} } }";
2250
            let result = try resolveProgramStr(&mut a, program);
2251
            try expectErrorKind(&result, super::ErrorKind::OptionalMatchMissingValue);
2252
        }
2253
    } {
2254
        // Else covers both cases.
2255
        let mut testArena98 = testArena();
2256
        let testStorage98: 'test98 = &mut testArena98 in {
2257
            let mut a = testResolver(testStorage98);
2258
            let program = "fn f(opt: ?i32) { match opt { else => {} } }";
2259
            let result = try resolveProgramStr(&mut a, program);
2260
            try expectNoErrors(&result);
2261
        }
2262
    } {
2263
        // Binding unwraps the inner type.
2264
        let mut testArena99 = testArena();
2265
        let testStorage99: 'test99 = &mut testArena99 in {
2266
            let mut a = testResolver(testStorage99);
2267
            let program = "fn f(opt: ?i32) -> i32 { match opt { v => return v + 1, case nil => return 0 } }";
2268
            let result = try resolveProgramStr(&mut a, program);
2269
            try expectNoErrors(&result);
2270
        }
2271
    }
2272
}
2273
2274
/// Test that match on non-union types requires exhaustiveness.
2275
@test unsafe fn testResolveMatchGenericExhaustive() throws (testing::TestError) {
2276
    {
2277
        // Match on i32 without catch-all should error.
2278
        let mut testArena100 = testArena();
2279
        let testStorage100: 'test100 = &mut testArena100 in {
2280
            let mut a = testResolver(testStorage100);
2281
            let program = "fn f(x: i32) { match x { case 1 => {} } }";
2282
            let result = try resolveProgramStr(&mut a, program);
2283
            try expectErrorKind(&result, super::ErrorKind::MatchNonExhaustive);
2284
        }
2285
    } {
2286
        // Match on i32 with else is fine.
2287
        let mut testArena101 = testArena();
2288
        let testStorage101: 'test101 = &mut testArena101 in {
2289
            let mut a = testResolver(testStorage101);
2290
            let program = "fn f(x: i32) { match x { case 1 => {}, else => {} } }";
2291
            let result = try resolveProgramStr(&mut a, program);
2292
            try expectNoErrors(&result);
2293
        }
2294
    } {
2295
        // Match on i32 with binding catch-all is fine.
2296
        let mut testArena102 = testArena();
2297
        let testStorage102: 'test102 = &mut testArena102 in {
2298
            let mut a = testResolver(testStorage102);
2299
            let program = "fn f(x: i32) { match x { y => {} } }";
2300
            let result = try resolveProgramStr(&mut a, program);
2301
            try expectNoErrors(&result);
2302
        }
2303
    } {
2304
        // Match on i32 with wildcard catch-all is fine.
2305
        let mut testArena103 = testArena();
2306
        let testStorage103: 'test103 = &mut testArena103 in {
2307
            let mut a = testResolver(testStorage103);
2308
            let program = "fn f(x: i32) { match x { case _ => {} } }";
2309
            let result = try resolveProgramStr(&mut a, program);
2310
            try expectNoErrors(&result);
2311
        }
2312
    }
2313
}
2314
2315
/// Test that match on bool requires both true and false cases.
2316
@test unsafe fn testResolveMatchBoolExhaustive() throws (testing::TestError) {
2317
    {
2318
        // Match on bool with both cases is fine.
2319
        let mut testArena104 = testArena();
2320
        let testStorage104: 'test104 = &mut testArena104 in {
2321
            let mut a = testResolver(testStorage104);
2322
            let program = "fn f(x: bool) { match x { case true => {}, case false => {} } }";
2323
            let result = try resolveProgramStr(&mut a, program);
2324
            try expectNoErrors(&result);
2325
        }
2326
    } {
2327
        // Match on bool missing true should error.
2328
        let mut testArena105 = testArena();
2329
        let testStorage105: 'test105 = &mut testArena105 in {
2330
            let mut a = testResolver(testStorage105);
2331
            let program = "fn f(x: bool) { match x { case false => {} } }";
2332
            let result = try resolveProgramStr(&mut a, program);
2333
            try expectErrorKind(&result, super::ErrorKind::BoolMatchMissing(true));
2334
        }
2335
    } {
2336
        // Match on bool missing false should error.
2337
        let mut testArena106 = testArena();
2338
        let testStorage106: 'test106 = &mut testArena106 in {
2339
            let mut a = testResolver(testStorage106);
2340
            let program = "fn f(x: bool) { match x { case true => {} } }";
2341
            let result = try resolveProgramStr(&mut a, program);
2342
            try expectErrorKind(&result, super::ErrorKind::BoolMatchMissing(false));
2343
        }
2344
    } {
2345
        // Match on bool with else is fine.
2346
        let mut testArena107 = testArena();
2347
        let testStorage107: 'test107 = &mut testArena107 in {
2348
            let mut a = testResolver(testStorage107);
2349
            let program = "fn f(x: bool) { match x { else => {} } }";
2350
            let result = try resolveProgramStr(&mut a, program);
2351
            try expectNoErrors(&result);
2352
        }
2353
    } {
2354
        // Match on bool with binding catch-all is fine.
2355
        let mut testArena108 = testArena();
2356
        let testStorage108: 'test108 = &mut testArena108 in {
2357
            let mut a = testResolver(testStorage108);
2358
            let program = "fn f(x: bool) { match x { b => {} } }";
2359
            let result = try resolveProgramStr(&mut a, program);
2360
            try expectNoErrors(&result);
2361
        }
2362
    }
2363
}
2364
2365
@test unsafe fn testResolveFnTypeVoidNoParams() throws (testing::TestError) {
2366
    let mut testArena113 = testArena();
2367
    let testStorage113: 'test113 = &mut testArena113 in {
2368
        let mut a = testResolver(testStorage113);
2369
        let result = try resolveProgramStr(&mut a, "fn f() {} f();");
2370
        try expectNoErrors(&result);
2371
2372
        let blockNode = result.root;
2373
        let case ast::NodeValue::Block(block) = blockNode.value
2374
            else throw testing::TestError::Failed;
2375
        let fnNode = try getBlockStmt(blockNode, 0);
2376
        let callStmt = try getBlockStmt(blockNode, 1);
2377
2378
        { // Verify the function symbol captures an empty parameter list and void return.
2379
            let sym = super::symbolFor(&a, fnNode)
2380
                else throw testing::TestError::Failed;
2381
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2382
                else throw testing::TestError::Failed;
2383
            try testing::expect(fnTy.paramTypes.len == 0);
2384
            try testing::expect(*fnTy.returnType == super::Type::Void);
2385
        }
2386
        { // Checking that the type of the call matches the function return type.
2387
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
2388
2389
            let fnSym = super::symbolFor(&a, fnNode)
2390
                else throw testing::TestError::Failed;
2391
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2392
                else throw testing::TestError::Failed;
2393
            try expectType(&a, callExpr, *fnTy.returnType);
2394
        }
2395
    }
2396
}
2397
2398
@test unsafe fn testResolveFnTypeReturnsValue() throws (testing::TestError) {
2399
    let mut testArena114 = testArena();
2400
    let testStorage114: 'test114 = &mut testArena114 in {
2401
        let mut a = testResolver(testStorage114);
2402
        let program = "fn f() -> i32 { return 1; } f();";
2403
        let result = try resolveProgramStr(&mut a, program);
2404
        try expectNoErrors(&result);
2405
2406
        let blockNode = result.root;
2407
        let case ast::NodeValue::Block(block) = blockNode.value
2408
            else throw testing::TestError::Failed;
2409
        let fnNode = try getBlockStmt(blockNode, 0);
2410
        let callStmt = try getBlockStmt(blockNode, 1);
2411
2412
        { // Function returns i32 with no parameters.
2413
            let sym = super::symbolFor(&a, fnNode)
2414
                else throw testing::TestError::Failed;
2415
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2416
                else throw testing::TestError::Failed;
2417
            try testing::expect(fnTy.paramTypes.len == 0);
2418
            try testing::expect(*fnTy.returnType == super::Type::I32);
2419
        }
2420
        { // Call expression should inherit the function's return type.
2421
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::I32);
2422
2423
            let fnSym = super::symbolFor(&a, fnNode)
2424
                else throw testing::TestError::Failed;
2425
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2426
                else throw testing::TestError::Failed;
2427
            try expectType(&a, callExpr, *fnTy.returnType);
2428
        }
2429
    }
2430
}
2431
2432
@test unsafe fn testResolveFnTypeSingleParam() throws (testing::TestError) {
2433
    let mut testArena115 = testArena();
2434
    let testStorage115: 'test115 = &mut testArena115 in {
2435
        let mut a = testResolver(testStorage115);
2436
        let program = "fn f(x: i8) {} let x: i8 = 1; f(x);";
2437
        let result = try resolveProgramStr(&mut a, program);
2438
        try expectNoErrors(&result);
2439
2440
        let blockNode = result.root;
2441
        let case ast::NodeValue::Block(block) = blockNode.value
2442
            else throw testing::TestError::Failed;
2443
        let fnNode = try getBlockStmt(blockNode, 0);
2444
        let callStmt = try getBlockStmt(blockNode, 2);
2445
2446
        { // Single parameter propagates nominal type onto the symbol and parameter node.
2447
            let sym = super::symbolFor(&a, fnNode)
2448
                else throw testing::TestError::Failed;
2449
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2450
                else throw testing::TestError::Failed;
2451
            try testing::expect(fnTy.paramTypes.len == 1);
2452
            try testing::expect(*fnTy.paramTypes[0] == super::Type::I8);
2453
            try testing::expect(*fnTy.returnType == super::Type::Void);
2454
2455
            let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
2456
                else throw testing::TestError::Failed;
2457
            try testing::expect(fnDecl.sig.params.len == 1);
2458
2459
            let paramNode = fnDecl.sig.params[0];
2460
            try expectType(&a, paramNode, super::Type::I8);
2461
        }
2462
        { // Call should resolve to void, matching the function's return type.
2463
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
2464
            let fnSym = super::symbolFor(&a, fnNode)
2465
                else throw testing::TestError::Failed;
2466
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2467
                else throw testing::TestError::Failed;
2468
            try expectType(&a, callExpr, *fnTy.returnType);
2469
        }
2470
    }
2471
}
2472
2473
@test unsafe fn testResolveFnTypeMultipleParams() throws (testing::TestError) {
2474
    let mut testArena116 = testArena();
2475
    let testStorage116: 'test116 = &mut testArena116 in {
2476
        let mut a = testResolver(testStorage116);
2477
        let program = "fn f(x: i8, y: i32) {} let x: i8 = 1; let y: i32 = 2; f(x, y);";
2478
        let result = try resolveProgramStr(&mut a, program);
2479
        try expectNoErrors(&result);
2480
2481
        let blockNode = result.root;
2482
        let case ast::NodeValue::Block(block) = blockNode.value
2483
            else throw testing::TestError::Failed;
2484
        let fnNode = try getBlockStmt(blockNode, 0);
2485
        let callStmt = try getBlockStmt(blockNode, 3);
2486
2487
        { // Ensure multi-parameter signatures record both argument types.
2488
            let sym = super::symbolFor(&a, fnNode)
2489
                else throw testing::TestError::Failed;
2490
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2491
                else throw testing::TestError::Failed;
2492
            try testing::expect(fnTy.paramTypes.len == 2);
2493
            try testing::expect(*fnTy.paramTypes[0] == super::Type::I8);
2494
            try testing::expect(*fnTy.paramTypes[1] == super::Type::I32);
2495
            try testing::expect(*fnTy.returnType == super::Type::Void);
2496
2497
            let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
2498
                else throw testing::TestError::Failed;
2499
            try testing::expect(fnDecl.sig.params.len == 2);
2500
2501
            let firstParam = fnDecl.sig.params[0];
2502
            let secondParam = fnDecl.sig.params[1];
2503
            try expectType(&a, firstParam, super::Type::I8);
2504
            try expectType(&a, secondParam, super::Type::I32);
2505
        }
2506
        { // Call expression should again mirror the function return type.
2507
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
2508
            let fnSym = super::symbolFor(&a, fnNode)
2509
                else throw testing::TestError::Failed;
2510
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2511
                else throw testing::TestError::Failed;
2512
            try expectType(&a, callExpr, *fnTy.returnType);
2513
        }
2514
    }
2515
}
2516
2517
@test unsafe fn testResolveFnRecursiveCall() throws (testing::TestError) {
2518
    let mut testArena117 = testArena();
2519
    let testStorage117: 'test117 = &mut testArena117 in {
2520
        let mut a = testResolver(testStorage117);
2521
        let program = "fn flip(b: bool) -> bool { if b { return false; } return flip(false); }";
2522
        let result = try resolveProgramStr(&mut a, program);
2523
        try expectNoErrors(&result);
2524
2525
        let blockNode = result.root;
2526
        let case ast::NodeValue::Block(block) = blockNode.value
2527
            else throw testing::TestError::Failed;
2528
        let fnNode = try getBlockStmt(blockNode, 0);
2529
2530
        { // Function symbol should be visible for recursive calls within its own body.
2531
            let sym = super::symbolFor(&a, fnNode)
2532
                else throw testing::TestError::Failed;
2533
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2534
                else throw testing::TestError::Failed;
2535
            try testing::expect(fnTy.paramTypes.len == 1);
2536
            try testing::expect(*fnTy.paramTypes[0] == super::Type::Bool);
2537
            try testing::expect(*fnTy.returnType == super::Type::Bool);
2538
        }
2539
    }
2540
}
2541
2542
@test unsafe fn testResolveFnCallMissingArgument() throws (testing::TestError) {
2543
    let mut testArena118 = testArena();
2544
    let testStorage118: 'test118 = &mut testArena118 in {
2545
        let mut a = testResolver(testStorage118);
2546
        let program = "fn f(x: i8) {} f();";
2547
        let result = try resolveProgramStr(&mut a, program);
2548
        // Expect an error when a required parameter is omitted.
2549
        try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
2550
            expected: 1,
2551
            actual: 0,
2552
        }));
2553
    }
2554
}
2555
2556
@test unsafe fn testResolveFnCallExtraArgument() throws (testing::TestError) {
2557
    let mut testArena119 = testArena();
2558
    let testStorage119: 'test119 = &mut testArena119 in {
2559
        let mut a = testResolver(testStorage119);
2560
        let program = "fn f() {} f(1);";
2561
        let result = try resolveProgramStr(&mut a, program);
2562
        // Passing more arguments than declared should fail.
2563
        try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
2564
            expected: 0,
2565
            actual: 1,
2566
        }));
2567
    }
2568
}
2569
2570
/// Invalid calls in function bodies retain their resolution diagnostics.
2571
@test unsafe fn testInvalidBodyCalls() throws (testing::TestError) {
2572
    for program in &[
2573
        "fn f(x: u32) {} fn g() { f(1, 2); }",
2574
        "fn f(x: u32) {} fn g() { if true { f(1, 2); } }",
2575
        "fn f(x: u32) {} unsafe fn g() { f(1, 2); }",
2576
    ] {
2577
        let mut arena = testArena();
2578
        let storage: 'test = &mut arena in {
2579
            let mut res = testResolver(storage);
2580
            let result = try resolveProgramStr(&mut res, program);
2581
            try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
2582
                expected: 1, actual: 2,
2583
            }));
2584
        }
2585
    }
2586
}
2587
2588
/// Unsafe calls with excess arguments report the unsafe-call diagnostic.
2589
@test unsafe fn testInvalidUnsafeBodyCall() throws (testing::TestError) {
2590
    let mut arena = testArena();
2591
    let storage: 'test = &mut arena in {
2592
        let mut res = testResolver(storage);
2593
        let result = try resolveProgramStr(&mut res,
2594
            "unsafe fn f(x: u32) {} fn g() { f(1, 2); }");
2595
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
2596
    }
2597
}
2598
2599
@test unsafe fn testResolveFnCallArgumentTypeMismatch() throws (testing::TestError) {
2600
    let mut testArena120 = testArena();
2601
    let testStorage120: 'test120 = &mut testArena120 in {
2602
        let mut a = testResolver(testStorage120);
2603
        let program = "fn f(x: i8) {} f(true);";
2604
        let result = try resolveProgramStr(&mut a, program);
2605
        let err = try expectError(&result);
2606
        // The argument type (bool) should not match the parameter type (i8).
2607
        try expectTypeMismatch(err, super::Type::I8, super::Type::Bool);
2608
    }
2609
}
2610
2611
@test unsafe fn testResolveFnReturnTypeMismatch() throws (testing::TestError) {
2612
    let mut testArena121 = testArena();
2613
    let testStorage121: 'test121 = &mut testArena121 in {
2614
        let mut a = testResolver(testStorage121);
2615
        let program = "fn f() -> i32 { return true; }";
2616
        let result = try resolveProgramStr(&mut a, program);
2617
        let err = try expectError(&result);
2618
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
2619
    }
2620
}
2621
2622
@test unsafe fn testResolveFnReturnVoid() throws (testing::TestError) {
2623
    {
2624
        let mut testArena122 = testArena();
2625
        let testStorage122: 'test122 = &mut testArena122 in {
2626
            let mut a = testResolver(testStorage122);
2627
            let result = try resolveProgramStr(&mut a, "fn f() { return; }");
2628
            try expectNoErrors(&result);
2629
        }
2630
    } {
2631
        let mut testArena123 = testArena();
2632
        let testStorage123: 'test123 = &mut testArena123 in {
2633
            let mut a = testResolver(testStorage123);
2634
            let result = try resolveProgramStr(&mut a, "fn g() -> i32 { return; }");
2635
            let err = try expectError(&result);
2636
            try expectTypeMismatch(err, super::Type::I32, super::Type::Void);
2637
        }
2638
    }
2639
}
2640
2641
@test unsafe fn testResolveFnMissingReturn() throws (testing::TestError) {
2642
    {
2643
        let mut testArena124 = testArena();
2644
        let testStorage124: 'test124 = &mut testArena124 in {
2645
            let mut a = testResolver(testStorage124);
2646
            let result = try resolveProgramStr(&mut a, "fn f() -> i32 {}");
2647
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2648
        }
2649
    } {
2650
        let mut testArena125 = testArena();
2651
        let testStorage125: 'test125 = &mut testArena125 in {
2652
            let mut a = testResolver(testStorage125);
2653
            let program = "fn g(flag: bool) -> i32 { if flag { return 1; } 2; }";
2654
            let result = try resolveProgramStr(&mut a, program);
2655
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2656
        }
2657
    }
2658
}
2659
2660
/// Never-returning functions require divergence on every path.
2661
@test unsafe fn testResolveNeverReturn() throws (testing::TestError) {
2662
    for program in &[
2663
        "fn stop() -> ! { panic; } fn f() -> i32 { stop(); }",
2664
        "fn stop() -> ! { panic; } fn f() -> ! { return stop(); }",
2665
        "fn f(callback: fn() -> !) -> ! { callback(); }",
2666
        "fn stop() -> ! { panic; } fn f() -> ! { let _ = stop(); }",
2667
        "fn stop() -> ! { panic; } fn f() -> i32 { let value: i32 = stop(); }",
2668
        "union Token: Once { Held(u32) } fn stop() -> ! { panic; } fn f(token: Token) -> ! { stop(); }",
2669
        "union Token: Once { Held(u32) } fn stop() -> ! { panic; } fn f(token: Token) -> ! { return stop(); }",
2670
        "union Token: Once { Held(u32) } fn stop() -> ! throws (i32) { throw 1; } fn f(token: Token) -> ! { try! stop(); }",
2671
        "fn f() -> ! { while true {} }",
2672
        "fn f(flag: bool) -> ! { if flag { panic; } else { while true {} } }",
2673
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! throws (i32) { try f(); }",
2674
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> i32 { try f() catch { return 2; }; }",
2675
    ] {
2676
        let mut testArena126 = testArena();
2677
        let testStorage126: 'test126 = &mut testArena126 in {
2678
            let mut a = testResolver(testStorage126);
2679
            let result = try resolveProgramStr(&mut a, program);
2680
            try expectNoErrors(&result);
2681
        }
2682
    }
2683
}
2684
2685
/// A never-returning signature rejects any normal completion path.
2686
@test unsafe fn testResolveNeverFallthrough() throws (testing::TestError) {
2687
    for program in &[
2688
        "fn f() -> ! {}",
2689
        "fn f(flag: bool) -> ! { if flag { panic; } }",
2690
        "fn f() -> ! { while true { break; } }",
2691
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! { try f() catch {}; }",
2692
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! { try f() catch e as i32 {}; }",
2693
    ] {
2694
        let mut testArena127 = testArena();
2695
        let testStorage127: 'test127 = &mut testArena127 in {
2696
            let mut a = testResolver(testStorage127);
2697
            let result = try resolveProgramStr(&mut a, program);
2698
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2699
        }
2700
    }
2701
}
2702
2703
/// No value, including undefined, can construct a never return value.
2704
@test unsafe fn testResolveNeverValue() throws (testing::TestError) {
2705
    for program in &[
2706
        "fn f() -> ! { return; }",
2707
        "fn f() -> ! { return 1; }",
2708
        "unsafe fn f() -> ! { return undefined; }",
2709
        "fn ordinary() {} fn f() { let callback: fn() -> ! = ordinary; }",
2710
    ] {
2711
        let mut testArena128 = testArena();
2712
        let testStorage128: 'test128 = &mut testArena128 in {
2713
            let mut a = testResolver(testStorage128);
2714
            let result = try resolveProgramStr(&mut a, program);
2715
            let error = try expectError(&result);
2716
        }
2717
    }
2718
}
2719
2720
/// Caught errors preserve the caller's exact-use ownership obligations.
2721
@test unsafe fn testResolveNeverCaughtOwnership() throws (testing::TestError) {
2722
    for program in &[
2723
        "union Token: Once { Held(u32) } fn fail() -> ! throws (i32) { throw 1; } fn f(token: Token) { try fail() catch {}; }",
2724
        "union Token: Once { Held(u32) } fn fail() -> ! throws (i32) { throw 1; } fn f(token: Token) { let absent = try? fail(); }",
2725
    ] {
2726
        let mut testArena129 = testArena();
2727
        let testStorage129: 'test129 = &mut testArena129 in {
2728
            let mut a = testResolver(testStorage129);
2729
            let result = try resolveProgramStr(&mut a, program);
2730
            let error = try expectError(&result);
2731
            let case super::ErrorKind::LinearNotConsumed(_) = error.kind
2732
                else throw testing::TestError::Failed;
2733
        }
2734
    }
2735
}
2736
2737
@test unsafe fn testResolveFnAllPathsReturn() throws (testing::TestError) {
2738
    let mut testArena130 = testArena();
2739
    let testStorage130: 'test130 = &mut testArena130 in {
2740
        let mut a = testResolver(testStorage130);
2741
        let program = "fn h(flag: bool) -> i32 { if flag { return 1; } else { return 2; } }";
2742
        let result = try resolveProgramStr(&mut a, program);
2743
        try expectNoErrors(&result);
2744
    }
2745
}
2746
2747
/// Test that match statements with returns in all branches don't require a
2748
/// return at the end of the function.
2749
@test unsafe fn testResolveFnMatchAllPathsReturn() throws (testing::TestError) {
2750
    {
2751
        // Union match with all variants returning.
2752
        let mut testArena131 = testArena();
2753
        let testStorage131: 'test131 = &mut testArena131 in {
2754
            let mut a = testResolver(testStorage131);
2755
            let program = "union E { A, B } fn f(e: E) -> i32 { match e { case E::A => return 1, case E::B => return 2 } }";
2756
            let result = try resolveProgramStr(&mut a, program);
2757
            try expectNoErrors(&result);
2758
        }
2759
    } {
2760
        // Match with default case where all branches return.
2761
        let mut testArena132 = testArena();
2762
        let testStorage132: 'test132 = &mut testArena132 in {
2763
            let mut a = testResolver(testStorage132);
2764
            let program = "fn f(x: i32) -> i32 { match x { case 1 => return 1, else => return 0, } }";
2765
            let result = try resolveProgramStr(&mut a, program);
2766
            try expectNoErrors(&result);
2767
        }
2768
    } {
2769
        // Match where not all branches return should error.
2770
        let mut testArena133 = testArena();
2771
        let testStorage133: 'test133 = &mut testArena133 in {
2772
            let mut a = testResolver(testStorage133);
2773
            let program = "union E { A, B } fn f(e: E) -> i32 { match e { case E::A => return 1, case E::B => {} } }";
2774
            let result = try resolveProgramStr(&mut a, program);
2775
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2776
        }
2777
    }
2778
}
2779
2780
@test unsafe fn testResolveAssign() throws (testing::TestError) {
2781
    {
2782
        let mut testArena134 = testArena();
2783
        let testStorage134: 'test134 = &mut testArena134 in {
2784
            let mut a = testResolver(testStorage134);
2785
            let result = try resolveProgramStr(&mut a, "let mut x: i32 = 0; set x = 1;");
2786
            try expectNoErrors(&result);
2787
        }
2788
    } {
2789
        let mut testArena135 = testArena();
2790
        let testStorage135: 'test135 = &mut testArena135 in {
2791
            let mut a = testResolver(testStorage135);
2792
            let result = try resolveProgramStr(&mut a, "let x: i32 = 0; set x = 1;");
2793
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2794
        }
2795
    } {
2796
        let mut testArena136 = testArena();
2797
        let testStorage136: 'test136 = &mut testArena136 in {
2798
            let mut a = testResolver(testStorage136);
2799
            let result = try resolveProgramStr(&mut a, "let mut x: bool = false; set x = 1;");
2800
            let err = try expectError(&result);
2801
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
2802
        }
2803
    } {
2804
        let mut testArena137 = testArena();
2805
        let testStorage137: 'test137 = &mut testArena137 in {
2806
            let mut a = testResolver(testStorage137);
2807
            let result = try resolveProgramStr(&mut a, "set x = 1;");
2808
            try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
2809
        }
2810
    } {
2811
        let mut testArena138 = testArena();
2812
        let testStorage138: 'test138 = &mut testArena138 in {
2813
            let mut a = testResolver(testStorage138);
2814
            let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = 1;");
2815
            try expectNoErrors(&result);
2816
        }
2817
    } {
2818
        let mut testArena139 = testArena();
2819
        let testStorage139: 'test139 = &mut testArena139 in {
2820
            let mut a = testResolver(testStorage139);
2821
            let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = nil;");
2822
            try expectNoErrors(&result);
2823
        }
2824
    }
2825
}
2826
2827
@test unsafe fn testResolveAssignSubscript() throws (testing::TestError) {
2828
    {
2829
        let mut testArena140 = testArena();
2830
        let testStorage140: 'test140 = &mut testArena140 in {
2831
            let mut a = testResolver(testStorage140);
2832
            let program = "let mut xs: [u8; 2] = [0, 1]; set xs[0] = 9;";
2833
            let result = try resolveProgramStr(&mut a, program);
2834
            try expectNoErrors(&result);
2835
        }
2836
    }
2837
    {
2838
        let mut testArena141 = testArena();
2839
        let testStorage141: 'test141 = &mut testArena141 in {
2840
            let mut a = testResolver(testStorage141);
2841
            let program = "static xs: [u8; 2] = [0, 1]; let slice: *mut [u8] = &mut xs[..]; set slice[0] = 1;";
2842
            let result = try resolveProgramStr(&mut a, program);
2843
            try expectNoErrors(&result);
2844
        }
2845
    }
2846
    {
2847
        let mut testArena142 = testArena();
2848
        let testStorage142: 'test142 = &mut testArena142 in {
2849
            let mut a = testResolver(testStorage142);
2850
            let program = "static xs: [u8; 2] = [0, 1]; let mut slice: *[u8] = &xs[..]; set slice[0] = 1;";
2851
            let result = try resolveProgramStr(&mut a, program);
2852
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2853
        }
2854
    }
2855
    {
2856
        let mut testArena143 = testArena();
2857
        let testStorage143: 'test143 = &mut testArena143 in {
2858
            let mut a = testResolver(testStorage143);
2859
            let program = "let xs: [u8; 2] = [0, 1]; set xs[0] = 9;";
2860
            let result = try resolveProgramStr(&mut a, program);
2861
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2862
        }
2863
    }
2864
    {
2865
        let mut testArena144 = testArena();
2866
        let testStorage144: 'test144 = &mut testArena144 in {
2867
            let mut a = testResolver(testStorage144);
2868
            let program = "static xs: [u8; 2] = [0, 1]; let slice: *[u8] = &xs[..]; set slice[0] = 1;";
2869
            let result = try resolveProgramStr(&mut a, program);
2870
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2871
        }
2872
    }
2873
}
2874
2875
@test unsafe fn testResolveAssignIntegerLits() throws (testing::TestError) {
2876
    try expectAnalyzeOk("let x: i8 = 127;");
2877
    try expectAnalyzeOk("let x: i8 = 0x7F;");
2878
    try expectAnalyzeOk("let x: i8 = -128;");
2879
    try expectAnalyzeOk("let x: u8 = 255;");
2880
    try expectAnalyzeOk("let x: u8 = 0b11111111;");
2881
    try expectAnalyzeOk("let x: i16 = 0x7FFF;");
2882
    try expectAnalyzeOk("let x: i16 = -32768;");
2883
    try expectAnalyzeOk("let x: u16 = 0xFFFF;");
2884
    try expectAnalyzeOk("let x: i32 = 2147483647;");
2885
    try expectAnalyzeOk("let x: i32 = -2147483648;");
2886
    try expectAnalyzeOk("let x: u32 = 0xFFFFFFFF;");
2887
    try expectAnalyzeOk("let x: i64 = 9223372036854775807;");
2888
    try expectAnalyzeOk("let x: i64 = -9223372036854775808;");
2889
2890
    try expectAnalyzeOk("constant LIMIT: u8 = 0xFF;");
2891
2892
    try expectIntMismatch("let x: i8 = 128;", super::Type::I8);
2893
    try expectIntMismatch("let x: i8 = -129;", super::Type::I8);
2894
    try expectIntMismatch("let x: i8 = 0x80;", super::Type::I8);
2895
    try expectIntMismatch("let x: i8 = 0b10000000;", super::Type::I8);
2896
    try expectIntMismatch("let x: u8 = 256;", super::Type::U8);
2897
    try expectIntMismatch("let x: u8 = -1;", super::Type::U8);
2898
    try expectIntMismatch("let x: u8 = 0b100000000;", super::Type::U8);
2899
    try expectIntMismatch("let x: i16 = 32768;", super::Type::I16);
2900
    try expectIntMismatch("let x: i16 = -32769;", super::Type::I16);
2901
    try expectIntMismatch("let x: u16 = 65536;", super::Type::U16);
2902
    try expectIntMismatch("let x: u16 = -1;", super::Type::U16);
2903
    try expectIntMismatch("let x: i32 = 2147483648;", super::Type::I32);
2904
    try expectIntMismatch("let x: i32 = -2147483649;", super::Type::I32);
2905
    try expectIntMismatch("let x: i32 = 0xFFFFFFFF;", super::Type::I32);
2906
    try expectIntMismatch("let x: u32 = -1;", super::Type::U32);
2907
    try expectIntMismatch("let x: u32 = 0x100000000;", super::Type::U32);
2908
    try expectIntMismatch("let x: i64 = 9223372036854775808;", super::Type::I64);
2909
    try expectIntMismatch("let x: i64 = -9223372036854775809;", super::Type::I64);
2910
    try expectIntMismatch("constant LIMIT: u8 = 512;", super::Type::U8);
2911
    try expectIntMismatch("constant LIMIT: u8 = -5;", super::Type::U8);
2912
}
2913
2914
@test unsafe fn testNilCoercions() throws (testing::TestError) {
2915
    {
2916
        let mut testArena145 = testArena();
2917
        let testStorage145: 'test145 = &mut testArena145 in {
2918
            let mut a = testResolver(testStorage145);
2919
            let result = try resolveBlockStr(&mut a, "let opt: ?i32 = nil;");
2920
            try expectNoErrors(&result);
2921
        }
2922
    } {
2923
        let mut testArena146 = testArena();
2924
        let testStorage146: 'test146 = &mut testArena146 in {
2925
            let mut a = testResolver(testStorage146);
2926
            let program = "fn g(opt: ?i32) {} fn f() { g(nil); }";
2927
            let result = try resolveProgramStr(&mut a, program);
2928
            try expectNoErrors(&result);
2929
        }
2930
    } {
2931
        let mut testArena147 = testArena();
2932
        let testStorage147: 'test147 = &mut testArena147 in {
2933
            let mut a = testResolver(testStorage147);
2934
            let program = "fn make(flag: bool) -> ?i32 { if flag { return 1; } return nil; }";
2935
            let result = try resolveProgramStr(&mut a, program);
2936
            try expectNoErrors(&result);
2937
        }
2938
    }
2939
}
2940
2941
@test unsafe fn testOptionalComparedWithNil() throws (testing::TestError) {
2942
    let mut testArena148 = testArena();
2943
    let testStorage148: 'test148 = &mut testArena148 in {
2944
        let mut a = testResolver(testStorage148);
2945
        let program = "let opt: ?i32 = nil; opt == nil; nil == opt; opt == 1; 1 == opt; opt == opt; nil == nil;";
2946
        let result = try resolveBlockStr(&mut a, program);
2947
        try expectNoErrors(&result);
2948
2949
        for i in 1..7 {
2950
            let stmt = try getBlockStmt(result.root, i);
2951
            try expectExprStmtType(&a, stmt, super::Type::Bool);
2952
        }
2953
    }
2954
}
2955
2956
@test unsafe fn testResolveRecordLiteralAllFieldsSet() throws (testing::TestError) {
2957
    let mut testArena149 = testArena();
2958
    let testStorage149: 'test149 = &mut testArena149 in {
2959
        let mut a = testResolver(testStorage149);
2960
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1, y: 2 };";
2961
        let result = try resolveProgramStr(&mut a, program);
2962
        try expectNoErrors(&result);
2963
    }
2964
}
2965
2966
@test unsafe fn testResolveRecordLiteralMissingField() throws (testing::TestError) {
2967
    let mut testArena150 = testArena();
2968
    let testStorage150: 'test150 = &mut testArena150 in {
2969
        let mut a = testResolver(testStorage150);
2970
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1 };";
2971
        let result = try resolveProgramStr(&mut a, program);
2972
        try expectErrorKind(&result, super::ErrorKind::RecordFieldMissing("y"));
2973
    }
2974
}
2975
2976
@test unsafe fn testResolveRecordLiteralFieldTypeMismatch() throws (testing::TestError) {
2977
    let mut testArena151 = testArena();
2978
    let testStorage151: 'test151 = &mut testArena151 in {
2979
        let mut a = testResolver(testStorage151);
2980
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: true, y: 2 };";
2981
        let result = try resolveProgramStr(&mut a, program);
2982
        let err = try expectError(&result);
2983
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
2984
2985
        let errNode = err.node
2986
            else throw testing::TestError::Failed;
2987
        let case ast::NodeValue::Bool(_) = errNode.value
2988
            else throw testing::TestError::Failed;
2989
    }
2990
}
2991
2992
@test unsafe fn testResolveRecordLiteralExtraField() throws (testing::TestError) {
2993
    let mut testArena152 = testArena();
2994
    let testStorage152: 'test152 = &mut testArena152 in {
2995
        let mut a = testResolver(testStorage152);
2996
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1, z: 3, y: 2 };";
2997
        let result = try resolveProgramStr(&mut a, program);
2998
        let err = try expectError(&result);
2999
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
3000
            else throw testing::TestError::Failed;
3001
    }
3002
}
3003
3004
/// Test that anonymous record literals with labels can be passed to functions expecting named records.
3005
@test unsafe fn testResolveAnonRecordLabeledToNamedRecord() throws (testing::TestError) {
3006
    let mut testArena153 = testArena();
3007
    let testStorage153: 'test153 = &mut testArena153 in {
3008
        let mut a = testResolver(testStorage153);
3009
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) -> i32 { return p.x; } foo({ x: 1, y: 2 });";
3010
        let result = try resolveProgramStr(&mut a, program);
3011
        try expectNoErrors(&result);
3012
    }
3013
}
3014
3015
/// Test that anonymous record with wrong field name causes out of order error.
3016
@test unsafe fn testResolveAnonRecordWrongFieldName() throws (testing::TestError) {
3017
    let mut testArena154 = testArena();
3018
    let testStorage154: 'test154 = &mut testArena154 in {
3019
        let mut a = testResolver(testStorage154);
3020
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1, z: 2 });";
3021
        let result = try resolveProgramStr(&mut a, program);
3022
        let err = try expectError(&result);
3023
        let case super::ErrorKind::RecordFieldOutOfOrder { field: _, prev: _ } = err.kind
3024
            else throw testing::TestError::Failed;
3025
    }
3026
}
3027
3028
/// Test that anonymous record with wrong field type causes type mismatch.
3029
@test unsafe fn testResolveAnonRecordWrongFieldType() throws (testing::TestError) {
3030
    let mut testArena155 = testArena();
3031
    let testStorage155: 'test155 = &mut testArena155 in {
3032
        let mut a = testResolver(testStorage155);
3033
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: true, y: 2 });";
3034
        let result = try resolveProgramStr(&mut a, program);
3035
        let err = try expectError(&result);
3036
        let case super::ErrorKind::TypeMismatch(_) = err.kind
3037
            else throw testing::TestError::Failed;
3038
    }
3039
}
3040
3041
/// Test that anonymous record with missing field causes a missing field error.
3042
@test unsafe fn testResolveAnonRecordMissingField() throws (testing::TestError) {
3043
    let mut testArena156 = testArena();
3044
    let testStorage156: 'test156 = &mut testArena156 in {
3045
        let mut a = testResolver(testStorage156);
3046
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1 });";
3047
        let result = try resolveProgramStr(&mut a, program);
3048
        try expectErrorKind(&result, super::ErrorKind::RecordFieldMissing("y"));
3049
    }
3050
}
3051
3052
/// Test that anonymous record with extra field causes a count mismatch error.
3053
@test unsafe fn testResolveAnonRecordExtraField() throws (testing::TestError) {
3054
    let mut testArena157 = testArena();
3055
    let testStorage157: 'test157 = &mut testArena157 in {
3056
        let mut a = testResolver(testStorage157);
3057
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1, y: 2, z: 3 });";
3058
        let result = try resolveProgramStr(&mut a, program);
3059
        let err = try expectError(&result);
3060
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
3061
            else throw testing::TestError::Failed;
3062
    }
3063
}
3064
3065
/// Test that anonymous record fields can be coerced (e.g., i32 to optional).
3066
@test unsafe fn testResolveAnonRecordFieldCoercion() throws (testing::TestError) {
3067
    let mut testArena158 = testArena();
3068
    let testStorage158: 'test158 = &mut testArena158 in {
3069
        let mut a = testResolver(testStorage158);
3070
        let program = "record Opt { x: ?i32 } fn foo(p: Opt) {} foo({ x: 42 });";
3071
        let result = try resolveProgramStr(&mut a, program);
3072
        try expectNoErrors(&result);
3073
    }
3074
}
3075
3076
/// Test that arrays of anonymous records with labeled fields are allowed.
3077
@test unsafe fn testResolveAnonRecordArray() throws (testing::TestError) {
3078
    let mut testArena159 = testArena();
3079
    let testStorage159: 'test159 = &mut testArena159 in {
3080
        let mut a = testResolver(testStorage159);
3081
        let program = "record Pt { x: i32, y: i32 } constant ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4 }];";
3082
        let result = try resolveProgramStr(&mut a, program);
3083
        try expectNoErrors(&result);
3084
    }
3085
}
3086
3087
/// Test that arrays of anonymous records with extra fields cause count mismatch.
3088
@test unsafe fn testResolveAnonRecordArrayMismatch() throws (testing::TestError) {
3089
    let mut testArena160 = testArena();
3090
    let testStorage160: 'test160 = &mut testArena160 in {
3091
        let mut a = testResolver(testStorage160);
3092
        let program = "record Pt { x: i32, y: i32 } constant ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4, z: 5 }];";
3093
        let result = try resolveProgramStr(&mut a, program);
3094
        let err = try expectError(&result);
3095
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
3096
            else throw testing::TestError::Failed;
3097
    }
3098
}
3099
3100
/// Test that unlabeled record declarations are analyzed correctly.
3101
@test unsafe fn testResolveUnlabeledRecordDecl() throws (testing::TestError) {
3102
    let mut testArena161 = testArena();
3103
    let testStorage161: 'test161 = &mut testArena161 in {
3104
        let mut a = testResolver(testStorage161);
3105
        let program = "record R(i32, bool);";
3106
        let result = try resolveProgramStr(&mut a, program);
3107
        try expectNoErrors(&result);
3108
3109
        // Verify the type symbol was created with labeled=false.
3110
        let nominalTy = try getTypeInScopeOf(&a, result.root, "R");
3111
        let case super::NominalType::Record(recordType) = *nominalTy
3112
            else throw testing::TestError::Failed;
3113
        try testing::expect(not recordType.labeled);
3114
        try testing::expect(recordType.fields.len == 2);
3115
        try testing::expect(recordType.fields[0].name == nil);
3116
        try testing::expect(recordType.fields[1].name == nil);
3117
    }
3118
}
3119
3120
@test unsafe fn testResolveLabeledRecordDecl() throws (testing::TestError) {
3121
    let mut testArena162 = testArena();
3122
    let testStorage162: 'test162 = &mut testArena162 in {
3123
        let mut a = testResolver(testStorage162);
3124
        let program = "record R { x: i32, y: i32 }";
3125
        let result = try resolveProgramStr(&mut a, program);
3126
        try expectNoErrors(&result);
3127
3128
        let nominalTy = try getTypeInScopeOf(&a, result.root, "R");
3129
        let case super::NominalType::Record(recordType) = *nominalTy
3130
            else throw testing::TestError::Failed;
3131
        try testing::expect(recordType.labeled);
3132
        try testing::expect(recordType.fields.len == 2);
3133
        try testing::expect(recordType.fields[0].name <> nil);
3134
        try testing::expect(recordType.fields[1].name <> nil);
3135
    }
3136
}
3137
3138
@test unsafe fn testResolveRecordFieldAccessValid() throws (testing::TestError) {
3139
    let mut testArena163 = testArena();
3140
    let testStorage163: 'test163 = &mut testArena163 in {
3141
        let mut a = testResolver(testStorage163);
3142
        let program = "record Pt { x: i32, y: u8 } let p = Pt { x: 1, y: 2 }; p.y;";
3143
        let result = try resolveProgramStr(&mut a, program);
3144
        try expectNoErrors(&result);
3145
3146
        let fieldStmt = try getBlockStmt(result.root, 2);
3147
        try expectExprStmtType(&a, fieldStmt, super::Type::U8);
3148
    }
3149
}
3150
3151
@test unsafe fn testResolveRecordFieldAccessUnknownField() throws (testing::TestError) {
3152
    let mut testArena164 = testArena();
3153
    let testStorage164: 'test164 = &mut testArena164 in {
3154
        let mut a = testResolver(testStorage164);
3155
        let program = "record Pt { x: i32 } let p = Pt { x: 1 }; p.y;";
3156
        let result = try resolveProgramStr(&mut a, program);
3157
        try expectErrorKind(&result, super::ErrorKind::RecordFieldUnknown("y"));
3158
    }
3159
}
3160
3161
@test unsafe fn testResolveRecordFieldAccessOnFunctionReturn() throws (testing::TestError) {
3162
    let mut testArena165 = testArena();
3163
    let testStorage165: 'test165 = &mut testArena165 in {
3164
        let mut a = testResolver(testStorage165);
3165
        let program = "record Pt { x: i32, y: i32 } fn make() -> Pt { return Pt { x: 5, y: 10 }; } make().x;";
3166
        let result = try resolveProgramStr(&mut a, program);
3167
        try expectNoErrors(&result);
3168
3169
        let stmt = try getBlockStmt(result.root, 2);
3170
        try expectExprStmtType(&a, stmt, super::Type::I32);
3171
    }
3172
}
3173
3174
@test unsafe fn testResolveRecordFieldAccessChained() throws (testing::TestError) {
3175
    let mut testArena166 = testArena();
3176
    let testStorage166: 'test166 = &mut testArena166 in {
3177
        let mut a = testResolver(testStorage166);
3178
        let program = "record C { value: i32 } record B { c: C } record A { b: B } let a = A { b: B { c: C { value: 100 } } }; a.b.c.value;";
3179
        let result = try resolveProgramStr(&mut a, program);
3180
        try expectNoErrors(&result);
3181
3182
        let stmt = try getBlockStmt(result.root, 4);
3183
        try expectExprStmtType(&a, stmt, super::Type::I32);
3184
    }
3185
}
3186
3187
@test unsafe fn testResolveRecordFieldAccessOnInteger() throws (testing::TestError) {
3188
    let mut testArena167 = testArena();
3189
    let testStorage167: 'test167 = &mut testArena167 in {
3190
        let mut a = testResolver(testStorage167);
3191
        let program = "let x: i32 = 42; x.field;";
3192
        let result = try resolveBlockStr(&mut a, program);
3193
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
3194
    }
3195
}
3196
3197
@test unsafe fn testResolveRecordFieldAccessOnArray() throws (testing::TestError) {
3198
    let mut testArena168 = testArena();
3199
    let testStorage168: 'test168 = &mut testArena168 in {
3200
        let mut a = testResolver(testStorage168);
3201
        let program = "let arr: [i32; 3] = [1, 2, 3]; arr.field;";
3202
        let result = try resolveProgramStr(&mut a, program);
3203
        try expectErrorKind(&result, super::ErrorKind::ArrayFieldUnknown("field"));
3204
    }
3205
}
3206
3207
@test unsafe fn testResolveRecordFieldAccessOnBool() throws (testing::TestError) {
3208
    let mut testArena169 = testArena();
3209
    let testStorage169: 'test169 = &mut testArena169 in {
3210
        let mut a = testResolver(testStorage169);
3211
        let program = "let b: bool = true; b.field;";
3212
        let result = try resolveProgramStr(&mut a, program);
3213
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
3214
    }
3215
}
3216
3217
@test unsafe fn testResolveRecordFieldAccessOnOptional() throws (testing::TestError) {
3218
    let mut testArena170 = testArena();
3219
    let testStorage170: 'test170 = &mut testArena170 in {
3220
        let mut a = testResolver(testStorage170);
3221
        let program = "record Pt { x: i32 } let opt: ?Pt = Pt { x: 5 }; opt.x;";
3222
        let result = try resolveProgramStr(&mut a, program);
3223
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
3224
    }
3225
}
3226
3227
/// Records may reference themselves through pointers without causing resolution errors.
3228
@test unsafe fn testResolveRecordSelfReferentialPointer() throws (testing::TestError) {
3229
    let mut testArena171 = testArena();
3230
    let testStorage171: 'test171 = &mut testArena171 in {
3231
        let mut a = testResolver(testStorage171);
3232
        let program = "record A { next: *A }";
3233
        let result = try resolveProgramStr(&mut a, program);
3234
        try expectNoErrors(&result);
3235
    }
3236
}
3237
3238
/// Mutually recursive records should resolve without infinite loops.
3239
@test unsafe fn testResolveRecordMutuallyRecursive() throws (testing::TestError) {
3240
    let mut testArena172 = testArena();
3241
    let testStorage172: 'test172 = &mut testArena172 in {
3242
        let mut a = testResolver(testStorage172);
3243
        let program = "record A { b: *B } record B { a: *A }";
3244
        let result = try resolveProgramStr(&mut a, program);
3245
        try expectNoErrors(&result);
3246
    }
3247
}
3248
3249
/// Unions may reference themselves through pointers without causing resolution errors.
3250
@test unsafe fn testResolveUnionSelfReferentialPointerAllowed() throws (testing::TestError) {
3251
    let mut testArena173 = testArena();
3252
    let testStorage173: 'test173 = &mut testArena173 in {
3253
        let mut a = testResolver(testStorage173);
3254
        let program = "union List { Cons(*List), Nil }";
3255
        let result = try resolveProgramStr(&mut a, program);
3256
        try expectNoErrors(&result);
3257
    }
3258
}
3259
3260
/// Mutually recursive unions should resolve without infinite loops.
3261
@test unsafe fn testResolveUnionMutuallyRecursive() throws (testing::TestError) {
3262
    let mut testArena174 = testArena();
3263
    let testStorage174: 'test174 = &mut testArena174 in {
3264
        let mut a = testResolver(testStorage174);
3265
        let program = "union A { HasB(*B), None } union B { HasA(*A), None }";
3266
        let result = try resolveProgramStr(&mut a, program);
3267
        try expectNoErrors(&result);
3268
    }
3269
}
3270
3271
/// Unions with record payloads containing slice references to self should resolve.
3272
/// This matches the pattern in sexpr.rad: `List { tail: *[Expr] }`.
3273
@test unsafe fn testResolveUnionRecordPayloadWithSliceSelfRef() throws (testing::TestError) {
3274
    let mut testArena175 = testArena();
3275
    let testStorage175: 'test175 = &mut testArena175 in {
3276
        let mut a = testResolver(testStorage175);
3277
        let program = "union Expr { Null, List { head: *[u8], tail: *[Expr] } }";
3278
        let result = try resolveProgramStr(&mut a, program);
3279
        try expectNoErrors(&result);
3280
    }
3281
}
3282
3283
@test unsafe fn testUndefinedCoercions() throws (testing::TestError) {
3284
    {
3285
        let mut testArena176 = testArena();
3286
        let testStorage176: 'test176 = &mut testArena176 in {
3287
            let mut a = testResolver(testStorage176);
3288
            let result = try resolveBlockStr(&mut a, "unsafe { let count: i32 = undefined; }");
3289
            try expectNoErrors(&result);
3290
        }
3291
    } {
3292
        let mut testArena177 = testArena();
3293
        let testStorage177: 'test177 = &mut testArena177 in {
3294
            let mut a = testResolver(testStorage177);
3295
            let program = "unsafe { let mut value: i32 = 0; set value = undefined; }";
3296
            let result = try resolveProgramStr(&mut a, program);
3297
            try expectNoErrors(&result);
3298
        }
3299
    } {
3300
        let mut testArena178 = testArena();
3301
        let testStorage178: 'test178 = &mut testArena178 in {
3302
            let mut a = testResolver(testStorage178);
3303
            let program = "fn f(x: i32) {} unsafe fn g() { f(undefined); }";
3304
            let result = try resolveProgramStr(&mut a, program);
3305
            try expectNoErrors(&result);
3306
        }
3307
    } {
3308
        let mut testArena179 = testArena();
3309
        let testStorage179: 'test179 = &mut testArena179 in {
3310
            let mut a = testResolver(testStorage179);
3311
            let program = "unsafe fn fetch() -> i32 { return undefined; }";
3312
            let result = try resolveProgramStr(&mut a, program);
3313
            try expectNoErrors(&result);
3314
        }
3315
    }
3316
}
3317
3318
@test unsafe fn testResolveBlockVoid() throws (testing::TestError) {
3319
    let mut testArena180 = testArena();
3320
    let testStorage180: 'test180 = &mut testArena180 in {
3321
        let mut a = testResolver(testStorage180);
3322
        let result = try resolveProgramStr(&mut a, "{ 42; }");
3323
        try expectNoErrors(&result);
3324
3325
        let block = try getBlockStmt(result.root, 0);
3326
        try expectType(&a, block, super::Type::Void);
3327
    }
3328
}
3329
3330
@test unsafe fn testResolveBlockNever() throws (testing::TestError) {
3331
    let mut testArena181 = testArena();
3332
    let testStorage181: 'test181 = &mut testArena181 in {
3333
        let mut a = testResolver(testStorage181);
3334
        let result = try resolveProgramStr(&mut a, "{ panic; }");
3335
        try expectNoErrors(&result);
3336
3337
        let block = try getBlockStmt(result.root, 0);
3338
        try expectType(&a, block, super::Type::Never);
3339
    }
3340
}
3341
3342
@test unsafe fn testResolveIfAllBranchesNever() throws (testing::TestError) {
3343
    let mut testArena182 = testArena();
3344
    let testStorage182: 'test182 = &mut testArena182 in {
3345
        let mut a = testResolver(testStorage182);
3346
        let program = "if true { panic; } else { panic; }";
3347
        let result = try resolveProgramStr(&mut a, program);
3348
        try expectNoErrors(&result);
3349
3350
        let stmt = try getBlockStmt(result.root, 0);
3351
        try expectType(&a, stmt, super::Type::Never);
3352
    }
3353
}
3354
3355
@test unsafe fn testResolveIfMixedBranchesNotNever() throws (testing::TestError) {
3356
    let mut testArena183 = testArena();
3357
    let testStorage183: 'test183 = &mut testArena183 in {
3358
        let mut a = testResolver(testStorage183);
3359
        let program = "if true { panic; } else {}";
3360
        let result = try resolveProgramStr(&mut a, program);
3361
        try expectNoErrors(&result);
3362
3363
        let stmt = try getBlockStmt(result.root, 0);
3364
        try expectType(&a, stmt, super::Type::Void);
3365
    }
3366
}
3367
3368
@test unsafe fn testResolveLetElse() throws (testing::TestError) {
3369
    let mut testArena184 = testArena();
3370
    let testStorage184: 'test184 = &mut testArena184 in {
3371
        let mut a = testResolver(testStorage184);
3372
        let program = "let opt: ?i32 = 42; let value = opt else panic; value;";
3373
        let result = try resolveProgramStr(&mut a, program);
3374
        try expectNoErrors(&result);
3375
3376
        let blockNode = result.root;
3377
        let case ast::NodeValue::Block(block) = blockNode.value
3378
            else throw testing::TestError::Failed;
3379
        let letElseNode = try getBlockStmt(blockNode, 1);
3380
        let valueStmt = try getBlockStmt(blockNode, 2);
3381
3382
        { // Ensure the bound identifier receives the inner optional type.
3383
            let valueExpr = try expectExprStmtType(&a, valueStmt, super::Type::I32);
3384
3385
            let sym = super::symbolFor(&a, valueExpr)
3386
                else throw testing::TestError::Failed;
3387
            let case super::SymbolData::Value { type: valType, .. } = sym.data
3388
                else throw testing::TestError::Failed;
3389
            try testing::expect(valType == super::Type::I32);
3390
        }
3391
        // The let-else statement itself should be typed as void.
3392
        try expectType(&a, letElseNode, super::Type::Void);
3393
    }
3394
}
3395
3396
@test unsafe fn testResolveLetElseDefaultValue() throws (testing::TestError) {
3397
    let mut testArena185 = testArena();
3398
    let testStorage185: 'test185 = &mut testArena185 in {
3399
        let mut a = testResolver(testStorage185);
3400
        let program = "let opt: ?i32 = nil; let value = opt else 42; value;";
3401
        let result = try resolveProgramStr(&mut a, program);
3402
        try expectNoErrors(&result);
3403
    }
3404
}
3405
3406
@test unsafe fn testResolveLetElseRequiresDivergentElse() throws (testing::TestError) {
3407
    let mut testArena186 = testArena();
3408
    let testStorage186: 'test186 = &mut testArena186 in {
3409
        let mut a = testResolver(testStorage186);
3410
        let program = "let opt: ?i32 = nil; let value = opt else {}; value;";
3411
        let result = try resolveProgramStr(&mut a, program);
3412
        let err = try expectError(&result);
3413
        try expectTypeMismatch(err, super::Type::I32, super::Type::Void);
3414
    }
3415
}
3416
3417
@test unsafe fn testResolveLetElseRequiresOptional() throws (testing::TestError) {
3418
    let mut testArena187 = testArena();
3419
    let testStorage187: 'test187 = &mut testArena187 in {
3420
        let mut a = testResolver(testStorage187);
3421
        let program = "let x: i32 = 42; let value = x else panic;";
3422
        let result = try resolveProgramStr(&mut a, program);
3423
        try expectErrorKind(&result, super::ErrorKind::ExpectedOptional);
3424
    }
3425
}
3426
3427
/// Test that `if let mut` produces a mutable binding.
3428
@test unsafe fn testResolveIfLetMut() throws (testing::TestError) {
3429
    let mut testArena188 = testArena();
3430
    let testStorage188: 'test188 = &mut testArena188 in {
3431
        let mut a = testResolver(testStorage188);
3432
        let program = "let opt: ?i32 = 42; if let mut v = opt { set v = v + 1; }";
3433
        let result = try resolveProgramStr(&mut a, program);
3434
        try expectNoErrors(&result);
3435
    }
3436
}
3437
3438
/// Test that `if let` (without mut) rejects assignment.
3439
@test unsafe fn testResolveIfLetImmutable() throws (testing::TestError) {
3440
    let mut testArena189 = testArena();
3441
    let testStorage189: 'test189 = &mut testArena189 in {
3442
        let mut a = testResolver(testStorage189);
3443
        let program = "let opt: ?i32 = 42; if let v = opt { set v = 1; }";
3444
        let result = try resolveProgramStr(&mut a, program);
3445
        let err = try expectError(&result);
3446
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3447
    }
3448
}
3449
3450
/// Test that `let mut ... else` produces a mutable binding.
3451
@test unsafe fn testResolveLetMutElse() throws (testing::TestError) {
3452
    let mut testArena190 = testArena();
3453
    let testStorage190: 'test190 = &mut testArena190 in {
3454
        let mut a = testResolver(testStorage190);
3455
        let program = "let opt: ?i32 = 42; let mut v = opt else panic; set v = v + 1;";
3456
        let result = try resolveProgramStr(&mut a, program);
3457
        try expectNoErrors(&result);
3458
    }
3459
}
3460
3461
/// Test that `let ... else` (without mut) rejects assignment.
3462
@test unsafe fn testResolveLetElseImmutable() throws (testing::TestError) {
3463
    let mut testArena191 = testArena();
3464
    let testStorage191: 'test191 = &mut testArena191 in {
3465
        let mut a = testResolver(testStorage191);
3466
        let program = "let opt: ?i32 = 42; let v = opt else panic; set v = 1;";
3467
        let result = try resolveProgramStr(&mut a, program);
3468
        let err = try expectError(&result);
3469
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3470
    }
3471
}
3472
3473
@test unsafe fn testResolveLetCaseElse() throws (testing::TestError) {
3474
    {
3475
        let mut testArena192 = testArena();
3476
        let testStorage192: 'test192 = &mut testArena192 in {
3477
            let mut a = testResolver(testStorage192);
3478
            let program = "let case _ = 1 else panic;";
3479
            let result = try resolveProgramStr(&mut a, program);
3480
            try expectNoErrors(&result);
3481
        }
3482
    } {
3483
        let mut testArena193 = testArena();
3484
        let testStorage193: 'test193 = &mut testArena193 in {
3485
            let mut a = testResolver(testStorage193);
3486
            let program = "let case _ = true else false;";
3487
            let result = try resolveProgramStr(&mut a, program);
3488
            try expectNoErrors(&result);
3489
        }
3490
    }
3491
}
3492
3493
@test unsafe fn testResolveLetCaseElseRequiresDivergentElse() throws (testing::TestError) {
3494
    let mut testArena194 = testArena();
3495
    let testStorage194: 'test194 = &mut testArena194 in {
3496
        let mut a = testResolver(testStorage194);
3497
        let program = "let case _ = 1 else {};";
3498
        let result = try resolveProgramStr(&mut a, program);
3499
        let err = try expectError(&result);
3500
        try expectTypeMismatch(err, super::Type::Int, super::Type::Void);
3501
    }
3502
}
3503
3504
@test unsafe fn testResolveTryValidPropagation() throws (testing::TestError) {
3505
    let mut testArena195 = testArena();
3506
    let testStorage195: 'test195 = &mut testArena195 in {
3507
        let mut a = testResolver(testStorage195);
3508
        let program = "fn fallible() throws (i32) {} fn caller() throws (i32) { try fallible() }";
3509
        let result = try resolveProgramStr(&mut a, program);
3510
        try expectNoErrors(&result);
3511
    }
3512
}
3513
3514
@test unsafe fn testResolveTryRequiresThrowsClause() throws (testing::TestError) {
3515
    let mut testArena196 = testArena();
3516
    let testStorage196: 'test196 = &mut testArena196 in {
3517
        let mut a = testResolver(testStorage196);
3518
        let program = "fn fallible() throws (i32) {} fn caller() { try fallible() }";
3519
        let result = try resolveProgramStr(&mut a, program);
3520
        try expectErrorKind(&result, super::ErrorKind::TryRequiresThrows);
3521
    }
3522
}
3523
3524
@test unsafe fn testResolveTryIncompatibleError() throws (testing::TestError) {
3525
    let mut testArena197 = testArena();
3526
    let testStorage197: 'test197 = &mut testArena197 in {
3527
        let mut a = testResolver(testStorage197);
3528
        let program = "fn fallible() throws (i32) {} fn caller() throws (i8) { try fallible() }";
3529
        let result = try resolveProgramStr(&mut a, program);
3530
        try expectErrorKind(&result, super::ErrorKind::TryIncompatibleError);
3531
    }
3532
}
3533
3534
@test unsafe fn testResolveTryNonThrowing() throws (testing::TestError) {
3535
    let mut testArena198 = testArena();
3536
    let testStorage198: 'test198 = &mut testArena198 in {
3537
        let mut a = testResolver(testStorage198);
3538
        let program = "fn safe() {} fn caller() throws (i32) { try safe() }";
3539
        let result = try resolveProgramStr(&mut a, program);
3540
        try expectErrorKind(&result, super::ErrorKind::TryNonThrowing);
3541
    }
3542
}
3543
3544
@test unsafe fn testResolveTryCatchBlockMatchesResult() throws (testing::TestError) {
3545
    let mut testArena199 = testArena();
3546
    let testStorage199: 'test199 = &mut testArena199 in {
3547
        let mut a = testResolver(testStorage199);
3548
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { return 42; }; }";
3549
        let result = try resolveProgramStr(&mut a, program);
3550
        try expectNoErrors(&result);
3551
    }
3552
}
3553
3554
@test unsafe fn testResolveTryCatchBlockDiverges() throws (testing::TestError) {
3555
    let mut testArena200 = testArena();
3556
    let testStorage200: 'test200 = &mut testArena200 in {
3557
        let mut a = testResolver(testStorage200);
3558
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { return 7; }; }";
3559
        let result = try resolveProgramStr(&mut a, program);
3560
        try expectNoErrors(&result);
3561
    }
3562
}
3563
3564
@test unsafe fn testResolveTryCatchBlockMustDiverge() throws (testing::TestError) {
3565
    let mut testArena201 = testArena();
3566
    let testStorage201: 'test201 = &mut testArena201 in {
3567
        let mut a = testResolver(testStorage201);
3568
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { 7; }; }";
3569
        let result = try resolveProgramStr(&mut a, program);
3570
        let err = try expectError(&result);
3571
        try expectTypeMismatch(err, super::Type::U32, super::Type::Void);
3572
    }
3573
}
3574
3575
@test unsafe fn testResolveCallMissingTry() throws (testing::TestError) {
3576
    let mut testArena202 = testArena();
3577
    let testStorage202: 'test202 = &mut testArena202 in {
3578
        let mut a = testResolver(testStorage202);
3579
        let program = "fn fallible() throws (i32) {} fn caller() { fallible() }";
3580
        let result = try resolveProgramStr(&mut a, program);
3581
        try expectErrorKind(&result, super::ErrorKind::MissingTry);
3582
    }
3583
}
3584
3585
/// Test that `try?` converts errors to optionals without requiring caller to throw.
3586
@test unsafe fn testResolveTryOptionalConvertsToOptional() throws (testing::TestError) {
3587
    // `try?` should wrap the return type in optional and not require caller to throw.
3588
    {
3589
        let mut testArena203 = testArena();
3590
        let testStorage203: 'test203 = &mut testArena203 in {
3591
            let mut a = testResolver(testStorage203);
3592
            let program = "record S {} fn fallible() -> *S throws (i32) { panic; } fn caller() -> ?*S { return try? fallible(); }";
3593
            let result = try resolveProgramStr(&mut a, program);
3594
            try expectNoErrors(&result);
3595
        }
3596
    }
3597
    // `try?` works in non-throwing function.
3598
    {
3599
        let mut testArena204 = testArena();
3600
        let testStorage204: 'test204 = &mut testArena204 in {
3601
            let mut a = testResolver(testStorage204);
3602
            let program = "fn fallible() -> i32 throws (i32) { panic; } fn caller() -> ?i32 { return try? fallible(); }";
3603
            let result = try resolveProgramStr(&mut a, program);
3604
            try expectNoErrors(&result);
3605
        }
3606
    }
3607
    // `try?` can be used in if-let patterns.
3608
    {
3609
        let mut testArena205 = testArena();
3610
        let testStorage205: 'test205 = &mut testArena205 in {
3611
            let mut a = testResolver(testStorage205);
3612
            let program = "fn fallible() -> i32 throws (i32) { panic; } fn caller() -> i32 { if let x = try? fallible() { return x; } return 0; }";
3613
            let result = try resolveProgramStr(&mut a, program);
3614
            try expectNoErrors(&result);
3615
        }
3616
    }
3617
}
3618
3619
@test unsafe fn testResolveThrowValid() throws (testing::TestError) {
3620
    let mut testArena206 = testArena();
3621
    let testStorage206: 'test206 = &mut testArena206 in {
3622
        let mut a = testResolver(testStorage206);
3623
        let program = "fn fail() throws (i32) { throw 1; }";
3624
        let result = try resolveProgramStr(&mut a, program);
3625
        try expectNoErrors(&result);
3626
    }
3627
}
3628
3629
@test unsafe fn testResolveThrowRequiresThrowsClause() throws (testing::TestError) {
3630
    let mut testArena207 = testArena();
3631
    let testStorage207: 'test207 = &mut testArena207 in {
3632
        let mut a = testResolver(testStorage207);
3633
        let program = "fn fail() { throw 1; }";
3634
        let result = try resolveProgramStr(&mut a, program);
3635
        try expectErrorKind(&result, super::ErrorKind::ThrowRequiresThrows);
3636
    }
3637
}
3638
3639
@test unsafe fn testResolveThrowIncompatibleError() throws (testing::TestError) {
3640
    let mut testArena208 = testArena();
3641
    let testStorage208: 'test208 = &mut testArena208 in {
3642
        let mut a = testResolver(testStorage208);
3643
        let program = "fn fail() throws (i32) { throw true; }";
3644
        let result = try resolveProgramStr(&mut a, program);
3645
        try expectErrorKind(&result, super::ErrorKind::ThrowIncompatibleError);
3646
    }
3647
}
3648
3649
// Binary operation tests //////////////////////////////////////////////////////
3650
3651
@test unsafe fn testResolveBinaryOpArithmetic() throws (testing::TestError) {
3652
    {
3653
        let mut testArena209 = testArena();
3654
        let testStorage209: 'test209 = &mut testArena209 in {
3655
            let mut a = testResolver(testStorage209);
3656
            let result = try resolveExprStr(&mut a, "4 + 4");
3657
            try expectNoErrors(&result);
3658
            try expectType(&a, result.root, super::Type::Int);
3659
        }
3660
    } {
3661
        let mut testArena210 = testArena();
3662
        let testStorage210: 'test210 = &mut testArena210 in {
3663
            let mut a = testResolver(testStorage210);
3664
            let result = try resolveExprStr(&mut a, "10 - 3");
3665
            try expectNoErrors(&result);
3666
            try expectType(&a, result.root, super::Type::Int);
3667
        }
3668
    } {
3669
        let mut testArena211 = testArena();
3670
        let testStorage211: 'test211 = &mut testArena211 in {
3671
            let mut a = testResolver(testStorage211);
3672
            let result = try resolveExprStr(&mut a, "5 * 6");
3673
            try expectNoErrors(&result);
3674
            try expectType(&a, result.root, super::Type::Int);
3675
        }
3676
    } {
3677
        let mut testArena212 = testArena();
3678
        let testStorage212: 'test212 = &mut testArena212 in {
3679
            let mut a = testResolver(testStorage212);
3680
            let result = try resolveExprStr(&mut a, "20 / 4");
3681
            try expectNoErrors(&result);
3682
            try expectType(&a, result.root, super::Type::Int);
3683
        }
3684
    } {
3685
        let mut testArena213 = testArena();
3686
        let testStorage213: 'test213 = &mut testArena213 in {
3687
            let mut a = testResolver(testStorage213);
3688
            let result = try resolveExprStr(&mut a, "17 % 5");
3689
            try expectNoErrors(&result);
3690
            try expectType(&a, result.root, super::Type::Int);
3691
        }
3692
    } {
3693
        let mut testArena214 = testArena();
3694
        let testStorage214: 'test214 = &mut testArena214 in {
3695
            let mut a = testResolver(testStorage214);
3696
            let result = try resolveBlockStr(&mut a, "let x: i32 = 4; let y: i32 = 5; x + y;");
3697
            try expectNoErrors(&result);
3698
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3699
            try expectExprStmtType(&a, stmt, super::Type::I32);
3700
        }
3701
    } {
3702
        let mut testArena215 = testArena();
3703
        let testStorage215: 'test215 = &mut testArena215 in {
3704
            let mut a = testResolver(testStorage215);
3705
            let result = try resolveExprStr(&mut a, "1 + (2 * 3) - 4");
3706
            try expectNoErrors(&result);
3707
            try expectType(&a, result.root, super::Type::Int);
3708
        }
3709
    } {
3710
        let mut testArena216 = testArena();
3711
        let testStorage216: 'test216 = &mut testArena216 in {
3712
            let mut a = testResolver(testStorage216);
3713
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n * 2;");
3714
            try expectNoErrors(&result);
3715
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3716
            try expectExprStmtType(&a, stmt, super::Type::I32);
3717
        }
3718
    } {
3719
        let mut testArena217 = testArena();
3720
        let testStorage217: 'test217 = &mut testArena217 in {
3721
            let mut a = testResolver(testStorage217);
3722
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; 2 * n;");
3723
            try expectNoErrors(&result);
3724
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3725
            try expectExprStmtType(&a, stmt, super::Type::I32);
3726
        }
3727
    } {
3728
        let mut testArena218 = testArena();
3729
        let testStorage218: 'test218 = &mut testArena218 in {
3730
            let mut a = testResolver(testStorage218);
3731
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n - 1;");
3732
            try expectNoErrors(&result);
3733
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3734
            try expectExprStmtType(&a, stmt, super::Type::I32);
3735
        }
3736
    }
3737
}
3738
3739
@test unsafe fn testResolveBinaryOpComparison() throws (testing::TestError) {
3740
    {
3741
        let mut testArena219 = testArena();
3742
        let testStorage219: 'test219 = &mut testArena219 in {
3743
            let mut a = testResolver(testStorage219);
3744
            let result = try resolveExprStr(&mut a, "5 == 5");
3745
            try expectNoErrors(&result);
3746
            try expectType(&a, result.root, super::Type::Bool);
3747
        }
3748
    } {
3749
        let mut testArena220 = testArena();
3750
        let testStorage220: 'test220 = &mut testArena220 in {
3751
            let mut a = testResolver(testStorage220);
3752
            let result = try resolveExprStr(&mut a, "5 <> 10");
3753
            try expectNoErrors(&result);
3754
            try expectType(&a, result.root, super::Type::Bool);
3755
        }
3756
    } {
3757
        let mut testArena221 = testArena();
3758
        let testStorage221: 'test221 = &mut testArena221 in {
3759
            let mut a = testResolver(testStorage221);
3760
            let result = try resolveExprStr(&mut a, "5 < 10");
3761
            try expectNoErrors(&result);
3762
            try expectType(&a, result.root, super::Type::Bool);
3763
        }
3764
    } {
3765
        let mut testArena222 = testArena();
3766
        let testStorage222: 'test222 = &mut testArena222 in {
3767
            let mut a = testResolver(testStorage222);
3768
            let result = try resolveExprStr(&mut a, "10 > 5");
3769
            try expectNoErrors(&result);
3770
            try expectType(&a, result.root, super::Type::Bool);
3771
        }
3772
    } {
3773
        let mut testArena223 = testArena();
3774
        let testStorage223: 'test223 = &mut testArena223 in {
3775
            let mut a = testResolver(testStorage223);
3776
            let result = try resolveExprStr(&mut a, "5 <= 5");
3777
            try expectNoErrors(&result);
3778
            try expectType(&a, result.root, super::Type::Bool);
3779
        }
3780
    } {
3781
        let mut testArena224 = testArena();
3782
        let testStorage224: 'test224 = &mut testArena224 in {
3783
            let mut a = testResolver(testStorage224);
3784
            let result = try resolveExprStr(&mut a, "10 >= 5");
3785
            try expectNoErrors(&result);
3786
            try expectType(&a, result.root, super::Type::Bool);
3787
        }
3788
    } {
3789
        let mut testArena225 = testArena();
3790
        let testStorage225: 'test225 = &mut testArena225 in {
3791
            let mut a = testResolver(testStorage225);
3792
            let result = try resolveExprStr(&mut a, "true == false");
3793
            try expectNoErrors(&result);
3794
            try expectType(&a, result.root, super::Type::Bool);
3795
        }
3796
    } {
3797
        let mut testArena226 = testArena();
3798
        let testStorage226: 'test226 = &mut testArena226 in {
3799
            let mut a = testResolver(testStorage226);
3800
            let result = try resolveExprStr(&mut a, "5 + 3 > 10 - 4");
3801
            try expectNoErrors(&result);
3802
            try expectType(&a, result.root, super::Type::Bool);
3803
        }
3804
    } {
3805
        let mut testArena227 = testArena();
3806
        let testStorage227: 'test227 = &mut testArena227 in {
3807
            let mut a = testResolver(testStorage227);
3808
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n == 1;");
3809
            try expectNoErrors(&result);
3810
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3811
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3812
        }
3813
    } {
3814
        let mut testArena228 = testArena();
3815
        let testStorage228: 'test228 = &mut testArena228 in {
3816
            let mut a = testResolver(testStorage228);
3817
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; 1 == n;");
3818
            try expectNoErrors(&result);
3819
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3820
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3821
        }
3822
    }
3823
}
3824
3825
@test unsafe fn testResolveBinaryOpLogical() throws (testing::TestError) {
3826
    {
3827
        let mut testArena229 = testArena();
3828
        let testStorage229: 'test229 = &mut testArena229 in {
3829
            let mut a = testResolver(testStorage229);
3830
            let result = try resolveBlockStr(&mut a, "let x: bool = true; let y: bool = false; x and y;");
3831
            try expectNoErrors(&result);
3832
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3833
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3834
        }
3835
    } {
3836
        let mut testArena230 = testArena();
3837
        let testStorage230: 'test230 = &mut testArena230 in {
3838
            let mut a = testResolver(testStorage230);
3839
            let result = try resolveBlockStr(&mut a, "let x: bool = true; let y: bool = false; x or y;");
3840
            try expectNoErrors(&result);
3841
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3842
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3843
        }
3844
    } {
3845
        let mut testArena231 = testArena();
3846
        let testStorage231: 'test231 = &mut testArena231 in {
3847
            let mut a = testResolver(testStorage231);
3848
            let result = try resolveExprStr(&mut a, "true and false");
3849
            try expectNoErrors(&result);
3850
            try expectType(&a, result.root, super::Type::Bool);
3851
        }
3852
    }
3853
}
3854
3855
@test unsafe fn testResolveBinaryOpArithmeticTypeMismatch() throws (testing::TestError) {
3856
    {
3857
        let mut testArena232 = testArena();
3858
        let testStorage232: 'test232 = &mut testArena232 in {
3859
            let mut a = testResolver(testStorage232);
3860
            let result = try resolveProgramStr(&mut a, "4 + true");
3861
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3862
        }
3863
    } {
3864
        let mut testArena233 = testArena();
3865
        let testStorage233: 'test233 = &mut testArena233 in {
3866
            let mut a = testResolver(testStorage233);
3867
            let result = try resolveBlockStr(&mut a, "let x: i32 = 4; let y: bool = false; x + y;");
3868
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3869
        }
3870
    } {
3871
        let mut testArena234 = testArena();
3872
        let testStorage234: 'test234 = &mut testArena234 in {
3873
            let mut a = testResolver(testStorage234);
3874
            let result = try resolveProgramStr(&mut a, "10 - false");
3875
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3876
        }
3877
    } {
3878
        let mut testArena235 = testArena();
3879
        let testStorage235: 'test235 = &mut testArena235 in {
3880
            let mut a = testResolver(testStorage235);
3881
            let result = try resolveProgramStr(&mut a, "5 * true");
3882
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3883
        }
3884
    } {
3885
        let mut testArena236 = testArena();
3886
        let testStorage236: 'test236 = &mut testArena236 in {
3887
            let mut a = testResolver(testStorage236);
3888
            let result = try resolveProgramStr(&mut a, "20 / false");
3889
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3890
        }
3891
    } {
3892
        let mut testArena237 = testArena();
3893
        let testStorage237: 'test237 = &mut testArena237 in {
3894
            let mut a = testResolver(testStorage237);
3895
            let result = try resolveProgramStr(&mut a, "17 % true");
3896
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3897
        }
3898
    } {
3899
        let mut testArena238 = testArena();
3900
        let testStorage238: 'test238 = &mut testArena238 in {
3901
            let mut a = testResolver(testStorage238);
3902
            let result = try resolveProgramStr(&mut a, "1 + (true * 3)");
3903
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3904
        }
3905
    }
3906
}
3907
3908
@test unsafe fn testResolveBinaryOpLogicalTypeMismatch() throws (testing::TestError) {
3909
    {
3910
        let mut testArena239 = testArena();
3911
        let testStorage239: 'test239 = &mut testArena239 in {
3912
            let mut a = testResolver(testStorage239);
3913
            let result = try resolveProgramStr(&mut a, "42 and true");
3914
            let err = try expectError(&result);
3915
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3916
        }
3917
    } {
3918
        let mut testArena240 = testArena();
3919
        let testStorage240: 'test240 = &mut testArena240 in {
3920
            let mut a = testResolver(testStorage240);
3921
            let result = try resolveProgramStr(&mut a, "true or 5");
3922
            let err = try expectError(&result);
3923
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3924
        }
3925
    } {
3926
        let mut testArena241 = testArena();
3927
        let testStorage241: 'test241 = &mut testArena241 in {
3928
            let mut a = testResolver(testStorage241);
3929
            let result = try resolveProgramStr(&mut a, "1 and 2");
3930
            let err = try expectError(&result);
3931
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3932
        }
3933
    }
3934
}
3935
3936
@test unsafe fn testResolveBinaryOpComparisonTypeMismatch() throws (testing::TestError) {
3937
    let mut testArena242 = testArena();
3938
    let testStorage242: 'test242 = &mut testArena242 in {
3939
        let mut a = testResolver(testStorage242);
3940
        let result = try resolveProgramStr(&mut a, "true < false");
3941
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3942
    }
3943
}
3944
3945
// Unary operation tests ///////////////////////////////////////////////////////
3946
3947
@test unsafe fn testResolveUnaryOpNot() throws (testing::TestError) {
3948
    {
3949
        let mut testArena243 = testArena();
3950
        let testStorage243: 'test243 = &mut testArena243 in {
3951
            let mut a = testResolver(testStorage243);
3952
            let result = try resolveExprStr(&mut a, "not true");
3953
            try expectNoErrors(&result);
3954
            try expectType(&a, result.root, super::Type::Bool);
3955
        }
3956
    } {
3957
        let mut testArena244 = testArena();
3958
        let testStorage244: 'test244 = &mut testArena244 in {
3959
            let mut a = testResolver(testStorage244);
3960
            let result = try resolveBlockStr(&mut a, "let x: bool = true; not x;");
3961
            try expectNoErrors(&result);
3962
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3963
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3964
        }
3965
    } {
3966
        let mut testArena245 = testArena();
3967
        let testStorage245: 'test245 = &mut testArena245 in {
3968
            let mut a = testResolver(testStorage245);
3969
            let result = try resolveExprStr(&mut a, "not (true and false)");
3970
            try expectNoErrors(&result);
3971
            try expectType(&a, result.root, super::Type::Bool);
3972
        }
3973
    } {
3974
        let mut testArena246 = testArena();
3975
        let testStorage246: 'test246 = &mut testArena246 in {
3976
            let mut a = testResolver(testStorage246);
3977
            let result = try resolveProgramStr(&mut a, "not 42");
3978
            let err = try expectError(&result);
3979
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3980
        }
3981
    } {
3982
        let mut testArena247 = testArena();
3983
        let testStorage247: 'test247 = &mut testArena247 in {
3984
            let mut a = testResolver(testStorage247);
3985
            let result = try resolveBlockStr(&mut a, "let x: i32 = 5; not x;");
3986
            let err = try expectError(&result);
3987
            try expectTypeMismatch(err, super::Type::Bool, super::Type::I32);
3988
        }
3989
    }
3990
}
3991
3992
@test unsafe fn testResolveUnaryOpNeg() throws (testing::TestError) {
3993
    {
3994
        let mut testArena248 = testArena();
3995
        let testStorage248: 'test248 = &mut testArena248 in {
3996
            let mut a = testResolver(testStorage248);
3997
            let result = try resolveExprStr(&mut a, "-42");
3998
            try expectNoErrors(&result);
3999
            try expectType(&a, result.root, super::Type::Int);
4000
        }
4001
    } {
4002
        let mut testArena249 = testArena();
4003
        let testStorage249: 'test249 = &mut testArena249 in {
4004
            let mut a = testResolver(testStorage249);
4005
            let result = try resolveBlockStr(&mut a, "let x: i32 = 10; -x;");
4006
            try expectNoErrors(&result);
4007
            let stmt = try parser::tests::getBlockLastStmt(result.root);
4008
            try expectExprStmtType(&a, stmt, super::Type::I32);
4009
        }
4010
    } {
4011
        let mut testArena250 = testArena();
4012
        let testStorage250: 'test250 = &mut testArena250 in {
4013
            let mut a = testResolver(testStorage250);
4014
            let result = try resolveExprStr(&mut a, "-(5 + 3)");
4015
            try expectNoErrors(&result);
4016
            try expectType(&a, result.root, super::Type::Int);
4017
        }
4018
    } {
4019
        let mut testArena251 = testArena();
4020
        let testStorage251: 'test251 = &mut testArena251 in {
4021
            let mut a = testResolver(testStorage251);
4022
            let result = try resolveBlockStr(&mut a, "let x: i8 = 5; -x;");
4023
            try expectNoErrors(&result);
4024
            let stmt = try parser::tests::getBlockLastStmt(result.root);
4025
            try expectExprStmtType(&a, stmt, super::Type::I8);
4026
        }
4027
    } {
4028
        let mut testArena252 = testArena();
4029
        let testStorage252: 'test252 = &mut testArena252 in {
4030
            let mut a = testResolver(testStorage252);
4031
            let result = try resolveProgramStr(&mut a, "-true");
4032
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
4033
        }
4034
    } {
4035
        let mut testArena253 = testArena();
4036
        let testStorage253: 'test253 = &mut testArena253 in {
4037
            let mut a = testResolver(testStorage253);
4038
            let result = try resolveBlockStr(&mut a, "let x: bool = false; -x;");
4039
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
4040
        }
4041
    }
4042
}
4043
4044
@test unsafe fn testResolveUnaryOpBitNot() throws (testing::TestError) {
4045
    {
4046
        let mut testArena254 = testArena();
4047
        let testStorage254: 'test254 = &mut testArena254 in {
4048
            let mut a = testResolver(testStorage254);
4049
            let result = try resolveExprStr(&mut a, "~42");
4050
            try expectNoErrors(&result);
4051
            try expectType(&a, result.root, super::Type::Int);
4052
        }
4053
    } {
4054
        let mut testArena255 = testArena();
4055
        let testStorage255: 'test255 = &mut testArena255 in {
4056
            let mut a = testResolver(testStorage255);
4057
            let result = try resolveBlockStr(&mut a, "let x: u32 = 255; ~x;");
4058
            try expectNoErrors(&result);
4059
            let stmt = try parser::tests::getBlockLastStmt(result.root);
4060
            try expectExprStmtType(&a, stmt, super::Type::U32);
4061
        }
4062
    } {
4063
        let mut testArena256 = testArena();
4064
        let testStorage256: 'test256 = &mut testArena256 in {
4065
            let mut a = testResolver(testStorage256);
4066
            let result = try resolveExprStr(&mut a, "~(0xFF)");
4067
            try expectNoErrors(&result);
4068
            try expectType(&a, result.root, super::Type::Int);
4069
        }
4070
    } {
4071
        let mut testArena257 = testArena();
4072
        let testStorage257: 'test257 = &mut testArena257 in {
4073
            let mut a = testResolver(testStorage257);
4074
            let result = try resolveBlockStr(&mut a, "let x: i8 = 5; ~x;");
4075
            try expectNoErrors(&result);
4076
            let stmt = try parser::tests::getBlockLastStmt(result.root);
4077
            try expectExprStmtType(&a, stmt, super::Type::I8);
4078
        }
4079
    } {
4080
        let mut testArena258 = testArena();
4081
        let testStorage258: 'test258 = &mut testArena258 in {
4082
            let mut a = testResolver(testStorage258);
4083
            let result = try resolveProgramStr(&mut a, "~true");
4084
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
4085
        }
4086
    } {
4087
        let mut testArena259 = testArena();
4088
        let testStorage259: 'test259 = &mut testArena259 in {
4089
            let mut a = testResolver(testStorage259);
4090
            let result = try resolveBlockStr(&mut a, "let x: bool = false; ~x;");
4091
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
4092
        }
4093
    }
4094
}
4095
4096
@test unsafe fn testResolveUnaryOpNested() throws (testing::TestError) {
4097
    {
4098
        let mut testArena260 = testArena();
4099
        let testStorage260: 'test260 = &mut testArena260 in {
4100
            let mut a = testResolver(testStorage260);
4101
            let result = try resolveExprStr(&mut a, "not not true");
4102
            try expectNoErrors(&result);
4103
            try expectType(&a, result.root, super::Type::Bool);
4104
        }
4105
    } {
4106
        let mut testArena261 = testArena();
4107
        let testStorage261: 'test261 = &mut testArena261 in {
4108
            let mut a = testResolver(testStorage261);
4109
            let result = try resolveExprStr(&mut a, "--42");
4110
            try expectNoErrors(&result);
4111
            try expectType(&a, result.root, super::Type::Int);
4112
        }
4113
    } {
4114
        let mut testArena262 = testArena();
4115
        let testStorage262: 'test262 = &mut testArena262 in {
4116
            let mut a = testResolver(testStorage262);
4117
            let result = try resolveExprStr(&mut a, "~~0xFF");
4118
            try expectNoErrors(&result);
4119
            try expectType(&a, result.root, super::Type::Int);
4120
        }
4121
    } {
4122
        let mut testArena263 = testArena();
4123
        let testStorage263: 'test263 = &mut testArena263 in {
4124
            let mut a = testResolver(testStorage263);
4125
            let result = try resolveExprStr(&mut a, "-(~42)");
4126
            try expectNoErrors(&result);
4127
            try expectType(&a, result.root, super::Type::Int);
4128
        }
4129
    }
4130
}
4131
4132
// test fn testNormalPointerArithmetic() throws (testing::TestError) {
4133
//     mut a = testResolver();
4134
//     let result = try resolveProgramStr(&mut a, "fn test() { let ptr: *i32 = undefined; let x = ptr + 1; }");
4135
//     try expectNoErrors(&result);
4136
// }
4137
4138
// Dereference tests //////////////////////////////////////////////////////////
4139
4140
@test unsafe fn testResolveDeref() throws (testing::TestError) {
4141
    {
4142
        let mut testArena264 = testArena();
4143
        let testStorage264: 'test264 = &mut testArena264 in {
4144
            let mut a = testResolver(testStorage264);
4145
            let result = try resolveBlockStr(&mut a, "static x: i32 = 42; let ptr: *i32 = &x; *ptr;");
4146
            try expectNoErrors(&result);
4147
            let stmt = try parser::tests::getBlockLastStmt(result.root);
4148
            try expectExprStmtType(&a, stmt, super::Type::I32);
4149
        }
4150
    } {
4151
        let mut testArena265 = testArena();
4152
        let testStorage265: 'test265 = &mut testArena265 in {
4153
            let mut a = testResolver(testStorage265);
4154
            let result = try resolveExprStr(&mut a, "*42");
4155
            try expectErrorKind(&result, super::ErrorKind::ExpectedPointer);
4156
        }
4157
    } {
4158
        let mut testArena266 = testArena();
4159
        let testStorage266: 'test266 = &mut testArena266 in {
4160
            let mut a = testResolver(testStorage266);
4161
            let result = try resolveBlockStr(&mut a, "let x: i32 = 5; *x;");
4162
            try expectErrorKind(&result, super::ErrorKind::ExpectedPointer);
4163
        }
4164
    }
4165
}
4166
4167
@test unsafe fn testResolveAssignDeref() throws (testing::TestError) {
4168
    {
4169
        let mut testArena267 = testArena();
4170
        let testStorage267: 'test267 = &mut testArena267 in {
4171
            let mut a = testResolver(testStorage267);
4172
            let program = "static x: i32 = 0; let ptr: *mut i32 = &mut x; set *ptr = 42;";
4173
            let result = try resolveProgramStr(&mut a, program);
4174
            try expectNoErrors(&result);
4175
        }
4176
    } {
4177
        let mut testArena268 = testArena();
4178
        let testStorage268: 'test268 = &mut testArena268 in {
4179
            let mut a = testResolver(testStorage268);
4180
            let program = "static x: i32 = 0; let ptr: *i32 = &x; set *ptr = 42;";
4181
            let result = try resolveProgramStr(&mut a, program);
4182
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4183
        }
4184
    } {
4185
        let mut testArena269 = testArena();
4186
        let testStorage269: 'test269 = &mut testArena269 in {
4187
            let mut a = testResolver(testStorage269);
4188
            let program = "static x: i32 = 0; let mut ptr: *i32 = &x; set *ptr = 42;";
4189
            let result = try resolveProgramStr(&mut a, program);
4190
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4191
        }
4192
    } {
4193
        let mut testArena270 = testArena();
4194
        let testStorage270: 'test270 = &mut testArena270 in {
4195
            let mut a = testResolver(testStorage270);
4196
            let program = "static x: u8 = 0; let mut ptr: *mut u8 = &mut x; set *ptr = 255;";
4197
            let result = try resolveProgramStr(&mut a, program);
4198
            try expectNoErrors(&result);
4199
        }
4200
    }
4201
}
4202
4203
// Type inference tests ///////////////////////////////////////////////////////
4204
4205
@test unsafe fn testResolveBasicTypeInference() throws (testing::TestError) {
4206
    {
4207
        // Boolean literals are unambiguous.
4208
        let mut testArena271 = testArena();
4209
        let testStorage271: 'test271 = &mut testArena271 in {
4210
            let mut a = testResolver(testStorage271);
4211
            let result = try resolveProgramStr(&mut a, "let x = true; x;");
4212
            try expectNoErrors(&result);
4213
4214
            let xStmt = try parser::tests::getBlockLastStmt(result.root);
4215
            try expectExprStmtType(&a, xStmt, super::Type::Bool);
4216
        }
4217
    } {
4218
        // Integer literals are ambiguous.
4219
        let mut testArena272 = testArena();
4220
        let testStorage272: 'test272 = &mut testArena272 in {
4221
            let mut a = testResolver(testStorage272);
4222
            let result = try resolveProgramStr(&mut a, "let x = 34;");
4223
            try expectErrorKind(&result, super::ErrorKind::CannotInferType);
4224
        }
4225
    }
4226
}
4227
4228
// Union tests /////////////////////////////////////////////////////////////////
4229
4230
@test unsafe fn testResolveUnionVariantWithoutPayload() throws (testing::TestError) {
4231
    let mut testArena273 = testArena();
4232
    let testStorage273: 'test273 = &mut testArena273 in {
4233
        let mut a = testResolver(testStorage273);
4234
        let program = "union Status { Ok, Error } Status::Ok;";
4235
        let result = try resolveProgramStr(&mut a, program);
4236
4237
        let ty = try getTypeInScopeOf(&a, result.root, "Status");
4238
        let case super::NominalType::Union(unionType) = *ty
4239
            else throw testing::TestError::Failed;
4240
        try testing::expect(unionType.variants.len == 2);
4241
        try testing::expect(mem::eq(unionType.variants[0].name, "Ok"));
4242
        try testing::expect(mem::eq(unionType.variants[1].name, "Error"));
4243
        if getUnionVariantPayload(ty, "Ok") <> super::Type::Void {
4244
            throw testing::TestError::Failed;
4245
        }
4246
        let stmt = try getBlockStmt(result.root, 1);
4247
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4248
        try expectNoErrors(&result);
4249
    }
4250
}
4251
4252
@test unsafe fn testResolveUnionVariantWithPayload() throws (testing::TestError) {
4253
    let mut testArena274 = testArena();
4254
    let testStorage274: 'test274 = &mut testArena274 in {
4255
        let mut a = testResolver(testStorage274);
4256
        let program = "union R { Ok(i32), Err(bool) } R::Ok(42);";
4257
        let result = try resolveProgramStr(&mut a, program);
4258
        try expectNoErrors(&result);
4259
4260
        let ty = try getTypeInScopeOf(&a, result.root, "R");
4261
4262
        let okPayload = getUnionVariantPayload(ty, "Ok");
4263
        try testing::expect(okPayload == super::Type::I32);
4264
4265
        let errPayload = getUnionVariantPayload(ty, "Err");
4266
        try testing::expect(errPayload == super::Type::Bool);
4267
4268
        let stmt = try getBlockStmt(result.root, 1);
4269
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4270
4271
        // TODO: Test payload type.
4272
    }
4273
}
4274
4275
@test unsafe fn testResolveUnionVariantWithoutPayloadExplicitDiscriminant() throws (testing::TestError) {
4276
    let mut testArena275 = testArena();
4277
    let testStorage275: 'test275 = &mut testArena275 in {
4278
        let mut a = testResolver(testStorage275);
4279
        let program = "union R { Ok = 7, Err = 11 } R::Ok;";
4280
        let result = try resolveProgramStr(&mut a, program);
4281
        try expectNoErrors(&result);
4282
4283
        let ty = try getTypeInScopeOf(&a, result.root, "R");
4284
        let stmt = try getBlockStmt(result.root, 1);
4285
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4286
    }
4287
}
4288
4289
@test unsafe fn testResolveUnionVariantPayloadTypeMismatch() throws (testing::TestError) {
4290
    let mut testArena276 = testArena();
4291
    let testStorage276: 'test276 = &mut testArena276 in {
4292
        let mut a = testResolver(testStorage276);
4293
        let program = "union R { Ok(i32), Error(bool) } R::Ok(true);";
4294
        let result = try resolveProgramStr(&mut a, program);
4295
        let err = try expectError(&result);
4296
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
4297
4298
        let ty = try getTypeInScopeOf(&a, result.root, "R");
4299
        let payload = getUnionVariantPayload(ty, "Ok");
4300
        try testing::expect(payload == super::Type::I32);
4301
4302
        let errNode = err.node
4303
            else throw testing::TestError::Failed;
4304
        let case ast::NodeValue::Bool(_) = errNode.value
4305
            else throw testing::TestError::Failed;
4306
    }
4307
}
4308
4309
@test unsafe fn testResolveUnionVariantUnexpectedPayload() throws (testing::TestError) {
4310
    let mut testArena277 = testArena();
4311
    let testStorage277: 'test277 = &mut testArena277 in {
4312
        let mut a = testResolver(testStorage277);
4313
        let program = "union Status { Ok, Error } Status::Ok(42);";
4314
        let result = try resolveProgramStr(&mut a, program);
4315
        let err = try expectError(&result);
4316
4317
        let case super::ErrorKind::UnionVariantPayloadUnexpected(_) = err.kind
4318
            else throw testing::TestError::Failed;
4319
        let node = err.node
4320
            else throw testing::TestError::Failed;
4321
        let case ast::NodeValue::Call(_) = node.value
4322
            else throw testing::TestError::Failed;
4323
    }
4324
}
4325
4326
@test unsafe fn testResolveUnionVariantUnknown() throws (testing::TestError) {
4327
    let mut testArena278 = testArena();
4328
    let testStorage278: 'test278 = &mut testArena278 in {
4329
        let mut a = testResolver(testStorage278);
4330
        let program = "union Status { Ok, Error } Status::Unknown;";
4331
        let result = try resolveProgramStr(&mut a, program);
4332
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
4333
    }
4334
}
4335
4336
@test unsafe fn testResolveScopeAccessUndefinedType() throws (testing::TestError) {
4337
    let mut testArena279 = testArena();
4338
    let testStorage279: 'test279 = &mut testArena279 in {
4339
        let mut a = testResolver(testStorage279);
4340
        let result = try resolveProgramStr(&mut a, "Unknown::X;");
4341
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
4342
    }
4343
}
4344
4345
@test unsafe fn testResolveUnionVariantVoidPayload() throws (testing::TestError) {
4346
    let mut testArena280 = testArena();
4347
    let testStorage280: 'test280 = &mut testArena280 in {
4348
        let mut a = testResolver(testStorage280);
4349
        let program = "union R { Success(i32), Pending } R::Pending;";
4350
        let result = try resolveProgramStr(&mut a, program);
4351
        try expectNoErrors(&result);
4352
4353
        let ty = try getTypeInScopeOf(&a, result.root, "R");
4354
        let payload = getUnionVariantPayload(ty, "Pending");
4355
        try testing::expect(payload == super::Type::Void);
4356
4357
        let stmt = try getBlockStmt(result.root, 1);
4358
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4359
    }
4360
}
4361
4362
@test unsafe fn testResolveUnionVariantRecordPayload() throws (testing::TestError) {
4363
    let mut testArena281 = testArena();
4364
    let testStorage281: 'test281 = &mut testArena281 in {
4365
        let mut a = testResolver(testStorage281);
4366
        let program = "record P { x: i32, y: i32 } union S { Point(P), Num(u32) } S::Point(P { x: 10, y: 20 });";
4367
        let result = try resolveProgramStr(&mut a, program);
4368
        try expectNoErrors(&result);
4369
4370
        let ty = try getTypeInScopeOf(&a, result.root, "S");
4371
        let stmt = try getBlockStmt(result.root, 2);
4372
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4373
    }
4374
}
4375
4376
@test unsafe fn testResolveBuiltinSizeOf() throws (testing::TestError) {
4377
    try resolveAndExpectConstExpr("@sizeOf(u8)", 1);
4378
    try resolveAndExpectConstExpr("@sizeOf(u16)", 2);
4379
    try resolveAndExpectConstExpr("@sizeOf(u32)", 4);
4380
    try resolveAndExpectConstExpr("@sizeOf(i32)", 4);
4381
    try resolveAndExpectConstExpr("@sizeOf(bool)", 1);
4382
    try resolveAndExpectConstExpr("@sizeOf(*u32)", 8);
4383
    try resolveAndExpectConstExpr("@sizeOf([u8; 10])", 10);
4384
    try resolveAndExpectConstExpr("@sizeOf(*[u32])", 16);
4385
    try resolveAndExpectConstExpr("@sizeOf(?u8)", 2);
4386
    try resolveAndExpectConstExpr("@sizeOf(?u16)", 4);
4387
    try resolveAndExpectConstExpr("@sizeOf(?u32)", 8);
4388
    try resolveAndExpectConstExpr("@sizeOf(*opaque)", 8);
4389
    try resolveAndExpectConstStmt("record T { x: u8 } @sizeOf(T);", 1);
4390
    try resolveAndExpectConstStmt("record T { x: i32 } @sizeOf(T);", 4);
4391
    try resolveAndExpectConstStmt("record T { x: i32, y: i8 } @sizeOf(T);", 8);
4392
    try resolveAndExpectConstStmt("record T { x: i8, y: i32 } @sizeOf(T);", 8);
4393
    try resolveAndExpectConstStmt("record T { x: i8, y: i32 } @sizeOf(T);", 8);
4394
    try resolveAndExpectConstStmt("record T { x: u32, y: u8, z: u8 }; @sizeOf(T);", 8);
4395
    try resolveAndExpectConstStmt("record T { x: u8, y: u32, z: u8 }; @sizeOf(T);", 12);
4396
    try resolveAndExpectConstStmt("union T { A, B, C }; @sizeOf(T);", 1);
4397
    try resolveAndExpectConstStmt("union T { A, B(u32), C }; @sizeOf(T);", 8);
4398
    try resolveAndExpectConstStmt("union T { A, B(u16), C }; @sizeOf(T);", 4);
4399
    try resolveAndExpectConstStmt("union T { A(u32), B(u16), C(u16) }; @sizeOf(T);", 8);
4400
    try resolveAndExpectConstStmt("union T { A(u32), B(u16), C([u8; 16]) }; @sizeOf(T);", 20);
4401
}
4402
4403
@test unsafe fn testResolveBuiltinAlignOf() throws (testing::TestError) {
4404
    try resolveAndExpectConstExpr("@alignOf(u8)", 1);
4405
    try resolveAndExpectConstExpr("@alignOf(u16)", 2);
4406
    try resolveAndExpectConstExpr("@alignOf(u32)", 4);
4407
    try resolveAndExpectConstExpr("@alignOf(i32)", 4);
4408
    try resolveAndExpectConstExpr("@alignOf(bool)", 1);
4409
    try resolveAndExpectConstExpr("@alignOf(*u8)", 8);
4410
    try resolveAndExpectConstExpr("@alignOf(*u16)", 8);
4411
    try resolveAndExpectConstExpr("@alignOf(*u32)", 8);
4412
    try resolveAndExpectConstExpr("@alignOf(*opaque)", 8);
4413
    try resolveAndExpectConstExpr("@alignOf([u8; 8])", 1);
4414
    try resolveAndExpectConstExpr("@alignOf([u16; 8])", 2);
4415
    try resolveAndExpectConstExpr("@alignOf([u32; 8])", 4);
4416
    try resolveAndExpectConstExpr("@alignOf(*[u32])", 8);
4417
    try resolveAndExpectConstExpr("@alignOf(?u8)", 1);
4418
    try resolveAndExpectConstExpr("@alignOf(?u16)", 2);
4419
    try resolveAndExpectConstExpr("@alignOf(?u32)", 4);
4420
    try resolveAndExpectConstStmt("record T { x: u8, y: u16 }; @alignOf(T);", 2);
4421
    try resolveAndExpectConstStmt("record T { x: u8, y: u32, z: u8 }; @alignOf(T);", 4);
4422
    try resolveAndExpectConstStmt("record T { x: u32, y: u8, z: u8 }; @alignOf(T);", 4);
4423
    try resolveAndExpectConstStmt("union T { A, B, C }; @alignOf(T);", 1);
4424
    try resolveAndExpectConstStmt("union T { A, B(u32), C }; @alignOf(T);", 4);
4425
}
4426
4427
@test unsafe fn testResolveBuiltinSizeOfRecord() throws (testing::TestError) {
4428
    let mut testArena282 = testArena();
4429
    let testStorage282: 'test282 = &mut testArena282 in {
4430
        let mut a = testResolver(testStorage282);
4431
        let program = "record T { x: u8, y: u32 } @sizeOf(T);";
4432
        let result = try resolveProgramStr(&mut a, program);
4433
        try expectNoErrors(&result);
4434
4435
        let stmt = try getBlockStmt(result.root, 1);
4436
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
4437
        try expectConstInt(&a, expr, 8);
4438
    }
4439
}
4440
4441
@test unsafe fn testResolveBuiltinSizeOfUnion() throws (testing::TestError) {
4442
    let mut testArena283 = testArena();
4443
    let testStorage283: 'test283 = &mut testArena283 in {
4444
        let mut a = testResolver(testStorage283);
4445
        let program = "union Result { Ok(u32), Err(u8) } @sizeOf(Result);";
4446
        let result = try resolveProgramStr(&mut a, program);
4447
        try expectNoErrors(&result);
4448
4449
        let stmt = try getBlockStmt(result.root, 1);
4450
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
4451
        try expectConstInt(&a, expr, 8);
4452
    }
4453
}
4454
4455
@test unsafe fn testResolveAlignAnnotation() throws (testing::TestError) {
4456
    {
4457
        let mut testArena284 = testArena();
4458
        let testStorage284: 'test284 = &mut testArena284 in {
4459
            let mut a = testResolver(testStorage284);
4460
            let result = try resolveBlockStr(&mut a, "let x: u8 align(8) = 0;");
4461
            try expectNoErrors(&result);
4462
4463
            let stmt = try getBlockStmt(result.root, 0);
4464
            let sym = super::symbolFor(&a, stmt)
4465
                else throw testing::TestError::Failed;
4466
            let case super::SymbolData::Value { type: valType, .. } = sym.data
4467
                else throw testing::TestError::Failed;
4468
            let layout = super::getLayout(&a, sym.node, valType);
4469
            try testing::expect(layout.alignment == 8);
4470
        }
4471
    } {
4472
        let mut testArena285 = testArena();
4473
        let testStorage285: 'test285 = &mut testArena285 in {
4474
            let mut a = testResolver(testStorage285);
4475
            let result = try resolveProgramStr(&mut a, "let x: u32 align(3) = 0;");
4476
            let err = try expectError(&result);
4477
            let case super::ErrorKind::InvalidAlignmentValue(val) = err.kind
4478
                else throw testing::TestError::Failed;
4479
            try testing::expect(val == 3);
4480
        }
4481
    } {
4482
        let mut testArena286 = testArena();
4483
        let testStorage286: 'test286 = &mut testArena286 in {
4484
            let mut a = testResolver(testStorage286);
4485
            let result = try resolveProgramStr(&mut a, "let x: u32 align(7) = 0;");
4486
            let err = try expectError(&result);
4487
            let case super::ErrorKind::InvalidAlignmentValue(val) = err.kind
4488
                else throw testing::TestError::Failed;
4489
            try testing::expect(val == 7);
4490
        }
4491
    }
4492
}
4493
4494
@test unsafe fn testResolveVoidAssignmentError() throws (testing::TestError) {
4495
    {
4496
        let mut testArena287 = testArena();
4497
        let testStorage287: 'test287 = &mut testArena287 in {
4498
            let mut a = testResolver(testStorage287);
4499
            let program = "fn voidFn() {} let _ = voidFn();";
4500
            let result = try resolveProgramStr(&mut a, program);
4501
            try expectErrorKind(&result, super::ErrorKind::CannotAssignVoid);
4502
        }
4503
    } {
4504
        let mut testArena288 = testArena();
4505
        let testStorage288: 'test288 = &mut testArena288 in {
4506
            let mut a = testResolver(testStorage288);
4507
            let program = "fn voidFn() {} let x = voidFn();";
4508
            let result = try resolveProgramStr(&mut a, program);
4509
            try expectErrorKind(&result, super::ErrorKind::CannotAssignVoid);
4510
        }
4511
    }
4512
}
4513
4514
//
4515
// Module Declaration Tests
4516
//
4517
4518
@test unsafe fn testResolveEmptyMod() throws (testing::TestError) {
4519
    let mut testArena289 = testArena();
4520
    let testStorage289: 'test289 = &mut testArena289 in {
4521
        let mut a = testResolver(testStorage289);
4522
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4523
        let mut graph = &mut MODULE_GRAPH;
4524
4525
        let rootId = try registerModule(graph, nil, "root", "mod child;", &mut arena);
4526
        let childId = try registerModule(graph, rootId, "child", "{}", &mut arena);
4527
        let result = try resolveModuleTree(&mut a, rootId);
4528
        try expectNoErrors(&result);
4529
    }
4530
}
4531
4532
@test unsafe fn testResolveModuleCannotAccessParentScope() throws (testing::TestError) {
4533
    let mut testArena290 = testArena();
4534
    let testStorage290: 'test290 = &mut testArena290 in {
4535
        let mut a = testResolver(testStorage290);
4536
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4537
4538
        // Register root and util modules.
4539
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod util; export fn helper() {}", &mut arena);
4540
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "fn main() { helper(); }", &mut arena);
4541
4542
        // Resolve should fail: the parent module is not in scope.
4543
        let result = try resolveModuleTree(&mut a, rootId);
4544
        let err = try expectError(&result);
4545
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4546
            else throw testing::TestError::Failed;
4547
        try testing::expect(mem::eq(name, "helper"));
4548
    }
4549
}
4550
4551
@test unsafe fn testResolveModuleAccessPrivateSubModule() throws (testing::TestError) {
4552
    let mut testArena291 = testArena();
4553
    let testStorage291: 'test291 = &mut testArena291 in {
4554
        let mut a = testResolver(testStorage291);
4555
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4556
4557
        // Register root and util modules.
4558
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod util; fn main() { util::helper(); }", &mut arena);
4559
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "export fn helper() {}", &mut arena);
4560
4561
        // Resolve should succeed: parent can access child.
4562
        let result = try resolveModuleTree(&mut a, rootId);
4563
        try expectNoErrors(&result);
4564
    }
4565
}
4566
4567
@test unsafe fn testResolveSiblingModulesCannotAccessDirectly() throws (testing::TestError) {
4568
    let mut testArena292 = testArena();
4569
    let testStorage292: 'test292 = &mut testArena292 in {
4570
        let mut a = testResolver(testStorage292);
4571
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4572
4573
        // Register root with two sibling modules.
4574
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod paul; export mod patrick;", &mut arena);
4575
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "paul", "fn main() { patrick::helper(); }", &mut arena);
4576
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "patrick", "export fn helper() -> i32 { return 42; }", &mut arena);
4577
4578
        // Resolve should fail: siblings can't access each other directly.
4579
        let result = try resolveModuleTree(&mut a, rootId);
4580
        let err = try expectError(&result);
4581
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4582
            else throw testing::TestError::Failed;
4583
        try testing::expect(mem::eq(name, "patrick"));
4584
    }
4585
}
4586
4587
@test unsafe fn testResolveSiblingModulesViaRoot() throws (testing::TestError) {
4588
    let mut testArena293 = testArena();
4589
    let testStorage293: 'test293 = &mut testArena293 in {
4590
        let mut a = testResolver(testStorage293);
4591
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4592
4593
        // Register root with two sibling modules.
4594
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod paul; export mod patrick;", &mut arena);
4595
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "paul", "use root::patrick; fn main() -> i32 { return patrick::helper(); }", &mut arena);
4596
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "patrick", "export fn helper() -> i32 { return 42; }", &mut arena);
4597
4598
        // Resolve should succeed: siblings can access each other via root.
4599
        let result = try resolveModuleTree(&mut a, rootId);
4600
        try expectNoErrors(&result);
4601
    }
4602
}
4603
4604
@test unsafe fn testResolveModuleMutualRecursion() throws (testing::TestError) {
4605
    let mut testArena294 = testArena();
4606
    let testStorage294: 'test294 = &mut testArena294 in {
4607
        let mut a = testResolver(testStorage294);
4608
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4609
4610
        // Register root with two sibling modules that call each other.
4611
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod left; export mod right;", &mut arena);
4612
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "left", "use root::right; export fn leftHelper() -> i32 { return right::rightHelper(); }", &mut arena);
4613
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "right", "use root::left; export fn rightHelper() -> i32 { return left::leftHelper(); }", &mut arena);
4614
4615
        // Resolve should succeed: cyclic use is allowed.
4616
        let result = try resolveModuleTree(&mut a, rootId);
4617
        try expectNoErrors(&result);
4618
    }
4619
}
4620
4621
@test unsafe fn testResolveAccessModuleType() throws (testing::TestError) {
4622
    let mut testArena295 = testArena();
4623
    let testStorage295: 'test295 = &mut testArena295 in {
4624
        let mut a = testResolver(testStorage295);
4625
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4626
4627
        // Register root with types module containing a record.
4628
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4629
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Point { x: i32, y: i32 }", &mut arena);
4630
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> i32 { let p = types::Point { x: 1, y: 2 }; return p.x; }", &mut arena);
4631
4632
        // Resolve should succeed: types can be accessed.
4633
        let result = try resolveModuleTree(&mut a, rootId);
4634
        try expectNoErrors(&result);
4635
    }
4636
}
4637
4638
@test unsafe fn testResolveAccessModuleConstant() throws (testing::TestError) {
4639
    let mut testArena296 = testArena();
4640
    let testStorage296: 'test296 = &mut testArena296 in {
4641
        let mut a = testResolver(testStorage296);
4642
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4643
4644
        // Register root with constants module.
4645
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
4646
        let constantsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant MAX_SIZE: i32 = 100;", &mut arena);
4647
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() -> i32 { return consts::MAX_SIZE; }", &mut arena);
4648
4649
        // Resolve should succeed: constants can be accessed.
4650
        let result = try resolveModuleTree(&mut a, rootId);
4651
        try expectNoErrors(&result);
4652
    }
4653
}
4654
4655
@test unsafe fn testResolveRootSymbolMustBeImported() throws (testing::TestError) {
4656
    let mut testArena297 = testArena();
4657
    let testStorage297: 'test297 = &mut testArena297 in {
4658
        let mut a = testResolver(testStorage297);
4659
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4660
4661
        // Register deeply nested modules: `root::app::services::auth`.
4662
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; export fn helper() -> i32 { return 42; }", &mut arena);
4663
        let mainId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "fn run() -> i32 { return root::helper(); }", &mut arena);
4664
4665
        // Resolve should fail: the `root` module must be imported.
4666
        let result = try resolveModuleTree(&mut a, rootId);
4667
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("root"));
4668
    }
4669
}
4670
4671
@test unsafe fn testResolveUseImportsNestedSymbol() throws (testing::TestError) {
4672
    let mut testArena298 = testArena();
4673
    let testStorage298: 'test298 = &mut testArena298 in {
4674
        let mut a = testResolver(testStorage298);
4675
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4676
4677
        // Register deeply nested modules: `root::app::services::auth`.
4678
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod app; mod main;", &mut arena);
4679
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "export mod services;", &mut arena);
4680
        let servicesId = try registerModule(&mut MODULE_GRAPH, appId, "services", "export mod auth;", &mut arena);
4681
        let authId = try registerModule(&mut MODULE_GRAPH, servicesId, "auth", "export fn login() -> i32 { return 1; }", &mut arena);
4682
        let mainId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::app::services::auth; fn run() -> i32 { return auth::login(); }", &mut arena);
4683
        let otherId = try registerModule(&mut MODULE_GRAPH, rootId, "other", "use root; fn run() -> i32 { return root::app::services::auth::login(); }", &mut arena);
4684
4685
        // Resolve should succeed: use imports the module symbol.
4686
        let result = try resolveModuleTree(&mut a, rootId);
4687
        try expectNoErrors(&result);
4688
    }
4689
}
4690
4691
@test unsafe fn testResolveUseNonExistentModule() throws (testing::TestError) {
4692
    let mut testArena299 = testArena();
4693
    let testStorage299: 'test299 = &mut testArena299 in {
4694
        let mut a = testResolver(testStorage299);
4695
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4696
4697
        // Register root with app trying to use a non-existent module.
4698
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod app;", &mut arena);
4699
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::unknown;", &mut arena);
4700
4701
        // Resolve should fail: module doesn't exist.
4702
        let result = try resolveModuleTree(&mut a, rootId);
4703
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("unknown"));
4704
    }
4705
}
4706
4707
@test unsafe fn testResolveUsePrivateFn() throws (testing::TestError) {
4708
    let mut testArena300 = testArena();
4709
    let testStorage300: 'test300 = &mut testArena300 in {
4710
        let mut a = testResolver(testStorage300);
4711
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4712
4713
        // Register root with util module containing a private function.
4714
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod util; mod app;", &mut arena);
4715
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "fn private() -> i32 { return 42; }", &mut arena);
4716
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::util; fn main() -> i32 { return util::private(); }", &mut arena);
4717
4718
        // Resolve should fail: function is not public.
4719
        let result = try resolveModuleTree(&mut a, rootId);
4720
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
4721
    }
4722
}
4723
4724
@test unsafe fn testResolveUsePrivateMod() throws (testing::TestError) {
4725
    let mut testArena301 = testArena();
4726
    let testStorage301: 'test301 = &mut testArena301 in {
4727
        let mut a = testResolver(testStorage301);
4728
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4729
4730
        // Register root with public and private child modules.
4731
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; mod private;", &mut arena);
4732
        let privateId = try registerModule(&mut MODULE_GRAPH, rootId, "private", "{}", &mut arena);
4733
        let publicId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::private;", &mut arena);
4734
4735
        // Resolve should fail: module is not public.
4736
        let result = try resolveModuleTree(&mut a, rootId);
4737
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
4738
    }
4739
}
4740
4741
@test unsafe fn testResolveUsePublicMod() throws (testing::TestError) {
4742
    let mut testArena302 = testArena();
4743
    let testStorage302: 'test302 = &mut testArena302 in {
4744
        let mut a = testResolver(testStorage302);
4745
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4746
4747
        // Register root with public and private child modules.
4748
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; export mod public;", &mut arena);
4749
        let privateId = try registerModule(&mut MODULE_GRAPH, rootId, "public", "{}", &mut arena);
4750
        let publicId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::public;", &mut arena);
4751
4752
        // Resolve should succeed: module is public.
4753
        let result = try resolveModuleTree(&mut a, rootId);
4754
        try expectNoErrors(&result);
4755
    }
4756
}
4757
4758
@test unsafe fn testResolveUseNonPublicType() throws (testing::TestError) {
4759
    let mut testArena303 = testArena();
4760
    let testStorage303: 'test303 = &mut testArena303 in {
4761
        let mut a = testResolver(testStorage303);
4762
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4763
4764
        // Register root with types module containing a private record.
4765
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4766
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "record Priv { x: i32 }", &mut arena);
4767
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> types::Priv { return types::Priv { x: 1 }; }", &mut arena);
4768
4769
        // Resolve should fail: record is not public.
4770
        let result = try resolveModuleTree(&mut a, rootId);
4771
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Priv"));
4772
    }
4773
}
4774
4775
@test unsafe fn testResolveImportPublicType() throws (testing::TestError) {
4776
    let mut testArena304 = testArena();
4777
    let testStorage304: 'test304 = &mut testArena304 in {
4778
        let mut a = testResolver(testStorage304);
4779
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4780
4781
        // Register root with types module containing a public record.
4782
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4783
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Pub { x: i32 }", &mut arena);
4784
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> types::Pub { return types::Pub { x: 1 }; }", &mut arena);
4785
4786
        // Resolve should succeed: record is public.
4787
        let result = try resolveModuleTree(&mut a, rootId);
4788
        try expectNoErrors(&result);
4789
    }
4790
}
4791
4792
@test unsafe fn testResolveUseNonPublicStatic() throws (testing::TestError) {
4793
    let mut testArena305 = testArena();
4794
    let testStorage305: 'test305 = &mut testArena305 in {
4795
        let mut a = testResolver(testStorage305);
4796
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4797
4798
        // Register root with statics module containing a private static.
4799
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
4800
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "static PRIVATE: i32 = 42;", &mut arena);
4801
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() -> i32 { return statics::PRIVATE; }", &mut arena);
4802
4803
        // Resolve should fail: static is not public.
4804
        let result = try resolveModuleTree(&mut a, rootId);
4805
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("PRIVATE"));
4806
    }
4807
}
4808
4809
@test unsafe fn testResolveImportPublicStatic() throws (testing::TestError) {
4810
    let mut testArena306 = testArena();
4811
    let testStorage306: 'test306 = &mut testArena306 in {
4812
        let mut a = testResolver(testStorage306);
4813
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4814
4815
        // Register root with statics module containing a public static.
4816
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
4817
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "export static PUBLIC: i32 = 42;", &mut arena);
4818
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() -> i32 { return statics::PUBLIC; }", &mut arena);
4819
4820
        // Resolve should succeed: static is public.
4821
        let result = try resolveModuleTree(&mut a, rootId);
4822
        try expectNoErrors(&result);
4823
    }
4824
}
4825
4826
@test unsafe fn testResolveAccessSuper() throws (testing::TestError) {
4827
    {
4828
        let mut testArena307 = testArena();
4829
        let testStorage307: 'test307 = &mut testArena307 in {
4830
            let mut a = testResolver(testStorage307);
4831
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4832
4833
            // Test function access.
4834
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; export fn parentFn() -> i32 { return 42; }", &mut arena);
4835
            let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "fn main() -> i32 { return super::parentFn(); }", &mut arena);
4836
            let result = try resolveModuleTree(&mut a, rootId);
4837
            try expectNoErrors(&result);
4838
        }
4839
    } {
4840
        let mut testArena308 = testArena();
4841
        let testStorage308: 'test308 = &mut testArena308 in {
4842
            let mut a = testResolver(testStorage308);
4843
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4844
4845
            // Test type access.
4846
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; export record Point { x: i32, y: i32 }", &mut arena);
4847
            let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "fn make() -> super::Point { return super::Point { x: 1, y: 2 }; }", &mut arena);
4848
            let result = try resolveModuleTree(&mut a, rootId);
4849
            try expectNoErrors(&result);
4850
        }
4851
    }
4852
}
4853
4854
/// Test nested super access to union variants (e.g. `super::E::A`).
4855
@test unsafe fn testResolveSuperUnionVariant() throws (testing::TestError) {
4856
    let mut testArena309 = testArena();
4857
    let testStorage309: 'test309 = &mut testArena309 in {
4858
        let mut a = testResolver(testStorage309);
4859
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4860
4861
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod c; export union E { A, B }", &mut arena);
4862
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "c",
4863
            "fn f(x: super::E) { match x { case super::E::A => {}, case super::E::B => {} } }",
4864
            &mut arena);
4865
        let result = try resolveModuleTree(&mut a, rootId);
4866
        try expectNoErrors(&result);
4867
    }
4868
}
4869
4870
@test unsafe fn testResolveUseSuper() throws (testing::TestError) {
4871
    let mut testArena310 = testArena();
4872
    let testStorage310: 'test310 = &mut testArena310 in {
4873
        let mut a = testResolver(testStorage310);
4874
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4875
4876
        // Register root with a function, and a child module that uses super to access it.
4877
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod joe; export mod kate;", &mut arena);
4878
        let kateId = try registerModule(&mut MODULE_GRAPH, rootId, "kate", "export fn run() {}", &mut arena);
4879
        let joeId = try registerModule(&mut MODULE_GRAPH, rootId, "joe", "use super::kate; fn main() { kate::run(); }", &mut arena);
4880
4881
        // Resolve should succeed - super allows accessing parent module.
4882
        let result = try resolveModuleTree(&mut a, rootId);
4883
        try expectNoErrors(&result);
4884
    }
4885
}
4886
4887
@test unsafe fn testResolveModNotFound() throws (testing::TestError) {
4888
    let mut testArena311 = testArena();
4889
    let testStorage311: 'test311 = &mut testArena311 in {
4890
        let mut a = testResolver(testStorage311);
4891
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4892
4893
        // Register root that declares a module that doesn't exist.
4894
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod unknown;", &mut arena);
4895
4896
        // Resolve should fail: module doesn't exist.
4897
        let result = try resolveModuleTree(&mut a, rootId);
4898
        let err = try expectError(&result);
4899
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4900
            else throw testing::TestError::Failed;
4901
        try testing::expect(mem::eq(name, "unknown"));
4902
    }
4903
}
4904
4905
@test unsafe fn testResolveDuplicateSubModule() throws (testing::TestError) {
4906
    let mut testArena312 = testArena();
4907
    let testStorage312: 'test312 = &mut testArena312 in {
4908
        let mut a = testResolver(testStorage312);
4909
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4910
4911
        // Register root that declares a module twice.
4912
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; mod child;", &mut arena);
4913
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "{}", &mut arena);
4914
4915
        // Resolve should fail: can't declare the same module twice.
4916
        let result = try resolveModuleTree(&mut a, rootId);
4917
        let err = try expectError(&result);
4918
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("child"));
4919
    }
4920
}
4921
4922
@test unsafe fn testResolveUseSubModule() throws (testing::TestError) {
4923
    let mut testArena313 = testArena();
4924
    let testStorage313: 'test313 = &mut testArena313 in {
4925
        let mut a = testResolver(testStorage313);
4926
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4927
4928
        // Register root that declares and imports the same module.
4929
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; use child;", &mut arena);
4930
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "{}", &mut arena);
4931
4932
        // Resolve should fail: Both `mod` and `use` are trying to create the same binding.
4933
        let result = try resolveModuleTree(&mut a, rootId);
4934
        let err = try expectError(&result);
4935
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("child"));
4936
    }
4937
}
4938
4939
@test unsafe fn testResolveDuplicateUse() throws (testing::TestError) {
4940
    let mut testArena314 = testArena();
4941
    let testStorage314: 'test314 = &mut testArena314 in {
4942
        let mut a = testResolver(testStorage314);
4943
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4944
4945
        // Register a module that imports the same module twice.
4946
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child", &mut arena);
4947
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "use root; use root;", &mut arena);
4948
4949
        // Resolve should fail.
4950
        let result = try resolveModuleTree(&mut a, rootId);
4951
        let err = try expectError(&result);
4952
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("root"));
4953
    }
4954
}
4955
4956
/// Test that opaque pointers are allowed in record fields.
4957
@test unsafe fn testOpaquePointerInRecordField() throws (testing::TestError) {
4958
    let mut testArena315 = testArena();
4959
    let testStorage315: 'test315 = &mut testArena315 in {
4960
        let mut a = testResolver(testStorage315);
4961
        let result = try resolveProgramStr(&mut a, "record T { x: *opaque }");
4962
        try expectNoErrors(&result);
4963
    }
4964
}
4965
4966
/// You cannot use `@sizeOf` or `@alignOf` on opaque type.
4967
@test unsafe fn testOpaqueTypeNoSizeOfAlignOf() throws (testing::TestError) {
4968
    let mut testArena316 = testArena();
4969
    let testStorage316: 'test316 = &mut testArena316 in {
4970
        let mut a = testResolver(testStorage316);
4971
4972
        let result1 = try resolveExprStr(&mut a, "@sizeOf(opaque)");
4973
        let err1 = try expectError(&result1);
4974
        try expectErrorKind(&result1, super::ErrorKind::OpaqueTypeNotAllowed);
4975
4976
        let result2 = try resolveExprStr(&mut a, "@alignOf(opaque)");
4977
        let err2 = try expectError(&result2);
4978
        try expectErrorKind(&result2, super::ErrorKind::OpaqueTypeNotAllowed);
4979
    }
4980
}
4981
4982
/// Test that immutable slice/pointer parameters cannot be borrowed mutably.
4983
@test unsafe fn testMutableBorrowFromImmutablePointer() throws (testing::TestError) {
4984
    let mut testArena317 = testArena();
4985
    let testStorage317: 'test317 = &mut testArena317 in {
4986
        let mut a = testResolver(testStorage317);
4987
        let program = "fn f(p: *i32) { let x = &mut *p; }";
4988
        let result = try resolveProgramStr(&mut a, program);
4989
        let err = try expectError(&result);
4990
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4991
    }
4992
}
4993
4994
/// Test that immutable slice parameters cannot be borrowed mutably.
4995
@test unsafe fn testMutableBorrowFromImmutableSlice() throws (testing::TestError) {
4996
    let mut testArena318 = testArena();
4997
    let testStorage318: 'test318 = &mut testArena318 in {
4998
        let mut a = testResolver(testStorage318);
4999
        let program = "fn f(s: *[i32]) { let x: *mut i32 = &mut s[0]; }";
5000
        let result = try resolveProgramStr(&mut a, program);
5001
        let err = try expectError(&result);
5002
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5003
    }
5004
}
5005
5006
/// Test that mutable pointer parameters can be borrowed mutably.
5007
@test unsafe fn testMutableBorrowFromMutablePointer() throws (testing::TestError) {
5008
    let mut testArena319 = testArena();
5009
    let testStorage319: 'test319 = &mut testArena319 in {
5010
        let mut a = testResolver(testStorage319);
5011
        let program = "fn f(p: *mut i32) { let x: *mut i32 = &mut *p; }";
5012
        let result = try resolveProgramStr(&mut a, program);
5013
        try expectNoErrors(&result);
5014
    }
5015
}
5016
5017
/// Test that mutable slice parameters can be borrowed mutably.
5018
@test unsafe fn testMutableBorrowFromMutableSlice() throws (testing::TestError) {
5019
    let mut testArena320 = testArena();
5020
    let testStorage320: 'test320 = &mut testArena320 in {
5021
        let mut a = testResolver(testStorage320);
5022
        let program = "fn f(s: *mut [i32]) { let x: *mut i32 = &mut s[0]; }";
5023
        let result = try resolveProgramStr(&mut a, program);
5024
        try expectNoErrors(&result);
5025
    }
5026
}
5027
5028
/// Test borrowing mutably from a field access on a call returning `*mut`.
5029
@test unsafe fn testMutableBorrowFromCallReturningMutablePointer() throws (testing::TestError) {
5030
    let mut testArena321 = testArena();
5031
    let testStorage321: 'test321 = &mut testArena321 in {
5032
        let mut a = testResolver(testStorage321);
5033
        let program = "record Box { x: i32 } fn idBox(b: *mut Box) -> *mut Box { return b; } fn f() { static b: Box = Box { x: 1 }; let px: *mut i32 = &mut idBox(&mut b).x; }";
5034
        let result = try resolveProgramStr(&mut a, program);
5035
        try expectNoErrors(&result);
5036
    }
5037
}
5038
5039
/// Test that calls returning immutable pointers cannot be mutably borrowed.
5040
@test unsafe fn testMutableBorrowFromCallReturningImmutablePointer() throws (testing::TestError) {
5041
    let mut testArena322 = testArena();
5042
    let testStorage322: 'test322 = &mut testArena322 in {
5043
        let mut a = testResolver(testStorage322);
5044
        let program = "record Box { x: i32 } fn idBox(b: *Box) -> *Box { return b; } fn f() { constant b: Box = Box { x: 1 }; let px: *mut i32 = &mut idBox(&b).x; }";
5045
        let result = try resolveProgramStr(&mut a, program);
5046
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5047
    }
5048
}
5049
5050
/// Test borrowing mutably from a public static through scope access.
5051
@test unsafe fn testMutableBorrowFromScopeAccessStatic() throws (testing::TestError) {
5052
    let mut testArena323 = testArena();
5053
    let testStorage323: 'test323 = &mut testArena323 in {
5054
        let mut a = testResolver(testStorage323);
5055
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5056
5057
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
5058
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "export static COUNTER: i32 = 0;", &mut arena);
5059
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() { let p: *mut i32 = &mut statics::COUNTER; set *p = 7; }", &mut arena);
5060
5061
        let result = try resolveModuleTree(&mut a, rootId);
5062
        try expectNoErrors(&result);
5063
    }
5064
}
5065
5066
/// Test that constants through scope access cannot be mutably borrowed.
5067
@test unsafe fn testMutableBorrowFromScopeAccessConstant() throws (testing::TestError) {
5068
    let mut testArena324 = testArena();
5069
    let testStorage324: 'test324 = &mut testArena324 in {
5070
        let mut a = testResolver(testStorage324);
5071
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5072
5073
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
5074
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant LIMIT: i32 = 7;", &mut arena);
5075
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() { let p: *mut i32 = &mut consts::LIMIT; set *p = 9; }", &mut arena);
5076
5077
        let result = try resolveModuleTree(&mut a, rootId);
5078
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5079
    }
5080
}
5081
5082
/// Test that mutable bindings of immutable pointers cannot borrow mutably through the pointer.
5083
@test unsafe fn testMutableBorrowFromMutableBindingOfPointer() throws (testing::TestError) {
5084
    let mut testArena325 = testArena();
5085
    let testStorage325: 'test325 = &mut testArena325 in {
5086
        let mut a = testResolver(testStorage325);
5087
        let program = "fn f() { static x: i32 = 1; let p: *i32 = &x; let y = &mut *p; }";
5088
        let result = try resolveProgramStr(&mut a, program);
5089
        let err = try expectError(&result);
5090
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5091
    }
5092
}
5093
5094
/// Test that mutable pointer to immutable slice cannot be assigned through index.
5095
/// This tests the case where we have `*mut *[T]`; the outer pointer is mutable but
5096
/// the inner slice is immutable, so we shouldn't be able to mutate the elements.
5097
@test unsafe fn testAssignThroughMutablePointerToImmutableSlice() throws (testing::TestError) {
5098
    let mut testArena326 = testArena();
5099
    let testStorage326: 'test326 = &mut testArena326 in {
5100
        let mut a = testResolver(testStorage326);
5101
        let program = "fn f(slice: *[i32]) { let p: *mut *[i32] = &mut slice; set p[0] = 1; }";
5102
        let result = try resolveProgramStr(&mut a, program);
5103
5104
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5105
    }
5106
}
5107
5108
/// Test that mutable slice parameters can be assigned through index.
5109
@test unsafe fn testAssignThroughMutableSliceParam() throws (testing::TestError) {
5110
    {
5111
        // Mutable slice param: direct assignment should work
5112
        let mut testArena327 = testArena();
5113
        let testStorage327: 'test327 = &mut testArena327 in {
5114
            let mut a = testResolver(testStorage327);
5115
            let program = "fn f(slice: *mut [i32]) { set slice[0] = 1; }";
5116
            let result = try resolveProgramStr(&mut a, program);
5117
            try expectNoErrors(&result);
5118
        }
5119
    } {
5120
        // Immutable slice param: direct assignment should fail
5121
        let mut testArena328 = testArena();
5122
        let testStorage328: 'test328 = &mut testArena328 in {
5123
            let mut a = testResolver(testStorage328);
5124
            let program = "fn f(slice: *[i32]) { set slice[0] = 1; }";
5125
            let result = try resolveProgramStr(&mut a, program);
5126
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5127
        }
5128
    }
5129
}
5130
5131
/// Test range end type coercion with assignable types.
5132
@test unsafe fn testRangeEndTypeCoercion() throws (testing::TestError) {
5133
    {
5134
        let mut testArena329 = testArena();
5135
        let testStorage329: 'test329 = &mut testArena329 in {
5136
            let mut a = testResolver(testStorage329);
5137
            let program = "fn f(end: u32) { for i in 0..end {} }";
5138
            let result = try resolveProgramStr(&mut a, program);
5139
            try expectNoErrors(&result);
5140
        }
5141
    } {
5142
        let mut testArena330 = testArena();
5143
        let testStorage330: 'test330 = &mut testArena330 in {
5144
            let mut a = testResolver(testStorage330);
5145
            let program = "fn f(start: u32) { for i in start..9 {} }";
5146
            let result = try resolveProgramStr(&mut a, program);
5147
            try expectNoErrors(&result);
5148
        }
5149
    }
5150
}
5151
5152
/// Mixed-width range bounds require an explicit cast.
5153
@test unsafe fn testRangeEndTypeSubType() throws (testing::TestError) {
5154
    {
5155
        let mut testArena331 = testArena();
5156
        let testStorage331: 'test331 = &mut testArena331 in {
5157
            let mut a = testResolver(testStorage331);
5158
            let program = "fn f(start: i8, end: u32) { for i in start..end {} }";
5159
            let result = try resolveProgramStr(&mut a, program);
5160
            let err = try expectError(&result);
5161
            try expectTypeMismatch(err, super::Type::I8, super::Type::U32);
5162
        }
5163
    } {
5164
        let mut testArena332 = testArena();
5165
        let testStorage332: 'test332 = &mut testArena332 in {
5166
            let mut a = testResolver(testStorage332);
5167
            let program = "fn f(start: i8, end: u32) { for i in (start as u32)..end {} }";
5168
            let result = try resolveProgramStr(&mut a, program);
5169
            try expectNoErrors(&result);
5170
        }
5171
    }
5172
}
5173
5174
/// Test that try-catch expressions in statement context accept mismatched types.
5175
@test unsafe fn testTryCatchInStatementContextTypeMismatchOk() throws (testing::TestError) {
5176
    let mut testArena333 = testArena();
5177
    let testStorage333: 'test333 = &mut testArena333 in {
5178
        let mut a = testResolver(testStorage333);
5179
        let program = "fn f() { try g() catch {}; } fn g() -> bool throws (i32) { panic; }";
5180
        let result = try resolveProgramStr(&mut a, program);
5181
        try expectNoErrors(&result);
5182
    }
5183
}
5184
5185
/// Test that try-catch blocks in value context require divergence or void.
5186
@test unsafe fn testTryCatchInValueContextTypeMismatch() throws (testing::TestError) {
5187
    let mut testArena334 = testArena();
5188
    let testStorage334: 'test334 = &mut testArena334 in {
5189
        let mut a = testResolver(testStorage334);
5190
        let program = "fn f() -> bool { return try g() catch {}; } fn g() -> bool throws (i32) { panic; }";
5191
        let result = try resolveProgramStr(&mut a, program);
5192
        let err = try expectError(&result);
5193
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Void);
5194
    }
5195
}
5196
5197
/// Test that try-catch blocks in value context work when they diverge.
5198
@test unsafe fn testTryCatchInValueContextDiverges() throws (testing::TestError) {
5199
    let mut testArena335 = testArena();
5200
    let testStorage335: 'test335 = &mut testArena335 in {
5201
        let mut a = testResolver(testStorage335);
5202
        let program = "fn f() -> bool { return try g() catch { return false; }; } fn g() -> bool throws (i32) { panic; }";
5203
        let result = try resolveProgramStr(&mut a, program);
5204
        try expectNoErrors(&result);
5205
    }
5206
}
5207
5208
/// Test that `try?` lifts result type to optional.
5209
@test unsafe fn testTryOptionalLiftsToOptional() throws (testing::TestError) {
5210
    let mut testArena336 = testArena();
5211
    let testStorage336: 'test336 = &mut testArena336 in {
5212
        let mut a = testResolver(testStorage336);
5213
        let program = "record S {} fn f() -> ?*S { return try? g(); } fn g() -> *S throws (i32) { panic; }";
5214
        let result = try resolveProgramStr(&mut a, program);
5215
        try expectNoErrors(&result);
5216
    }
5217
}
5218
5219
/// Test that record fields can be assigned if the record binding is mutable.
5220
@test unsafe fn testMutableAssignToMutableRecordBinding() throws (testing::TestError) {
5221
    let mut testArena337 = testArena();
5222
    let testStorage337: 'test337 = &mut testArena337 in {
5223
        let mut a = testResolver(testStorage337);
5224
        let program = "record S { x: i32 } fn f() { let mut s = S { x: 1 }; set s.x = 2; }";
5225
        let result = try resolveProgramStr(&mut a, program);
5226
        try expectNoErrors(&result);
5227
    }
5228
}
5229
5230
/// Test that record fields cannot be assigned if the record binding is immutable.
5231
@test unsafe fn testMutableAssignToImmutableRecordBinding() throws (testing::TestError) {
5232
    let mut testArena338 = testArena();
5233
    let testStorage338: 'test338 = &mut testArena338 in {
5234
        let mut a = testResolver(testStorage338);
5235
        let program = "record S { x: i32 } fn f() { let s = S { x: 1 }; set s.x = 2; }";
5236
        let result = try resolveProgramStr(&mut a, program);
5237
        let err = try expectError(&result);
5238
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5239
    }
5240
}
5241
5242
/// Test that record fields can be assigned through a mutable pointer.
5243
@test unsafe fn testMutableAssignToMutablePointerToRecord() throws (testing::TestError) {
5244
    let mut testArena339 = testArena();
5245
    let testStorage339: 'test339 = &mut testArena339 in {
5246
        let mut a = testResolver(testStorage339);
5247
        let program = "record S { x: i32 } fn f(p: *mut S) { set p.x = 2; }";
5248
        let result = try resolveProgramStr(&mut a, program);
5249
        try expectNoErrors(&result);
5250
    }
5251
}
5252
5253
/// Test that record fields cannot be assigned through an immutable pointer.
5254
@test unsafe fn testMutableAssignToImmutablePointerToRecord() throws (testing::TestError) {
5255
    let mut testArena340 = testArena();
5256
    let testStorage340: 'test340 = &mut testArena340 in {
5257
        let mut a = testResolver(testStorage340);
5258
        let program = "record S { x: i32 } fn f(p: *S) { set p.x = 2; }";
5259
        let result = try resolveProgramStr(&mut a, program);
5260
        let err = try expectError(&result);
5261
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5262
    }
5263
}
5264
5265
// Opaque pointer tests.
5266
5267
/// You can assign any pointer (*T) to an opaque pointer (*opaque) without a cast.
5268
@test unsafe fn testOpaquePointerAutoCoercion() throws (testing::TestError) {
5269
    let mut testArena341 = testArena();
5270
    let testStorage341: 'test341 = &mut testArena341 in {
5271
        let mut a = testResolver(testStorage341);
5272
        let result = try resolveProgramStr(&mut a, "unsafe fn f(x: *i32) { let mut ptr: *i32 = x; let o: *opaque = ptr; set ptr = o as *i32; }");
5273
        try expectNoErrors(&result);
5274
    }
5275
}
5276
5277
/// You cannot assign an opaque pointer to a non-opaque pointer without a cast.
5278
@test unsafe fn testOpaquePointerNoReverseCoercion() throws (testing::TestError) {
5279
    let mut testArena342 = testArena();
5280
    let testStorage342: 'test342 = &mut testArena342 in {
5281
        let mut a = testResolver(testStorage342);
5282
        let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let ptr: *i32 = o; }");
5283
        let err = try expectError(&result);
5284
        let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
5285
            else throw testing::TestError::Failed;
5286
        let case super::Type::Pointer { target: expectedTarget, .. } = mismatch.expected
5287
            else throw testing::TestError::Failed;
5288
        let case super::Type::Pointer { target: actualTarget, .. } = mismatch.actual
5289
            else throw testing::TestError::Failed;
5290
5291
        try testing::expect(*expectedTarget == super::Type::I32);
5292
        try testing::expect(*actualTarget == super::Type::Opaque);
5293
    }
5294
}
5295
5296
/// You cannot have a value of type `opaque` (function parameter).
5297
@test unsafe fn testOpaqueValue() throws (testing::TestError) {
5298
    {
5299
        let mut testArena343 = testArena();
5300
        let testStorage343: 'test343 = &mut testArena343 in {
5301
            let mut a = testResolver(testStorage343);
5302
            let result = try resolveProgramStr(&mut a, "fn f(x: opaque) {}");
5303
            let err = try expectError(&result);
5304
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
5305
        }
5306
    } {
5307
        let mut testArena344 = testArena();
5308
        let testStorage344: 'test344 = &mut testArena344 in {
5309
            let mut a = testResolver(testStorage344);
5310
            let result = try resolveProgramStr(&mut a, "unsafe fn f() { let x: opaque = undefined; }");
5311
            let err = try expectError(&result);
5312
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
5313
        }
5314
    } {
5315
        let mut testArena345 = testArena();
5316
        let testStorage345: 'test345 = &mut testArena345 in {
5317
            let mut a = testResolver(testStorage345);
5318
            let result = try resolveProgramStr(&mut a, "record R { x: opaque }");
5319
            let err = try expectError(&result);
5320
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
5321
        }
5322
    }
5323
}
5324
5325
/// You cannot dereference an opaque pointer, you have to cast it first.
5326
@test unsafe fn testOpaquePointerNoDereference() throws (testing::TestError) {
5327
    let mut testArena346 = testArena();
5328
    let testStorage346: 'test346 = &mut testArena346 in {
5329
        let mut a = testResolver(testStorage346);
5330
        let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = *o; }");
5331
        let err = try expectError(&result);
5332
        try expectErrorKind(&result, super::ErrorKind::OpaqueTypeDeref);
5333
    }
5334
}
5335
5336
/// Test that you can dereference after casting.
5337
@test unsafe fn testOpaquePointerDereferenceAfterCast() throws (testing::TestError) {
5338
    let mut testArena347 = testArena();
5339
    let testStorage347: 'test347 = &mut testArena347 in {
5340
        let mut a = testResolver(testStorage347);
5341
        let result = try resolveProgramStr(&mut a, "unsafe fn f() { let o: *opaque = undefined; let x = *(o as *i32); }");
5342
        try expectNoErrors(&result);
5343
    }
5344
}
5345
5346
/// You cannot do pointer arithmetic with an opaque pointer.
5347
@test unsafe fn testOpaquePointerNoArithmetic() throws (testing::TestError) {
5348
    {
5349
        let mut testArena348 = testArena();
5350
        let testStorage348: 'test348 = &mut testArena348 in {
5351
            let mut a = testResolver(testStorage348);
5352
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = o + 1; }");
5353
            let err = try expectError(&result);
5354
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
5355
        }
5356
    } {
5357
        let mut testArena349 = testArena();
5358
        let testStorage349: 'test349 = &mut testArena349 in {
5359
            let mut a = testResolver(testStorage349);
5360
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = 1 + o; }");
5361
            let err = try expectError(&result);
5362
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
5363
        }
5364
    } {
5365
        let mut testArena350 = testArena();
5366
        let testStorage350: 'test350 = &mut testArena350 in {
5367
            let mut a = testResolver(testStorage350);
5368
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = o - 1; }");
5369
            let err = try expectError(&result);
5370
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
5371
        }
5372
    } {
5373
        let mut testArena351 = testArena();
5374
        let testStorage351: 'test351 = &mut testArena351 in {
5375
            let mut a = testResolver(testStorage351);
5376
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = 1 - o; }");
5377
            let err = try expectError(&result);
5378
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
5379
        }
5380
    }
5381
}
5382
5383
// Wildcard import/reexport tests.
5384
5385
/// Test transitive re-export.
5386
@test unsafe fn testWildcardReexportTransitive() throws (testing::TestError) {
5387
    let mut testArena352 = testArena();
5388
    let testStorage352: 'test352 = &mut testArena352 in {
5389
        let mut a = testResolver(testStorage352);
5390
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5391
5392
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod a; export mod b;", &mut arena);
5393
        let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b; fn main() -> i32 { return b::helper() + b::MAX; }", &mut arena);
5394
        let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "mod c; export use c::*;", &mut arena);
5395
        let cId = try registerModule(&mut MODULE_GRAPH, bId, "c", "mod d; export use d::*; export fn helper() -> i32 { return 42; }", &mut arena);
5396
        let dId = try registerModule(&mut MODULE_GRAPH, cId, "d", "export constant MAX: i32 = 100;", &mut arena);
5397
5398
        let result = try resolveModuleTree(&mut a, rootId);
5399
        try expectNoErrors(&result);
5400
    }
5401
}
5402
5403
/// Test that wildcard import can access public symbols.
5404
@test unsafe fn testWildcardImportPublicOnly() throws (testing::TestError) {
5405
    let mut testArena353 = testArena();
5406
    let testStorage353: 'test353 = &mut testArena353 in {
5407
        let mut a = testResolver(testStorage353);
5408
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5409
5410
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod b; mod a;", &mut arena);
5411
        let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "export record Value { number: i32 } export fn public() -> i32 { return 1; } fn private() -> i32 { return 2; }", &mut arena);
5412
        let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b::*; fn id(value: Value) -> Value { return value; } fn main() -> i32 { return public() + id(Value { number: 2 }).number; }", &mut arena);
5413
5414
        let result = try resolveModuleTree(&mut a, rootId);
5415
        try expectNoErrors(&result);
5416
    }
5417
}
5418
5419
/// Test that wildcard import cannot access private symbols.
5420
@test unsafe fn testWildcardImportSkipsPrivate() throws (testing::TestError) {
5421
    let mut testArena354 = testArena();
5422
    let testStorage354: 'test354 = &mut testArena354 in {
5423
        let mut a = testResolver(testStorage354);
5424
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5425
5426
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod b; mod a;", &mut arena);
5427
        let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "export fn public() -> i32 { return 1; } fn private() -> i32 { return 2; }", &mut arena);
5428
        let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b::*; fn main() -> i32 { return private(); }", &mut arena);
5429
5430
        let result = try resolveModuleTree(&mut a, rootId);
5431
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
5432
    }
5433
}
5434
5435
/// Test that a constant array can use another constant as its length.
5436
@test unsafe fn testConstArrayWithConstLength() throws (testing::TestError) {
5437
    let mut testArena355 = testArena();
5438
    let testStorage355: 'test355 = &mut testArena355 in {
5439
        let mut a = testResolver(testStorage355);
5440
        let program = "constant LEN: u32 = 3; constant ARR: [i32; LEN] = [1, 2, 3];";
5441
        let result = try resolveProgramStr(&mut a, program);
5442
        try expectNoErrors(&result);
5443
5444
        // Verify the array constant has the correct type with length 3.
5445
        let arrStmt = try getBlockStmt(result.root, 1);
5446
        let sym = super::symbolFor(&a, arrStmt)
5447
            else throw testing::TestError::Failed;
5448
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
5449
            else throw testing::TestError::Failed;
5450
        try testing::expect(arrType.length == 3);
5451
    }
5452
}
5453
5454
/// Test that a record field can use a constant as its array length.
5455
@test unsafe fn testRecordFieldWithConstArrayLength() throws (testing::TestError) {
5456
    let mut testArena356 = testArena();
5457
    let testStorage356: 'test356 = &mut testArena356 in {
5458
        let mut a = testResolver(testStorage356);
5459
        let program = "constant SIZE: u32 = 4; record Buffer { data: [i32; SIZE], }";
5460
        let result = try resolveProgramStr(&mut a, program);
5461
        try expectNoErrors(&result);
5462
    }
5463
}
5464
5465
/// Test that a constant can have a record literal value (lazy record body resolution).
5466
@test unsafe fn testConstWithRecordLiteral() throws (testing::TestError) {
5467
    let mut testArena357 = testArena();
5468
    let testStorage357: 'test357 = &mut testArena357 in {
5469
        let mut a = testResolver(testStorage357);
5470
        let program = "record Point { x: i32, y: i32 } constant ORIGIN: Point = Point { x: 0, y: 0 };";
5471
        let result = try resolveProgramStr(&mut a, program);
5472
        try expectNoErrors(&result);
5473
    }
5474
}
5475
5476
/// Test that a constant can have a union variant value (lazy union body resolution).
5477
@test unsafe fn testConstWithUnionVariant() throws (testing::TestError) {
5478
    let mut testArena358 = testArena();
5479
    let testStorage358: 'test358 = &mut testArena358 in {
5480
        let mut a = testResolver(testStorage358);
5481
        let program = "union Color { Red, Green, Blue } constant DEFAULT: Color = Color::Red;";
5482
        let result = try resolveProgramStr(&mut a, program);
5483
        try expectNoErrors(&result);
5484
    }
5485
}
5486
5487
/// Test that record field types can reference imported types.
5488
///
5489
/// This tests that `use` statements are processed before record body resolution,
5490
/// allowing record fields to use types from imported modules.
5491
@test unsafe fn testRecordFieldUsesImportedType() throws (testing::TestError) {
5492
    let mut testArena359 = testArena();
5493
    let testStorage359: 'test359 = &mut testArena359 in {
5494
        let mut a = testResolver(testStorage359);
5495
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5496
5497
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod scanner;", &mut arena);
5498
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Pool { count: u32 }", &mut arena);
5499
        let scannerId = try registerModule(&mut MODULE_GRAPH, rootId, "scanner", "use root::types; record Scanner { pool: *types::Pool }", &mut arena);
5500
5501
        let result = try resolveModuleTree(&mut a, rootId);
5502
        try expectNoErrors(&result);
5503
    }
5504
}
5505
5506
/// Test that imported constants can be used in array size expressions.
5507
///
5508
/// This tests that constant values are propagated through scope access expressions,
5509
/// enabling compile-time evaluation of array sizes using imported constants.
5510
@test unsafe fn testImportedConstantInArraySize() throws (testing::TestError) {
5511
    let mut testArena360 = testArena();
5512
    let testStorage360: 'test360 = &mut testArena360 in {
5513
        let mut a = testResolver(testStorage360);
5514
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5515
5516
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
5517
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant SIZE: u32 = 8;", &mut arena);
5518
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; static BUFFER: [u8; consts::SIZE] = [0; consts::SIZE];", &mut arena);
5519
5520
        let result = try resolveModuleTree(&mut a, rootId);
5521
        try expectNoErrors(&result);
5522
    }
5523
}
5524
5525
/// Test that `if let case` binds payload variables in the then branch.
5526
///
5527
/// When using `if let case Union::Variant(x) = expr { ... }`, the variable `x` should
5528
/// be bound to the payload value within the then branch scope.
5529
@test unsafe fn testResolveIfCaseBindsPayload() throws (testing::TestError) {
5530
    let mut testArena361 = testArena();
5531
    let testStorage361: 'test361 = &mut testArena361 in {
5532
        let mut a = testResolver(testStorage361);
5533
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { if let case Opt::Some(x) = value { return x; } return 0; }";
5534
        let result = try resolveProgramStr(&mut a, program);
5535
        try expectNoErrors(&result);
5536
    }
5537
}
5538
5539
/// Test that `if let case` payload binding is scoped to the then branch.
5540
///
5541
/// The payload variable should not be accessible outside the then branch.
5542
@test unsafe fn testResolveIfCasePayloadScopeError() throws (testing::TestError) {
5543
    let mut testArena362 = testArena();
5544
    let testStorage362: 'test362 = &mut testArena362 in {
5545
        let mut a = testResolver(testStorage362);
5546
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { if let case Opt::Some(x) = value {} return x; }";
5547
        let result = try resolveProgramStr(&mut a, program);
5548
        let err = try expectError(&result);
5549
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
5550
            else throw testing::TestError::Failed;
5551
        try testing::expect(mem::eq(name, "x"));
5552
    }
5553
}
5554
5555
/// Test that `let case` binds payload variables in the current scope.
5556
///
5557
/// When using `let case Union::Variant(x) = expr else { ... }`, the variable `x`
5558
/// should be bound in the scope after the statement.
5559
@test unsafe fn testResolveLetCaseElseBindsPayload() throws (testing::TestError) {
5560
    let mut testArena363 = testArena();
5561
    let testStorage363: 'test363 = &mut testArena363 in {
5562
        let mut a = testResolver(testStorage363);
5563
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { let case Opt::Some(x) = value else panic; return x; }";
5564
        let result = try resolveProgramStr(&mut a, program);
5565
        try expectNoErrors(&result);
5566
    }
5567
}
5568
5569
/// Test that function pointers with identical signatures are assignable.
5570
///
5571
/// Two function types with the same parameters, return type, and throw list
5572
/// should be considered structurally equal, even if they are separate allocations.
5573
@test unsafe fn testFnPointerAssignability() throws (testing::TestError) {
5574
    let mut testArena364 = testArena();
5575
    let testStorage364: 'test364 = &mut testArena364 in {
5576
        let mut a = testResolver(testStorage364);
5577
        let program = "fn apply(f: fn(i32) -> i32, x: i32) -> i32 { return f(x); } fn double(n: i32) -> i32 { return n * 2; } apply(double, 5);";
5578
        let result = try resolveProgramStr(&mut a, program);
5579
        try expectNoErrors(&result);
5580
    }
5581
}
5582
5583
/// Test that function pointers with different parameter types are not assignable.
5584
@test unsafe fn testFnPointerParamMismatch() throws (testing::TestError) {
5585
    let mut testArena365 = testArena();
5586
    let testStorage365: 'test365 = &mut testArena365 in {
5587
        let mut a = testResolver(testStorage365);
5588
        let program = "fn apply(f: fn(i32) -> i32, x: i32) -> i32 { return f(x); } fn other(n: i8) -> i32 { return n as i32; } apply(other, 5);";
5589
        let result = try resolveProgramStr(&mut a, program);
5590
        let err = try expectError(&result);
5591
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5592
            else throw testing::TestError::Failed;
5593
    }
5594
}
5595
5596
/// Test that function pointers with different return types are not assignable.
5597
@test unsafe fn testFnPointerReturnMismatch() throws (testing::TestError) {
5598
    let mut testArena366 = testArena();
5599
    let testStorage366: 'test366 = &mut testArena366 in {
5600
        let mut a = testResolver(testStorage366);
5601
        let program = "fn apply(f: fn(i32) -> i32, x: i32) -> i32 { return f(x); } fn other(n: i32) -> i8 { return n as i8; } apply(other, 5);";
5602
        let result = try resolveProgramStr(&mut a, program);
5603
        let err = try expectError(&result);
5604
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5605
            else throw testing::TestError::Failed;
5606
    }
5607
}
5608
5609
/// Test that named records use nominal typing, not structural.
5610
///
5611
/// Two different named record types with identical fields should NOT be
5612
/// assignable to each other, because they are distinct nominal types.
5613
@test unsafe fn testNamedRecordNominalTyping() throws (testing::TestError) {
5614
    let mut testArena367 = testArena();
5615
    let testStorage367: 'test367 = &mut testArena367 in {
5616
        let mut a = testResolver(testStorage367);
5617
        let program = "record Point { x: i32, y: i32 } record Vec2 { x: i32, y: i32 } fn take(p: Point) -> i32 { return p.x; } let v = Vec2 { x: 1, y: 2 }; take(v);";
5618
        let result = try resolveProgramStr(&mut a, program);
5619
        let err = try expectError(&result);
5620
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5621
            else throw testing::TestError::Failed;
5622
    }
5623
}
5624
5625
/// Test that union variants with labeled record payloads can be constructed.
5626
@test unsafe fn testUnionVariantAnonRecordPayload() throws (testing::TestError) {
5627
    let mut testArena368 = testArena();
5628
    let testStorage368: 'test368 = &mut testArena368 in {
5629
        let mut a = testResolver(testStorage368);
5630
        let program = "union Event { Click { x: i32, y: i32 }, Key { code: u32 } } let e = Event::Click { x: 10, y: 20 };";
5631
        let result = try resolveProgramStr(&mut a, program);
5632
        try expectNoErrors(&result);
5633
    }
5634
}
5635
5636
/// Test that unlabeled record literals with positional fields work correctly.
5637
///
5638
/// When a record is declared with positional fields (e.g., `record R(i32, bool)`),
5639
/// the literal must use constructor call syntax with positional arguments.
5640
@test unsafe fn testResolveUnlabeledRecordLitValid() throws (testing::TestError) {
5641
    let mut testArena369 = testArena();
5642
    let testStorage369: 'test369 = &mut testArena369 in {
5643
        let mut a = testResolver(testStorage369);
5644
        let program = "record R(i32, bool); let r: R = R(1, true);";
5645
        let result = try resolveProgramStr(&mut a, program);
5646
        try expectNoErrors(&result);
5647
    }
5648
}
5649
5650
/// Test that using brace syntax for an unlabeled record causes an error.
5651
@test unsafe fn testResolveUnlabeledRecordLitStyleMismatch() throws (testing::TestError) {
5652
    let mut testArena370 = testArena();
5653
    let testStorage370: 'test370 = &mut testArena370 in {
5654
        let mut a = testResolver(testStorage370);
5655
        let program = "record R(i32); let r = R { x: 1 };";
5656
        let result = try resolveProgramStr(&mut a, program);
5657
        try expectErrorKind(&result, super::ErrorKind::RecordFieldStyleMismatch);
5658
    }
5659
}
5660
5661
/// Test that providing too many fields for an unlabeled record causes count mismatch.
5662
@test unsafe fn testResolveUnlabeledRecordLitTooManyFields() throws (testing::TestError) {
5663
    let mut testArena371 = testArena();
5664
    let testStorage371: 'test371 = &mut testArena371 in {
5665
        let mut a = testResolver(testStorage371);
5666
        let program = "record R(i32, bool); let r = R(1, true, 3);";
5667
        let result = try resolveProgramStr(&mut a, program);
5668
        let err = try expectError(&result);
5669
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5670
            else throw testing::TestError::Failed;
5671
    }
5672
}
5673
5674
/// Test that match pattern with wrong number of bindings causes count mismatch.
5675
@test unsafe fn testResolveMatchPatternWrongBindingCount() throws (testing::TestError) {
5676
    let mut testArena372 = testArena();
5677
    let testStorage372: 'test372 = &mut testArena372 in {
5678
        let mut a = testResolver(testStorage372);
5679
        let program = "union Event { Click { x: i32, y: i32 } } fn f(e: Event) { match e { case Event::Click(a) => {} } }";
5680
        let result = try resolveProgramStr(&mut a, program);
5681
        let err = try expectError(&result);
5682
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5683
            else throw testing::TestError::Failed;
5684
    }
5685
}
5686
5687
/// Test that shorthand field syntax works in record literals.
5688
/// `Point { x, y }` should be equivalent to `Point { x: x, y: y }`.
5689
@test unsafe fn testResolveRecordLiteralShorthand() throws (testing::TestError) {
5690
    let mut testArena373 = testArena();
5691
    let testStorage373: 'test373 = &mut testArena373 in {
5692
        let mut a = testResolver(testStorage373);
5693
        let program = "record Point { x: i32, y: i32 } fn f() { let x: i32 = 1; let y: i32 = 2; let p = Point { x, y }; }";
5694
        let result = try resolveProgramStr(&mut a, program);
5695
        try expectNoErrors(&result);
5696
    }
5697
}
5698
5699
/// Test shorthand field syntax with mixed explicit and shorthand fields.
5700
@test unsafe fn testResolveRecordLiteralMixedShorthand() throws (testing::TestError) {
5701
    let mut testArena374 = testArena();
5702
    let testStorage374: 'test374 = &mut testArena374 in {
5703
        let mut a = testResolver(testStorage374);
5704
        let program = "record Point { x: i32, y: i32 } fn f() { let x: i32 = 5; let p = Point { x, y: 10 }; }";
5705
        let result = try resolveProgramStr(&mut a, program);
5706
        try expectNoErrors(&result);
5707
    }
5708
}
5709
5710
/// Test record-style union variant patterns with shorthand syntax.
5711
@test unsafe fn testResolveMatchRecordPatternShorthand() throws (testing::TestError) {
5712
    let mut testArena375 = testArena();
5713
    let testStorage375: 'test375 = &mut testArena375 in {
5714
        let mut a = testResolver(testStorage375);
5715
        let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { width, height } => return width + height } }";
5716
        let result = try resolveProgramStr(&mut a, program);
5717
        try expectNoErrors(&result);
5718
    }
5719
}
5720
5721
/// Test record pattern with mixed shorthand and explicit labels.
5722
@test unsafe fn testResolveMatchRecordPatternMixed() throws (testing::TestError) {
5723
    let mut testArena376 = testArena();
5724
    let testStorage376: 'test376 = &mut testArena376 in {
5725
        let mut a = testResolver(testStorage376);
5726
        let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { width, height: h } => return width + h } }";
5727
        let result = try resolveProgramStr(&mut a, program);
5728
        try expectNoErrors(&result);
5729
    }
5730
}
5731
5732
/// Test record pattern with fields in reverse order.
5733
@test unsafe fn testResolveMatchRecordPatternReversed() throws (testing::TestError) {
5734
    let mut testArena377 = testArena();
5735
    let testStorage377: 'test377 = &mut testArena377 in {
5736
        let mut a = testResolver(testStorage377);
5737
        let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { height: h, width: w } => return w + h } }";
5738
        let result = try resolveProgramStr(&mut a, program);
5739
        try expectNoErrors(&result);
5740
    }
5741
}
5742
5743
/// Test record pattern with shorthand syntax in reverse order.
5744
/// Pattern `{ height, width }` binds all fields using shorthand, but not in definition order.
5745
@test unsafe fn testResolveMatchRecordPatternShorthandReversed() throws (testing::TestError) {
5746
    let mut testArena378 = testArena();
5747
    let testStorage378: 'test378 = &mut testArena378 in {
5748
        let mut a = testResolver(testStorage378);
5749
        let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { height, width } => return width + height } }";
5750
        let result = try resolveProgramStr(&mut a, program);
5751
        try expectNoErrors(&result);
5752
    }
5753
}
5754
5755
/// Test record pattern with `..` ignoring fields.
5756
@test unsafe fn testResolveMatchRecordPatternIgnoreRest() throws (testing::TestError) {
5757
    {
5758
        let mut testArena379 = testArena();
5759
        let testStorage379: 'test379 = &mut testArena379 in {
5760
            let mut a = testResolver(testStorage379);
5761
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { x, .. } => return x } }";
5762
            let result = try resolveProgramStr(&mut a, program);
5763
            try expectNoErrors(&result);
5764
        }
5765
    } {
5766
        let mut testArena380 = testArena();
5767
        let testStorage380: 'test380 = &mut testArena380 in {
5768
            let mut a = testResolver(testStorage380);
5769
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { x: val, .. } => return val } }";
5770
            let result = try resolveProgramStr(&mut a, program);
5771
            try expectNoErrors(&result);
5772
        }
5773
    } {
5774
        let mut testArena381 = testArena();
5775
        let testStorage381: 'test381 = &mut testArena381 in {
5776
            let mut a = testResolver(testStorage381);
5777
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { z, .. } => return z } }";
5778
            let result = try resolveProgramStr(&mut a, program);
5779
            try expectNoErrors(&result);
5780
        }
5781
    } {
5782
        let mut testArena382 = testArena();
5783
        let testStorage382: 'test382 = &mut testArena382 in {
5784
            let mut a = testResolver(testStorage382);
5785
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { z, x, .. } => return x + z } }";
5786
            let result = try resolveProgramStr(&mut a, program);
5787
            try expectNoErrors(&result);
5788
        }
5789
    } {
5790
        let mut testArena383 = testArena();
5791
        let testStorage383: 'test383 = &mut testArena383 in {
5792
            let mut a = testResolver(testStorage383);
5793
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> bool { match g { case G::Point { .. } => return true } }";
5794
            let result = try resolveProgramStr(&mut a, program);
5795
            try expectNoErrors(&result);
5796
        }
5797
    }
5798
}
5799
5800
/// Test standalone record pattern matching with unlabeled patterns.
5801
@test unsafe fn testResolveMatchStandaloneRecordUnlabeledPattern() throws (testing::TestError) {
5802
    let mut testArena384 = testArena();
5803
    let testStorage384: 'test384 = &mut testArena384 in {
5804
        let mut a = testResolver(testStorage384);
5805
        let program = "record S(i32); fn f(s: S) -> i32 { match s { case S(x) => return x, else => return 0 } }";
5806
        let result = try resolveProgramStr(&mut a, program);
5807
        try expectNoErrors(&result);
5808
    }
5809
}
5810
5811
/// Test standalone record pattern matching with labeled patterns.
5812
/// Pattern syntax: `T { x }` matches a named record and binds x to the field.
5813
@test unsafe fn testResolveMatchStandaloneRecordLabeledPattern() throws (testing::TestError) {
5814
    let mut testArena385 = testArena();
5815
    let testStorage385: 'test385 = &mut testArena385 in {
5816
        let mut a = testResolver(testStorage385);
5817
        let program = "record T { x: i32 } fn f(t: T) -> i32 { match t { case T { x } => return x, else => return 0 } }";
5818
        let result = try resolveProgramStr(&mut a, program);
5819
        try expectNoErrors(&result);
5820
    }
5821
}
5822
5823
/// Test standalone record pattern with multiple fields.
5824
/// Pattern syntax: `R(a, b)` matches an unlabeled record with multiple fields.
5825
@test unsafe fn testResolveMatchStandaloneRecordMultipleFields() throws (testing::TestError) {
5826
    let mut testArena386 = testArena();
5827
    let testStorage386: 'test386 = &mut testArena386 in {
5828
        let mut a = testResolver(testStorage386);
5829
        let program = "record R(bool, u8); fn f(r: R) -> u8 { match r { case R(_, x) => return x, else => return 0 } }";
5830
        let result = try resolveProgramStr(&mut a, program);
5831
        try expectNoErrors(&result);
5832
    }
5833
}
5834
5835
/// Test standalone record pattern with wrong field count.
5836
/// Pattern `S(x, y)` should fail for a single-field record.
5837
@test unsafe fn testResolveMatchStandaloneRecordWrongFieldCount() throws (testing::TestError) {
5838
    let mut testArena387 = testArena();
5839
    let testStorage387: 'test387 = &mut testArena387 in {
5840
        let mut a = testResolver(testStorage387);
5841
        let program = "record S(i32); fn f(s: S) -> i32 { match s { case S(x, y) => return x + y, else => return 0 } }";
5842
        let result = try resolveProgramStr(&mut a, program);
5843
        let err = try expectError(&result);
5844
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5845
            else throw testing::TestError::Failed;
5846
    }
5847
}
5848
5849
/// Test array pattern matching with element bindings.
5850
/// Pattern syntax: `[x, y]` matches an array and binds elements.
5851
@test unsafe fn testResolveMatchArrayPattern() throws (testing::TestError) {
5852
    let mut testArena388 = testArena();
5853
    let testStorage388: 'test388 = &mut testArena388 in {
5854
        let mut a = testResolver(testStorage388);
5855
        let program = "fn f(arr: [i32; 2]) -> i32 { match arr { case [x, y] => return x + y } }";
5856
        let result = try resolveProgramStr(&mut a, program);
5857
        try expectNoErrors(&result);
5858
    }
5859
}
5860
5861
/// Test identifier pattern that binds the whole value.
5862
/// Pattern syntax: `x` matches any value and binds it.
5863
@test unsafe fn testResolveMatchIdentPattern() throws (testing::TestError) {
5864
    let mut testArena390 = testArena();
5865
    let testStorage390: 'test390 = &mut testArena390 in {
5866
        let mut a = testResolver(testStorage390);
5867
        let program = "fn f(val: i32) -> i32 { match val { x => return x } }";
5868
        let result = try resolveProgramStr(&mut a, program);
5869
        try expectNoErrors(&result);
5870
    }
5871
}
5872
5873
/// Test numeric literal pattern matching.
5874
@test unsafe fn testResolveMatchNumericLiteralPattern() throws (testing::TestError) {
5875
    let mut testArena391 = testArena();
5876
    let testStorage391: 'test391 = &mut testArena391 in {
5877
        let mut a = testResolver(testStorage391);
5878
        let program = "fn f(val: i32) -> i32 { match val { case 42 => return 1, else => return 0 } }";
5879
        let result = try resolveProgramStr(&mut a, program);
5880
        try expectNoErrors(&result);
5881
    }
5882
}
5883
5884
/// Test string literal pattern matching.
5885
@test unsafe fn testResolveMatchStringLiteralPattern() throws (testing::TestError) {
5886
    let mut testArena392 = testArena();
5887
    let testStorage392: 'test392 = &mut testArena392 in {
5888
        let mut a = testResolver(testStorage392);
5889
        let program = "fn f(val: *[u8]) -> i32 { match val { case \"hello\" => return 1, else => return 0 } }";
5890
        let result = try resolveProgramStr(&mut a, program);
5891
        try expectNoErrors(&result);
5892
    }
5893
}
5894
5895
/// Test boolean literal pattern matching.
5896
@test unsafe fn testResolveMatchBoolLiteralPattern() throws (testing::TestError) {
5897
    let mut testArena393 = testArena();
5898
    let testStorage393: 'test393 = &mut testArena393 in {
5899
        let mut a = testResolver(testStorage393);
5900
        let program = "fn f(val: bool) -> i32 { match val { case true => return 1, case false => return 0 } }";
5901
        let result = try resolveProgramStr(&mut a, program);
5902
        try expectNoErrors(&result);
5903
    }
5904
}
5905
5906
/// Test @sliceOf with correct arguments succeeds.
5907
@test unsafe fn testResolveSliceOfCorrect() throws (testing::TestError) {
5908
    // Immutable pointer.
5909
    {
5910
        let mut testArena394 = testArena();
5911
        let testStorage394: 'test394 = &mut testArena394 in {
5912
            let mut a = testResolver(testStorage394);
5913
            let program = "unsafe fn f(ptr: *u8, len: u32) -> *[u8] { return @sliceOf(ptr, len); }";
5914
            let result = try resolveProgramStr(&mut a, program);
5915
            try expectNoErrors(&result);
5916
        }
5917
    }
5918
    // Mutable pointer produces mutable slice.
5919
    {
5920
        let mut testArena395 = testArena();
5921
        let testStorage395: 'test395 = &mut testArena395 in {
5922
            let mut a = testResolver(testStorage395);
5923
            let program = "unsafe fn f(ptr: *mut u8, len: u32) -> *mut [u8] { return @sliceOf(ptr, len); }";
5924
            let result = try resolveProgramStr(&mut a, program);
5925
            try expectNoErrors(&result);
5926
        }
5927
    }
5928
}
5929
5930
/// Test @sliceOf with wrong argument count produces an error.
5931
@test unsafe fn testResolveSliceOfWrongArgCount() throws (testing::TestError) {
5932
    // No arguments.
5933
    {
5934
        let mut testArena396 = testArena();
5935
        let testStorage396: 'test396 = &mut testArena396 in {
5936
            let mut a = testResolver(testStorage396);
5937
            let program = "fn f() -> *[u8] { return @sliceOf(); }";
5938
            let result = try resolveProgramStr(&mut a, program);
5939
            let err = try expectError(&result);
5940
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5941
                else throw testing::TestError::Failed;
5942
            try testing::expect(mismatch.expected == 2);
5943
            try testing::expect(mismatch.actual == 0);
5944
        }
5945
    }
5946
    // Too few arguments.
5947
    {
5948
        let mut testArena397 = testArena();
5949
        let testStorage397: 'test397 = &mut testArena397 in {
5950
            let mut a = testResolver(testStorage397);
5951
            let program = "fn f(ptr: *u8) -> *[u8] { return @sliceOf(ptr); }";
5952
            let result = try resolveProgramStr(&mut a, program);
5953
            let err = try expectError(&result);
5954
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5955
                else throw testing::TestError::Failed;
5956
            try testing::expect(mismatch.expected == 2);
5957
            try testing::expect(mismatch.actual == 1);
5958
        }
5959
    }
5960
    // Too many arguments.
5961
    {
5962
        let mut testArena398 = testArena();
5963
        let testStorage398: 'test398 = &mut testArena398 in {
5964
            let mut a = testResolver(testStorage398);
5965
            let program = "fn f(ptr: *u8, len: u32, cap: u32, extra: u32) -> *[u8] { return @sliceOf(ptr, len, cap, extra); }";
5966
            let result = try resolveProgramStr(&mut a, program);
5967
            let err = try expectError(&result);
5968
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5969
                else throw testing::TestError::Failed;
5970
            try testing::expect(mismatch.expected == 2);
5971
            try testing::expect(mismatch.actual == 4);
5972
        }
5973
    }
5974
}
5975
5976
/// Test @sliceOf with wrong argument types produces errors.
5977
@test unsafe fn testResolveSliceOfWrongArgTypes() throws (testing::TestError) {
5978
    // Non-pointer first argument.
5979
    {
5980
        let mut testArena399 = testArena();
5981
        let testStorage399: 'test399 = &mut testArena399 in {
5982
            let mut a = testResolver(testStorage399);
5983
            let program = "fn f(val: u32, len: u32) -> *[u8] { return @sliceOf(val, len); }";
5984
            let result = try resolveProgramStr(&mut a, program);
5985
            let err = try expectError(&result);
5986
            let case super::ErrorKind::ExpectedPointer = err.kind
5987
                else throw testing::TestError::Failed;
5988
        }
5989
    }
5990
    // Array instead of pointer.
5991
    {
5992
        let mut testArena400 = testArena();
5993
        let testStorage400: 'test400 = &mut testArena400 in {
5994
            let mut a = testResolver(testStorage400);
5995
            let program = "fn f(arr: [u8; 4], len: u32) -> *[u8] { return @sliceOf(arr, len); }";
5996
            let result = try resolveProgramStr(&mut a, program);
5997
            let err = try expectError(&result);
5998
            let case super::ErrorKind::ExpectedPointer = err.kind
5999
                else throw testing::TestError::Failed;
6000
        }
6001
    }
6002
    // Non-numeric second argument.
6003
    {
6004
        let mut testArena401 = testArena();
6005
        let testStorage401: 'test401 = &mut testArena401 in {
6006
            let mut a = testResolver(testStorage401);
6007
            let program = "fn f(ptr: *u8, len: bool) -> *[u8] { return @sliceOf(ptr, len); }";
6008
            let result = try resolveProgramStr(&mut a, program);
6009
            let err = try expectError(&result);
6010
            let case super::ErrorKind::TypeMismatch(_) = err.kind
6011
                else throw testing::TestError::Failed;
6012
        }
6013
    }
6014
    // Pointer second argument.
6015
    {
6016
        let mut testArena402 = testArena();
6017
        let testStorage402: 'test402 = &mut testArena402 in {
6018
            let mut a = testResolver(testStorage402);
6019
            let program = "fn f(ptr: *u8, len: *u32) -> *[u8] { return @sliceOf(ptr, len); }";
6020
            let result = try resolveProgramStr(&mut a, program);
6021
            let err = try expectError(&result);
6022
            let case super::ErrorKind::TypeMismatch(_) = err.kind
6023
                else throw testing::TestError::Failed;
6024
        }
6025
    }
6026
}
6027
6028
/// Test @sliceOf with 3 arguments (ptr, len, cap) succeeds.
6029
@test unsafe fn testResolveSliceOfWithCap() throws (testing::TestError) {
6030
    {
6031
        let mut testArena403 = testArena();
6032
        let testStorage403: 'test403 = &mut testArena403 in {
6033
            let mut a = testResolver(testStorage403);
6034
            let program = "unsafe fn f(ptr: *u8, len: u32, cap: u32) -> *[u8] { return @sliceOf(ptr, len, cap); }";
6035
            let result = try resolveProgramStr(&mut a, program);
6036
            try expectNoErrors(&result);
6037
        }
6038
    }
6039
    // Mutable pointer produces mutable slice.
6040
    {
6041
        let mut testArena404 = testArena();
6042
        let testStorage404: 'test404 = &mut testArena404 in {
6043
            let mut a = testResolver(testStorage404);
6044
            let program = "unsafe fn f(ptr: *mut u8, len: u32, cap: u32) -> *mut [u8] { return @sliceOf(ptr, len, cap); }";
6045
            let result = try resolveProgramStr(&mut a, program);
6046
            try expectNoErrors(&result);
6047
        }
6048
    }
6049
}
6050
6051
/// Test @sliceOf with 3 arguments but wrong cap type.
6052
@test unsafe fn testResolveSliceOfCapWrongType() throws (testing::TestError) {
6053
    let mut testArena405 = testArena();
6054
    let testStorage405: 'test405 = &mut testArena405 in {
6055
        let mut a = testResolver(testStorage405);
6056
        let program = "fn f(ptr: *u8, len: u32, cap: bool) -> *[u8] { return @sliceOf(ptr, len, cap); }";
6057
        let result = try resolveProgramStr(&mut a, program);
6058
        let err = try expectError(&result);
6059
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6060
            else throw testing::TestError::Failed;
6061
    }
6062
}
6063
6064
/// Test .cap field access on slices resolves to u32.
6065
@test unsafe fn testResolveSliceCapField() throws (testing::TestError) {
6066
    let mut testArena406 = testArena();
6067
    let testStorage406: 'test406 = &mut testArena406 in {
6068
        let mut a = testResolver(testStorage406);
6069
        let program = "fn f(s: *[u8]) -> u32 { return s.cap; }";
6070
        let result = try resolveProgramStr(&mut a, program);
6071
        try expectNoErrors(&result);
6072
    }
6073
}
6074
6075
/// Test `.append()` on immutable slice produces an error.
6076
@test unsafe fn testResolveSliceAppendImmutable() throws (testing::TestError) {
6077
    let mut testArena407 = testArena();
6078
    let testStorage407: 'test407 = &mut testArena407 in {
6079
        let mut a = testResolver(testStorage407);
6080
        let program = "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque } fn f(s: *[i32], a: A) { s.append(1, a); }";
6081
        let result = try resolveProgramStr(&mut a, program);
6082
        let err = try expectError(&result);
6083
        let case super::ErrorKind::ImmutableBinding = err.kind
6084
            else throw testing::TestError::Failed;
6085
    }
6086
}
6087
6088
/// Test `.append()` with wrong argument count produces an error.
6089
@test unsafe fn testResolveSliceAppendWrongArgCount() throws (testing::TestError) {
6090
    // Too few arguments.
6091
    {
6092
        let mut testArena408 = testArena();
6093
        let testStorage408: 'test408 = &mut testArena408 in {
6094
            let mut a = testResolver(testStorage408);
6095
            let program = "fn f(s: *mut [i32]) { s.append(1); }";
6096
            let result = try resolveProgramStr(&mut a, program);
6097
            let err = try expectError(&result);
6098
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
6099
                else throw testing::TestError::Failed;
6100
            try testing::expect(m.expected == 2);
6101
            try testing::expect(m.actual == 1);
6102
        }
6103
    }
6104
    // Too many arguments.
6105
    {
6106
        let mut testArena409 = testArena();
6107
        let testStorage409: 'test409 = &mut testArena409 in {
6108
            let mut a = testResolver(testStorage409);
6109
            let program = "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque } fn f(s: *mut [i32], a: A) { s.append(1, a, 0); }";
6110
            let result = try resolveProgramStr(&mut a, program);
6111
            let err = try expectError(&result);
6112
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
6113
                else throw testing::TestError::Failed;
6114
            try testing::expect(m.expected == 2);
6115
            try testing::expect(m.actual == 3);
6116
        }
6117
    }
6118
}
6119
6120
/// Test `.append()` with correct arguments succeeds.
6121
@test unsafe fn testResolveSliceAppendCorrect() throws (testing::TestError) {
6122
    let mut testArena410 = testArena();
6123
    let testStorage410: 'test410 = &mut testArena410 in {
6124
        let mut a = testResolver(testStorage410);
6125
        let program = "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque } fn f(s: *mut [i32], a: A) { s.append(1, a); }";
6126
        let result = try resolveProgramStr(&mut a, program);
6127
        try expectNoErrors(&result);
6128
    }
6129
}
6130
6131
/// Test `.append()` with wrong element type produces an error.
6132
@test unsafe fn testResolveSliceAppendWrongElemType() throws (testing::TestError) {
6133
    let mut testArena411 = testArena();
6134
    let testStorage411: 'test411 = &mut testArena411 in {
6135
        let mut a = testResolver(testStorage411);
6136
        let program = "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque } fn f(s: *mut [i32], a: A) { s.append(true, a); }";
6137
        let result = try resolveProgramStr(&mut a, program);
6138
        let err = try expectError(&result);
6139
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6140
            else throw testing::TestError::Failed;
6141
    }
6142
}
6143
6144
/// Test `.delete()` on immutable slice produces an error.
6145
@test unsafe fn testResolveSliceDeleteImmutable() throws (testing::TestError) {
6146
    let mut testArena412 = testArena();
6147
    let testStorage412: 'test412 = &mut testArena412 in {
6148
        let mut a = testResolver(testStorage412);
6149
        let program = "fn f(s: *[i32]) { s.delete(0); }";
6150
        let result = try resolveProgramStr(&mut a, program);
6151
        let err = try expectError(&result);
6152
        let case super::ErrorKind::ImmutableBinding = err.kind
6153
            else throw testing::TestError::Failed;
6154
    }
6155
}
6156
6157
/// Test `.delete()` with wrong argument count produces an error.
6158
@test unsafe fn testResolveSliceDeleteWrongArgCount() throws (testing::TestError) {
6159
    // No arguments.
6160
    {
6161
        let mut testArena413 = testArena();
6162
        let testStorage413: 'test413 = &mut testArena413 in {
6163
            let mut a = testResolver(testStorage413);
6164
            let program = "fn f(s: *mut [i32]) { s.delete(); }";
6165
            let result = try resolveProgramStr(&mut a, program);
6166
            let err = try expectError(&result);
6167
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
6168
                else throw testing::TestError::Failed;
6169
            try testing::expect(m.expected == 1);
6170
            try testing::expect(m.actual == 0);
6171
        }
6172
    }
6173
    // Too many arguments.
6174
    {
6175
        let mut testArena414 = testArena();
6176
        let testStorage414: 'test414 = &mut testArena414 in {
6177
            let mut a = testResolver(testStorage414);
6178
            let program = "fn f(s: *mut [i32]) { s.delete(0, 1); }";
6179
            let result = try resolveProgramStr(&mut a, program);
6180
            let err = try expectError(&result);
6181
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
6182
                else throw testing::TestError::Failed;
6183
            try testing::expect(m.expected == 1);
6184
            try testing::expect(m.actual == 2);
6185
        }
6186
    }
6187
}
6188
6189
/// Test `.delete()` with correct arguments succeeds.
6190
@test unsafe fn testResolveSliceDeleteCorrect() throws (testing::TestError) {
6191
    let mut testArena415 = testArena();
6192
    let testStorage415: 'test415 = &mut testArena415 in {
6193
        let mut a = testResolver(testStorage415);
6194
        let program = "fn f(s: *mut [i32]) { s.delete(0); }";
6195
        let result = try resolveProgramStr(&mut a, program);
6196
        try expectNoErrors(&result);
6197
    }
6198
}
6199
6200
/// Test `.delete()` with wrong argument type produces an error.
6201
@test unsafe fn testResolveSliceDeleteWrongArgType() throws (testing::TestError) {
6202
    let mut testArena416 = testArena();
6203
    let testStorage416: 'test416 = &mut testArena416 in {
6204
        let mut a = testResolver(testStorage416);
6205
        let program = "fn f(s: *mut [i32]) { s.delete(true); }";
6206
        let result = try resolveProgramStr(&mut a, program);
6207
        let err = try expectError(&result);
6208
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6209
            else throw testing::TestError::Failed;
6210
    }
6211
}
6212
6213
/// Test `match &opt` produces immutable pointer bindings.
6214
@test unsafe fn testResolveMatchRefUnionBinding() throws (testing::TestError) {
6215
    let mut testArena417 = testArena();
6216
    let testStorage417: 'test417 = &mut testArena417 in {
6217
        let mut a = testResolver(testStorage417);
6218
        let program = "union Opt { Some(i32), None } fn f() { let opt = Opt::Some(42); match &opt { case Opt::Some(x) => { *x; } else => {} } }";
6219
        let result = try resolveProgramStr(&mut a, program);
6220
        try expectNoErrors(&result);
6221
6222
        let fnBlock = try getFnBody(&a, result.root, "f");
6223
        let matchNode = fnBlock.statements[1];
6224
        let case ast::NodeValue::Match(sw) = matchNode.value
6225
            else throw testing::TestError::Failed;
6226
        let caseNode = sw.prongs[0];
6227
6228
        let scope = super::scopeFor(&a, caseNode)
6229
            else throw testing::TestError::Failed;
6230
        let payloadSym = super::findSymbolInScope(scope, "x")
6231
            else throw testing::TestError::Failed;
6232
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
6233
            else throw testing::TestError::Failed;
6234
        let case super::Type::Pointer { class: types::PointerClass::Ref, target, mutable } = payloadValType
6235
            else throw testing::TestError::Failed;
6236
        try testing::expect(not mutable);
6237
        try testing::expect(*target == super::Type::I32);
6238
    }
6239
}
6240
6241
/// Test `match &mut opt` produces mutable pointer bindings.
6242
@test unsafe fn testResolveMatchMutRefUnionBinding() throws (testing::TestError) {
6243
    let mut testArena418 = testArena();
6244
    let testStorage418: 'test418 = &mut testArena418 in {
6245
        let mut a = testResolver(testStorage418);
6246
        let program = "union Opt { Some(i32), None } fn f() { let mut opt = Opt::Some(42); match &mut opt { case Opt::Some(x) => { *x; } else => {} } }";
6247
        let result = try resolveProgramStr(&mut a, program);
6248
        try expectNoErrors(&result);
6249
6250
        let fnBlock = try getFnBody(&a, result.root, "f");
6251
        let matchNode = fnBlock.statements[1];
6252
        let case ast::NodeValue::Match(sw) = matchNode.value
6253
            else throw testing::TestError::Failed;
6254
        let caseNode = sw.prongs[0];
6255
6256
        let scope = super::scopeFor(&a, caseNode)
6257
            else throw testing::TestError::Failed;
6258
        let payloadSym = super::findSymbolInScope(scope, "x")
6259
            else throw testing::TestError::Failed;
6260
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
6261
            else throw testing::TestError::Failed;
6262
        let case super::Type::Pointer { class: types::PointerClass::Ref, target, mutable } = payloadValType
6263
            else throw testing::TestError::Failed;
6264
        try testing::expect(mutable);
6265
        try testing::expect(*target == super::Type::I32);
6266
    }
6267
}
6268
6269
/// Non-constant integer widening must use an explicit cast.
6270
@test unsafe fn testResolveIntegerWideningRequiresCast() throws (testing::TestError) {
6271
    {
6272
        let mut testArena419 = testArena();
6273
        let testStorage419: 'test419 = &mut testArena419 in {
6274
            let mut a = testResolver(testStorage419);
6275
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = x;");
6276
            let err = try expectError(&result);
6277
            try expectTypeMismatch(err, super::Type::U32, super::Type::U8);
6278
        }
6279
    } {
6280
        let mut testArena420 = testArena();
6281
        let testStorage420: 'test420 = &mut testArena420 in {
6282
            let mut a = testResolver(testStorage420);
6283
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u16 = x;");
6284
            let err = try expectError(&result);
6285
            try expectTypeMismatch(err, super::Type::U16, super::Type::U8);
6286
        }
6287
    } {
6288
        let mut testArena421 = testArena();
6289
        let testStorage421: 'test421 = &mut testArena421 in {
6290
            let mut a = testResolver(testStorage421);
6291
            let result = try resolveBlockStr(&mut a, "let x: u16 = 1; let y: u32 = x;");
6292
            let err = try expectError(&result);
6293
            try expectTypeMismatch(err, super::Type::U32, super::Type::U16);
6294
        }
6295
    } {
6296
        let mut testArena422 = testArena();
6297
        let testStorage422: 'test422 = &mut testArena422 in {
6298
            let mut a = testResolver(testStorage422);
6299
            let result = try resolveBlockStr(&mut a, "let x: i8 = 1; let y: i32 = x;");
6300
            let err = try expectError(&result);
6301
            try expectTypeMismatch(err, super::Type::I32, super::Type::I8);
6302
        }
6303
    } {
6304
        let mut testArena423 = testArena();
6305
        let testStorage423: 'test423 = &mut testArena423 in {
6306
            let mut a = testResolver(testStorage423);
6307
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = x as u32;");
6308
            try expectNoErrors(&result);
6309
        }
6310
    } {
6311
        let mut testArena424 = testArena();
6312
        let testStorage424: 'test424 = &mut testArena424 in {
6313
            let mut a = testResolver(testStorage424);
6314
            let result = try resolveBlockStr(&mut a, "let x: i8 = 1; let y: i32 = x as i32;");
6315
            try expectNoErrors(&result);
6316
        }
6317
    }
6318
}
6319
6320
/// Mixed-width integer binary ops require an explicit cast.
6321
@test unsafe fn testResolveIntegerWideningBinOpRequiresCast() throws (testing::TestError) {
6322
    {
6323
        let mut testArena425 = testArena();
6324
        let testStorage425: 'test425 = &mut testArena425 in {
6325
            let mut a = testResolver(testStorage425);
6326
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = x | y;");
6327
            let err = try expectError(&result);
6328
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
6329
        }
6330
    } {
6331
        let mut testArena426 = testArena();
6332
        let testStorage426: 'test426 = &mut testArena426 in {
6333
            let mut a = testResolver(testStorage426);
6334
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 0xFF; let z: u32 = x & y;");
6335
            let err = try expectError(&result);
6336
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
6337
        }
6338
    } {
6339
        let mut testArena427 = testArena();
6340
        let testStorage427: 'test427 = &mut testArena427 in {
6341
            let mut a = testResolver(testStorage427);
6342
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = x + y;");
6343
            let err = try expectError(&result);
6344
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
6345
        }
6346
    } {
6347
        let mut testArena428 = testArena();
6348
        let testStorage428: 'test428 = &mut testArena428 in {
6349
            let mut a = testResolver(testStorage428);
6350
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u8 = x << 2;");
6351
            try expectNoErrors(&result);
6352
        }
6353
    } {
6354
        let mut testArena429 = testArena();
6355
        let testStorage429: 'test429 = &mut testArena429 in {
6356
            let mut a = testResolver(testStorage429);
6357
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = (x as u32) | y;");
6358
            try expectNoErrors(&result);
6359
        }
6360
    } {
6361
        let mut testArena430 = testArena();
6362
        let testStorage430: 'test430 = &mut testArena430 in {
6363
            let mut a = testResolver(testStorage430);
6364
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = (x as u32) + y;");
6365
            try expectNoErrors(&result);
6366
        }
6367
    }
6368
}
6369
6370
/// A mutable slice pointer should be assignable to an immutable slice pointer.
6371
@test unsafe fn testResolveMutSliceAssignableToImmutSlice() throws (testing::TestError) {
6372
    let mut testArena431 = testArena();
6373
    let testStorage431: 'test431 = &mut testArena431 in {
6374
        let mut a = testResolver(testStorage431);
6375
        let result = try resolveBlockStr(&mut a, "static arr: [i32; 3] = [1, 2, 3]; let p: *mut [i32] = &mut arr[..]; let q: *[i32] = p;");
6376
        try expectNoErrors(&result);
6377
    }
6378
}
6379
6380
/// Comprehensive tests for `as` cast expressions.
6381
@test unsafe fn testResolveAsCasts() throws (testing::TestError) {
6382
    { // Pointer to numeric.
6383
        let mut testArena432 = testArena();
6384
        let testStorage432: 'test432 = &mut testArena432 in {
6385
            let mut a = testResolver(testStorage432);
6386
            let result = try resolveBlockStr(&mut a, "static x: i32 = 0; let p = &x; p as u32;");
6387
            try expectNoErrors(&result);
6388
        }
6389
    } { // Function pointer to numeric.
6390
        let mut testArena433 = testArena();
6391
        let testStorage433: 'test433 = &mut testArena433 in {
6392
            let mut a = testResolver(testStorage433);
6393
            let result = try resolveProgramStr(&mut a, "fn run(f: fn()) { f as u32; }");
6394
            try expectNoErrors(&result);
6395
        }
6396
    } { // *u8 to *i32 (u8 to i32 is valid).
6397
        let mut testArena434 = testArena();
6398
        let testStorage434: 'test434 = &mut testArena434 in {
6399
            let mut a = testResolver(testStorage434);
6400
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: *u8 = undefined; p as *i32; }");
6401
            try expectNoErrors(&result);
6402
        }
6403
    } { // **u8 to **i32 (*u8 to *i32 is valid).
6404
        let mut testArena435 = testArena();
6405
        let testStorage435: 'test435 = &mut testArena435 in {
6406
            let mut a = testResolver(testStorage435);
6407
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: **u8 = undefined; p as **i32; }");
6408
            try expectNoErrors(&result);
6409
        }
6410
    }
6411
6412
    { // *[i32] to *[opaque].
6413
        let mut testArena436 = testArena();
6414
        let testStorage436: 'test436 = &mut testArena436 in {
6415
            let mut a = testResolver(testStorage436);
6416
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as *[opaque]; }");
6417
            try expectNoErrors(&result);
6418
        }
6419
    } { // *[opaque] to *[i32].
6420
        let mut testArena437 = testArena();
6421
        let testStorage437: 'test437 = &mut testArena437 in {
6422
            let mut a = testResolver(testStorage437);
6423
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[opaque] = undefined; s as *[i32]; }");
6424
            try expectNoErrors(&result);
6425
        }
6426
    }
6427
6428
    { // *[i32] to *[u8].
6429
        let mut testArena438 = testArena();
6430
        let testStorage438: 'test438 = &mut testArena438 in {
6431
            let mut a = testResolver(testStorage438);
6432
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[i32] = undefined; s as *[u8]; }");
6433
            try expectNoErrors(&result);
6434
        }
6435
    } { // *[record] to *[u8].
6436
        let mut testArena439 = testArena();
6437
        let testStorage439: 'test439 = &mut testArena439 in {
6438
            let mut a = testResolver(testStorage439);
6439
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } unsafe fn f(s: *[R]) { s as *[u8]; }");
6440
            try expectNoErrors(&result);
6441
        }
6442
    }
6443
6444
    { // *[u8] to *[i32].
6445
        let mut testArena440 = testArena();
6446
        let testStorage440: 'test440 = &mut testArena440 in {
6447
            let mut a = testResolver(testStorage440);
6448
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[u8] = undefined; s as *[i32]; }");
6449
            try expectNoErrors(&result);
6450
        }
6451
    } { // *[*u8] to *[*i32]
6452
        let mut testArena441 = testArena();
6453
        let testStorage441: 'test441 = &mut testArena441 in {
6454
            let mut a = testResolver(testStorage441);
6455
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[*u8] = undefined; s as *[*i32]; }");
6456
            try expectNoErrors(&result);
6457
        }
6458
    }
6459
6460
    { // Identity cast: *mut [i32] to *mut [i32].
6461
        let mut testArena442 = testArena();
6462
        let testStorage442: 'test442 = &mut testArena442 in {
6463
            let mut a = testResolver(testStorage442);
6464
            let result = try resolveProgramStr(&mut a, "fn run(s: *mut [i32]) { s as *mut [i32]; }");
6465
            try expectNoErrors(&result);
6466
        }
6467
    } { // Identity cast: *i32 to *i32.
6468
        let mut testArena443 = testArena();
6469
        let testStorage443: 'test443 = &mut testArena443 in {
6470
            let mut a = testResolver(testStorage443);
6471
            let result = try resolveProgramStr(&mut a, "fn run(p: *i32) { p as *i32; }");
6472
            try expectNoErrors(&result);
6473
        }
6474
    } { // Identity cast: i32 to i32.
6475
        let mut testArena444 = testArena();
6476
        let testStorage444: 'test444 = &mut testArena444 in {
6477
            let mut a = testResolver(testStorage444);
6478
            let result = try resolveBlockStr(&mut a, "let x: i32 = 0; x as i32;");
6479
            try expectNoErrors(&result);
6480
        }
6481
    }
6482
}
6483
6484
/// Tests for invalid `as` casts that should be rejected.
6485
@test unsafe fn testResolveAsCastsInvalid() throws (testing::TestError) {
6486
    { // Pointer to slice is invalid.
6487
        let mut testArena445 = testArena();
6488
        let testStorage445: 'test445 = &mut testArena445 in {
6489
            let mut a = testResolver(testStorage445);
6490
            let result = try resolveProgramStr(&mut a, "fn run(p: *i32) { p as *[i32]; }");
6491
            let err = try expectError(&result);
6492
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6493
                else throw testing::TestError::Failed;
6494
        }
6495
    } { // Slice to pointer is invalid.
6496
        let mut testArena446 = testArena();
6497
        let testStorage446: 'test446 = &mut testArena446 in {
6498
            let mut a = testResolver(testStorage446);
6499
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as *i32; }");
6500
            let err = try expectError(&result);
6501
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6502
                else throw testing::TestError::Failed;
6503
        }
6504
    } { // *T to *i32 is invalid.
6505
        let mut testArena447 = testArena();
6506
        let testStorage447: 'test447 = &mut testArena447 in {
6507
            let mut a = testResolver(testStorage447);
6508
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(p: *R) { p as *i32; }");
6509
            let err = try expectError(&result);
6510
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6511
                else throw testing::TestError::Failed;
6512
        }
6513
    } { // *[T] to *[i32] is invalid.
6514
        let mut testArena448 = testArena();
6515
        let testStorage448: 'test448 = &mut testArena448 in {
6516
            let mut a = testResolver(testStorage448);
6517
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(s: *[R]) { s as *[i32]; }");
6518
            let err = try expectError(&result);
6519
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6520
                else throw testing::TestError::Failed;
6521
        }
6522
    } { // Slice to numeric is invalid.
6523
        let mut testArena449 = testArena();
6524
        let testStorage449: 'test449 = &mut testArena449 in {
6525
            let mut a = testResolver(testStorage449);
6526
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as u32; }");
6527
            let err = try expectError(&result);
6528
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6529
                else throw testing::TestError::Failed;
6530
        }
6531
    } { // *record to *u8 is invalid.
6532
        let mut testArena450 = testArena();
6533
        let testStorage450: 'test450 = &mut testArena450 in {
6534
            let mut a = testResolver(testStorage450);
6535
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(p: *R) { p as *u8; }");
6536
            let err = try expectError(&result);
6537
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6538
                else throw testing::TestError::Failed;
6539
        }
6540
    }
6541
}
6542
6543
/// Test that catch binding is available in catch block scope.
6544
@test unsafe fn testResolveTryCatchBinding() throws (testing::TestError) {
6545
    {
6546
        let mut testArena451 = testArena();
6547
        let testStorage451: 'test451 = &mut testArena451 in {
6548
            let mut a = testResolver(testStorage451);
6549
            let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; } fn caller() -> u32 { return try fallible() catch err { return 0; }; }";
6550
            let result = try resolveProgramStr(&mut a, program);
6551
            try expectNoErrors(&result);
6552
        }
6553
    } {
6554
        let mut testArena452 = testArena();
6555
        let testStorage452: 'test452 = &mut testArena452 in {
6556
            let mut a = testResolver(testStorage452);
6557
            let program = "union Error { A, B } fn fallible() -> u32 throws (Error) { throw Error::A; } fn caller() -> u32 { return try fallible() catch e { if e == Error::A { return 1; } else { return 2; } }; }";
6558
            let result = try resolveProgramStr(&mut a, program);
6559
            try expectNoErrors(&result);
6560
        }
6561
    } {
6562
        let mut testArena453 = testArena();
6563
        let testStorage453: 'test453 = &mut testArena453 in {
6564
            let mut a = testResolver(testStorage453);
6565
            let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; } fn caller() -> u32 { return try fallible() catch err { if err == Error::Fail { return 1; } return 0; }; }";
6566
            let result = try resolveProgramStr(&mut a, program);
6567
            try expectNoErrors(&result);
6568
        }
6569
    } {
6570
        let mut testArena454 = testArena();
6571
        let testStorage454: 'test454 = &mut testArena454 in {
6572
            let mut a = testResolver(testStorage454);
6573
            let program = "union Error { Fail(u32) } fn fallible() -> u32 throws (Error) { throw Error::Fail(42); } fn caller() -> u32 { return try fallible() catch err { match err { case Error::Fail(x) => return x, } }; }";
6574
            let result = try resolveProgramStr(&mut a, program);
6575
            try expectNoErrors(&result);
6576
        }
6577
    }
6578
}
6579
6580
/// Test that duplicate union variant patterns are detected.
6581
@test unsafe fn testResolveMatchDuplicateUnionPattern() throws (testing::TestError) {
6582
    {
6583
        let mut testArena455 = testArena();
6584
        let testStorage455: 'test455 = &mut testArena455 in {
6585
            let mut a = testResolver(testStorage455);
6586
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::A => {}, else => {} } }";
6587
            let result = try resolveProgramStr(&mut a, program);
6588
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6589
        }
6590
    } {
6591
        // No duplicate: distinct variants are fine.
6592
        let mut testArena456 = testArena();
6593
        let testStorage456: 'test456 = &mut testArena456 in {
6594
            let mut a = testResolver(testStorage456);
6595
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::B => {} } }";
6596
            let result = try resolveProgramStr(&mut a, program);
6597
            try expectNoErrors(&result);
6598
        }
6599
    }
6600
}
6601
6602
/// Test that duplicate bool patterns are detected.
6603
@test unsafe fn testResolveMatchDuplicateBoolPattern() throws (testing::TestError) {
6604
    {
6605
        let mut testArena457 = testArena();
6606
        let testStorage457: 'test457 = &mut testArena457 in {
6607
            let mut a = testResolver(testStorage457);
6608
            let program = "fn f(x: bool) { match x { case true => {}, case true => {}, else => {} } }";
6609
            let result = try resolveProgramStr(&mut a, program);
6610
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6611
        }
6612
    } {
6613
        let mut testArena458 = testArena();
6614
        let testStorage458: 'test458 = &mut testArena458 in {
6615
            let mut a = testResolver(testStorage458);
6616
            let program = "fn f(x: bool) { match x { case false => {}, case false => {}, else => {} } }";
6617
            let result = try resolveProgramStr(&mut a, program);
6618
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6619
        }
6620
    }
6621
}
6622
6623
/// Test that duplicate nil patterns in optional match are detected.
6624
@test unsafe fn testResolveMatchDuplicateOptionalPattern() throws (testing::TestError) {
6625
    {
6626
        let mut testArena459 = testArena();
6627
        let testStorage459: 'test459 = &mut testArena459 in {
6628
            let mut a = testResolver(testStorage459);
6629
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {}, case nil => {} } }";
6630
            let result = try resolveProgramStr(&mut a, program);
6631
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6632
        }
6633
    } {
6634
        // Duplicate value binding.
6635
        let mut testArena460 = testArena();
6636
        let testStorage460: 'test460 = &mut testArena460 in {
6637
            let mut a = testResolver(testStorage460);
6638
            let program = "fn f(opt: ?i32) { match opt { v => {}, w => {}, case nil => {} } }";
6639
            let result = try resolveProgramStr(&mut a, program);
6640
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6641
        }
6642
    }
6643
}
6644
6645
/// Test that guarded match arms are not considered duplicates.
6646
@test unsafe fn testResolveMatchGuardedNotDuplicate() throws (testing::TestError) {
6647
    {
6648
        // Guarded union variant followed by same variant is fine.
6649
        let mut testArena461 = testArena();
6650
        let testStorage461: 'test461 = &mut testArena461 in {
6651
            let mut a = testResolver(testStorage461);
6652
            let program = "union U { A, B } fn f(u: U) { match u { case U::A if true => {}, case U::A => {}, case U::B => {} } }";
6653
            let result = try resolveProgramStr(&mut a, program);
6654
            try expectNoErrors(&result);
6655
        }
6656
    } {
6657
        // Guarded bool pattern followed by same bool is fine.
6658
        let mut testArena462 = testArena();
6659
        let testStorage462: 'test462 = &mut testArena462 in {
6660
            let mut a = testResolver(testStorage462);
6661
            let program = "fn f(x: bool) { match x { case true if true => {}, case true => {}, case false => {} } }";
6662
            let result = try resolveProgramStr(&mut a, program);
6663
            try expectNoErrors(&result);
6664
        }
6665
    } {
6666
        // Guarded nil pattern followed by nil is fine.
6667
        let mut testArena463 = testArena();
6668
        let testStorage463: 'test463 = &mut testArena463 in {
6669
            let mut a = testResolver(testStorage463);
6670
            let program = "fn f(opt: ?i32) { match opt { case nil if true => {}, case nil => {}, v => {} } }";
6671
            let result = try resolveProgramStr(&mut a, program);
6672
            try expectNoErrors(&result);
6673
        }
6674
    } {
6675
        // Guarded value binding followed by another binding is fine.
6676
        let mut testArena464 = testArena();
6677
        let testStorage464: 'test464 = &mut testArena464 in {
6678
            let mut a = testResolver(testStorage464);
6679
            let program = "fn f(opt: ?i32) { match opt { v if true => {}, w => {}, case nil => {} } }";
6680
            let result = try resolveProgramStr(&mut a, program);
6681
            try expectNoErrors(&result);
6682
        }
6683
    }
6684
}
6685
6686
/// Test that unreachable else is detected when all union variants are covered.
6687
@test unsafe fn testResolveMatchUnreachableElseUnion() throws (testing::TestError) {
6688
    {
6689
        let mut testArena465 = testArena();
6690
        let testStorage465: 'test465 = &mut testArena465 in {
6691
            let mut a = testResolver(testStorage465);
6692
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::B => {}, else => {} } }";
6693
            let result = try resolveProgramStr(&mut a, program);
6694
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6695
        }
6696
    } {
6697
        // Partial coverage with else is fine.
6698
        let mut testArena466 = testArena();
6699
        let testStorage466: 'test466 = &mut testArena466 in {
6700
            let mut a = testResolver(testStorage466);
6701
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, else => {} } }";
6702
            let result = try resolveProgramStr(&mut a, program);
6703
            try expectNoErrors(&result);
6704
        }
6705
    }
6706
}
6707
6708
/// Test that unreachable else is detected when both bool cases are covered.
6709
@test unsafe fn testResolveMatchUnreachableElseBool() throws (testing::TestError) {
6710
    {
6711
        let mut testArena467 = testArena();
6712
        let testStorage467: 'test467 = &mut testArena467 in {
6713
            let mut a = testResolver(testStorage467);
6714
            let program = "fn f(x: bool) { match x { case true => {}, case false => {}, else => {} } }";
6715
            let result = try resolveProgramStr(&mut a, program);
6716
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6717
        }
6718
    } {
6719
        // Only one case with else is fine.
6720
        let mut testArena468 = testArena();
6721
        let testStorage468: 'test468 = &mut testArena468 in {
6722
            let mut a = testResolver(testStorage468);
6723
            let program = "fn f(x: bool) { match x { case true => {}, else => {} } }";
6724
            let result = try resolveProgramStr(&mut a, program);
6725
            try expectNoErrors(&result);
6726
        }
6727
    }
6728
}
6729
6730
/// Test that unreachable else is detected when both optional cases are covered.
6731
@test unsafe fn testResolveMatchUnreachableElseOptional() throws (testing::TestError) {
6732
    {
6733
        let mut testArena469 = testArena();
6734
        let testStorage469: 'test469 = &mut testArena469 in {
6735
            let mut a = testResolver(testStorage469);
6736
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {}, else => {} } }";
6737
            let result = try resolveProgramStr(&mut a, program);
6738
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6739
        }
6740
    } {
6741
        // Only value binding with else is fine.
6742
        let mut testArena470 = testArena();
6743
        let testStorage470: 'test470 = &mut testArena470 in {
6744
            let mut a = testResolver(testStorage470);
6745
            let program = "fn f(opt: ?i32) { match opt { v => {}, else => {} } }";
6746
            let result = try resolveProgramStr(&mut a, program);
6747
            try expectNoErrors(&result);
6748
        }
6749
    }
6750
}
6751
6752
// --- Multi-error typed catch tests ---
6753
6754
@test unsafe fn testTypedCatchExhaustive() throws (testing::TestError) {
6755
    let mut testArena471 = testArena();
6756
    let testStorage471: 'test471 = &mut testArena471 in {
6757
        let mut a = testResolver(testStorage471);
6758
        let program = "union ErrA { A } union ErrB { B } fn f() -> i32 throws (ErrA, ErrB) { throw ErrA::A(); return 0; } fn g() -> i32 { return try f() catch e as ErrA { return 0; } catch e as ErrB { return 1; }; }";
6759
        let result = try resolveProgramStr(&mut a, program);
6760
        try expectNoErrors(&result);
6761
    }
6762
}
6763
6764
@test unsafe fn testTypedCatchNonExhaustive() throws (testing::TestError) {
6765
    let mut testArena472 = testArena();
6766
    let testStorage472: 'test472 = &mut testArena472 in {
6767
        let mut a = testResolver(testStorage472);
6768
        let program = "union ErrA { A } union ErrB { B } fn f() -> i32 throws (ErrA, ErrB) { throw ErrA::A(); return 0; } fn g() -> i32 { return try f() catch e as ErrA { return 0; }; }";
6769
        let result = try resolveProgramStr(&mut a, program);
6770
        try expectErrorKind(&result, super::ErrorKind::TryCatchNonExhaustive);
6771
    }
6772
}
6773
6774
@test unsafe fn testTypedCatchDuplicate() throws (testing::TestError) {
6775
    let mut testArena473 = testArena();
6776
    let testStorage473: 'test473 = &mut testArena473 in {
6777
        let mut a = testResolver(testStorage473);
6778
        let program = "union ErrA { A } union ErrB { B } fn f() -> i32 throws (ErrA, ErrB) { throw ErrA::A(); return 0; } fn g() -> i32 { return try f() catch e as ErrA { return 0; } catch e as ErrA { return 1; }; }";
6779
        let result = try resolveProgramStr(&mut a, program);
6780
        try expectErrorKind(&result, super::ErrorKind::TryCatchDuplicateType);
6781
    }
6782
}
6783
6784
@test unsafe fn testTypedCatchWithCatchAll() throws (testing::TestError) {
6785
    let mut testArena474 = testArena();
6786
    let testStorage474: 'test474 = &mut testArena474 in {
6787
        let mut a = testResolver(testStorage474);
6788
        let program = "union ErrA { A } union ErrB { B } fn f() -> i32 throws (ErrA, ErrB) { throw ErrA::A(); return 0; } fn g() -> i32 { return try f() catch e as ErrA { return 0; } catch { return 1; }; }";
6789
        let result = try resolveProgramStr(&mut a, program);
6790
        try expectNoErrors(&result);
6791
    }
6792
}
6793
6794
@test unsafe fn testTypedCatchWrongType() throws (testing::TestError) {
6795
    let mut testArena475 = testArena();
6796
    let testStorage475: 'test475 = &mut testArena475 in {
6797
        let mut a = testResolver(testStorage475);
6798
        let program = "union ErrA { A } union ErrB { B } union ErrC { C } fn f() -> i32 throws (ErrA, ErrB) { throw ErrA::A(); return 0; } fn g() -> i32 { return try f() catch e as ErrC { return 0; } catch e as ErrA { return 1; }; }";
6799
        let result = try resolveProgramStr(&mut a, program);
6800
        try expectErrorKind(&result, super::ErrorKind::TryIncompatibleError);
6801
    }
6802
}
6803
6804
@test unsafe fn testInferredCatchMultiError() throws (testing::TestError) {
6805
    let mut testArena476 = testArena();
6806
    let testStorage476: 'test476 = &mut testArena476 in {
6807
        let mut a = testResolver(testStorage476);
6808
        let program = "union ErrA { A } union ErrB { B } fn f() -> i32 throws (ErrA, ErrB) { throw ErrA::A(); return 0; } fn g() -> i32 { return try f() catch e { return 0; }; }";
6809
        let result = try resolveProgramStr(&mut a, program);
6810
        try expectErrorKind(&result, super::ErrorKind::TryCatchMultiError);
6811
    }
6812
}
6813
6814
@test unsafe fn testResolveInstanceMissingMethod() throws (testing::TestError) {
6815
    let mut testArena477 = testArena();
6816
    let testStorage477: 'test477 = &mut testArena477 in {
6817
        let mut a = testResolver(testStorage477);
6818
        let program = "trait S { fn (*S) f() -> i32; } record R { x: i32 } instance S for R {}";
6819
        let result = try resolveProgramStr(&mut a, program);
6820
        try expectErrorKind(&result, super::ErrorKind::MissingTraitMethod("f"));
6821
    }
6822
}
6823
6824
@test unsafe fn testResolveInstanceUnknownMethod() throws (testing::TestError) {
6825
    let mut testArena478 = testArena();
6826
    let testStorage478: 'test478 = &mut testArena478 in {
6827
        let mut a = testResolver(testStorage478);
6828
        let program = "trait S { fn (*S) f() -> i32; } record R { x: i32 } instance S for R { fn (self: *R) x() -> i32 { return 0; } }";
6829
        let result = try resolveProgramStr(&mut a, program);
6830
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
6831
    }
6832
}
6833
6834
@test unsafe fn testResolveTraitDuplicateMethodRejected() throws (testing::TestError) {
6835
    let mut testArena479 = testArena();
6836
    let testStorage479: 'test479 = &mut testArena479 in {
6837
        let mut a = testResolver(testStorage479);
6838
        let program = "trait Adder { fn (*mut Adder) add(n: i32) -> i32; fn (*mut Adder) add(n: i32) -> i32; }";
6839
        let result = try resolveProgramStr(&mut a, program);
6840
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("add"));
6841
    }
6842
}
6843
6844
@test unsafe fn testResolveInstanceReceiverTypeMustMatchTarget() throws (testing::TestError) {
6845
    let mut testArena480 = testArena();
6846
    let testStorage480: 'test480 = &mut testArena480 in {
6847
        let mut a = testResolver(testStorage480);
6848
        let program = "record Counter { value: i32 } record Wrong { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Wrong) add(n: i32) -> i32 { return n; } }";
6849
        let result = try resolveProgramStr(&mut a, program);
6850
        let err = try expectError(&result);
6851
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6852
            else throw testing::TestError::Failed;
6853
    }
6854
}
6855
6856
@test unsafe fn testResolveTraitMethodThrowsRequireTry() throws (testing::TestError) {
6857
    let mut testArena481 = testArena();
6858
    let testStorage481: 'test481 = &mut testArena481 in {
6859
        let mut a = testResolver(testStorage481);
6860
        let program = "union Error { Fail } record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32 throws (Error); } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 throws (Error) { throw Error::Fail; return n; } } fn caller(a: *mut opaque Adder) -> i32 { return a.add(1); }";
6861
        let result = try resolveProgramStr(&mut a, program);
6862
        try expectErrorKind(&result, super::ErrorKind::MissingTry);
6863
    }
6864
}
6865
6866
/// Trait declares immutable receiver (*Trait) but instance uses mutable (*mut Type).
6867
/// The instance method could mutate through what was originally an immutable pointer.
6868
@test unsafe fn testResolveInstanceMutReceiverOnImmutableTrait() throws (testing::TestError) {
6869
    let mut testArena482 = testArena();
6870
    let testStorage482: 'test482 = &mut testArena482 in {
6871
        let mut a = testResolver(testStorage482);
6872
        let program = "record Counter { value: i32 } trait Reader { fn (*Reader) read() -> i32; } instance Reader for Counter { fn (c: *mut Counter) read() -> i32 { set c.value = c.value + 1; return c.value; } }";
6873
        let result = try resolveProgramStr(&mut a, program);
6874
        // Should reject: instance declares *mut receiver but trait only requires immutable.
6875
        try expectErrorKind(&result, super::ErrorKind::ReceiverMutabilityMismatch);
6876
    }
6877
}
6878
6879
/// Instance method declares different parameter types than the trait.
6880
/// The resolver should reject the mismatch rather than silently using the trait's types.
6881
@test unsafe fn testResolveInstanceParamTypeMismatch() throws (testing::TestError) {
6882
    let mut testArena483 = testArena();
6883
    let testStorage483: 'test483 = &mut testArena483 in {
6884
        let mut a = testResolver(testStorage483);
6885
        let program = "record Acc { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Acc { fn (a: *mut Acc) add(n: u8) -> i32 { set a.value = a.value + n as i32; return a.value; } }";
6886
        let result = try resolveProgramStr(&mut a, program);
6887
        // Should reject: instance param type u8 doesn't match trait param type i32.
6888
        let err = try expectError(&result);
6889
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6890
            else throw testing::TestError::Failed;
6891
    }
6892
}
6893
6894
/// Duplicate instance declarations for the same (trait, type) pair should be rejected.
6895
@test unsafe fn testResolveInstanceDuplicateRejected() throws (testing::TestError) {
6896
    let mut testArena484 = testArena();
6897
    let testStorage484: 'test484 = &mut testArena484 in {
6898
        let mut a = testResolver(testStorage484);
6899
        let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n + 100; return c.value; } }";
6900
        let result = try resolveProgramStr(&mut a, program);
6901
        // Should reject: duplicate instance for (Adder, Counter).
6902
        try expectErrorKind(&result, super::ErrorKind::DuplicateInstance);
6903
    }
6904
}
6905
6906
/// Trait method receiver must point to the declaring trait type.
6907
@test unsafe fn testResolveTraitReceiverMismatch() throws (testing::TestError) {
6908
    let mut testArena485 = testArena();
6909
    let testStorage485: 'test485 = &mut testArena485 in {
6910
        let mut a = testResolver(testStorage485);
6911
        let program = "record Other { x: i32 } trait Foo { fn (*mut Other) bar() -> i32; }";
6912
        let result = try resolveProgramStr(&mut a, program);
6913
        try expectErrorKind(&result, super::ErrorKind::TraitReceiverMismatch);
6914
    }
6915
}
6916
6917
/// Using a trait name as a value expression should be rejected.
6918
@test unsafe fn testResolveTraitNameAsValueRejected() throws (testing::TestError) {
6919
    let mut testArena486 = testArena();
6920
    let testStorage486: 'test486 = &mut testArena486 in {
6921
        let mut a = testResolver(testStorage486);
6922
        let program = "trait Foo { fn (*Foo) bar() -> i32; } fn test() -> i32 { let x = Foo; return 0; }";
6923
        let result = try resolveProgramStr(&mut a, program);
6924
        try expectErrorKind(&result, super::ErrorKind::UnexpectedTraitName);
6925
    }
6926
}
6927
6928
/// Cross-module trait: coerce to trait object and dispatch from a different module.
6929
@test unsafe fn testResolveTraitCrossModuleCoercion() throws (testing::TestError) {
6930
    let mut testArena487 = testArena();
6931
    let testStorage487: 'test487 = &mut testArena487 in {
6932
        let mut a = testResolver(testStorage487);
6933
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6934
6935
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; mod app;", &mut arena);
6936
        let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "export record Counter { value: i32 } export trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } }", &mut arena);
6937
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::defs; fn test() -> i32 { static c: defs::Counter = defs::Counter { value: 10 }; let a: *mut opaque defs::Adder = &mut c; return a.add(5); }", &mut arena);
6938
6939
        let result = try resolveModuleTree(&mut a, rootId);
6940
        try expectNoErrors(&result);
6941
    }
6942
}
6943
6944
/// Instance in a different module from trait and type.
6945
@test unsafe fn testResolveInstanceCrossModule() throws (testing::TestError) {
6946
    let mut testArena488 = testArena();
6947
    let testStorage488: 'test488 = &mut testArena488 in {
6948
        let mut a = testResolver(testStorage488);
6949
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6950
6951
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; export mod impls; mod app;", &mut arena);
6952
        let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "export record Counter { value: i32 } export trait Adder { fn (*mut Adder) add(n: i32) -> i32; }", &mut arena);
6953
        let implsId = try registerModule(&mut MODULE_GRAPH, rootId, "impls", "use root::defs; instance defs::Adder for defs::Counter { fn (c: *mut defs::Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } }", &mut arena);
6954
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::defs; fn test() -> i32 { static c: defs::Counter = defs::Counter { value: 10 }; let a: *mut opaque defs::Adder = &mut c; return a.add(5); }", &mut arena);
6955
6956
        let result = try resolveModuleTree(&mut a, rootId);
6957
        try expectNoErrors(&result);
6958
    }
6959
}
6960
6961
/// Calling a mutable-receiver trait method on an immutable trait object
6962
/// must be rejected.
6963
@test unsafe fn testResolveTraitMutMethodOnImmutableObject() throws (testing::TestError) {
6964
    let mut testArena489 = testArena();
6965
    let testStorage489: 'test489 = &mut testArena489 in {
6966
        let mut a = testResolver(testStorage489);
6967
        let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } } fn caller(a: *opaque Adder) -> i32 { return a.add(1); }";
6968
        let result = try resolveProgramStr(&mut a, program);
6969
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
6970
    }
6971
}
6972
6973
/// Immutable methods on an immutable trait object should be accepted.
6974
@test unsafe fn testResolveTraitImmutableMethodOnImmutableObject() throws (testing::TestError) {
6975
    let mut testArena490 = testArena();
6976
    let testStorage490: 'test490 = &mut testArena490 in {
6977
        let mut a = testResolver(testStorage490);
6978
        let program = "record Counter { value: i32 } trait Reader { fn (*Reader) get() -> i32; } instance Reader for Counter { fn (c: *Counter) get() -> i32 { return c.value; } } fn caller(r: *opaque Reader) -> i32 { return r.get(); }";
6979
        let result = try resolveProgramStr(&mut a, program);
6980
        try expectNoErrors(&result);
6981
    }
6982
}
6983
6984
/// Both mutable and immutable methods on a mutable trait object should work.
6985
@test unsafe fn testResolveTraitMixedMethodsOnMutableObject() throws (testing::TestError) {
6986
    let mut testArena491 = testArena();
6987
    let testStorage491: 'test491 = &mut testArena491 in {
6988
        let mut a = testResolver(testStorage491);
6989
        let program = "record Counter { value: i32 } trait Ops { fn (&mut Ops) inc(); fn (&Ops) get() -> i32; } instance Ops for Counter { fn (c: &mut Counter) inc() { set c.value = c.value + 1; } fn (c: &Counter) get() -> i32 { return c.value; } } fn caller(o: *mut opaque Ops) -> i32 { o.inc(); return o.get(); }";
6990
        let result = try resolveProgramStr(&mut a, program);
6991
        try expectNoErrors(&result);
6992
    }
6993
}
6994
6995
/// Instance method body type must match the trait return type.
6996
/// The trait declares `-> i32` but the body returns `bool`.
6997
@test unsafe fn testResolveInstanceReturnTypeMismatch() throws (testing::TestError) {
6998
    let mut testArena492 = testArena();
6999
    let testStorage492: 'test492 = &mut testArena492 in {
7000
        let mut a = testResolver(testStorage492);
7001
        let program = "record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() -> bool { return true; } }";
7002
        let result = try resolveProgramStr(&mut a, program);
7003
        let err = try expectError(&result);
7004
        let case super::ErrorKind::TypeMismatch(_) = err.kind
7005
            else throw testing::TestError::Failed;
7006
    }
7007
}
7008
7009
/// Diamond supertrait inheritance: traits B and C both extend A.
7010
/// Declaring them independently should work fine.
7011
@test unsafe fn testResolveTraitDiamondSupertrait() throws (testing::TestError) {
7012
    let mut testArena493 = testArena();
7013
    let testStorage493: 'test493 = &mut testArena493 in {
7014
        let mut a = testResolver(testStorage493);
7015
        let program = "trait A { fn (*A) f() -> i32; } trait B: A { fn (*B) g() -> i32; } trait C: A { fn (*C) h() -> i32; }";
7016
        let result = try resolveProgramStr(&mut a, program);
7017
        try expectNoErrors(&result);
7018
    }
7019
}
7020
7021
/// Diamond supertrait with a combined trait that would cause duplicate
7022
/// method names should be detected.
7023
@test unsafe fn testResolveTraitDiamondDuplicateMethod() throws (testing::TestError) {
7024
    let mut testArena494 = testArena();
7025
    let testStorage494: 'test494 = &mut testArena494 in {
7026
        let mut a = testResolver(testStorage494);
7027
        let program = "trait A { fn (*A) f() -> i32; } trait B: A { fn (*B) g() -> i32; } trait C: A { fn (*C) h() -> i32; } trait D: B + C { fn (*D) i() -> i32; }";
7028
        let result = try resolveProgramStr(&mut a, program);
7029
        // B inherits `f` from A, C inherits `f` from A. D: B + C sees duplicate `f`.
7030
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("f"));
7031
    }
7032
}
7033
7034
/// Supertrait instance must exist when declaring a combined trait instance.
7035
@test unsafe fn testResolveInstanceMissingSupertraitInstance() throws (testing::TestError) {
7036
    let mut testArena495 = testArena();
7037
    let testStorage495: 'test495 = &mut testArena495 in {
7038
        let mut a = testResolver(testStorage495);
7039
        let program = "trait Base { fn (*Base) f() -> i32; } trait Child: Base { fn (*Child) g() -> i32; } record R { x: i32 } instance Child for R { fn (r: *R) g() -> i32 { return r.x; } }";
7040
        let result = try resolveProgramStr(&mut a, program);
7041
        try expectErrorKind(&result, super::ErrorKind::MissingSupertraitInstance("Base"));
7042
    }
7043
}
7044
7045
/// Instance method omits return type when the trait declares `-> i32`.
7046
/// This is rejected -- the return type must be stated explicitly.
7047
@test unsafe fn testResolveInstanceReturnTypeOmitted() throws (testing::TestError) {
7048
    let mut testArena496 = testArena();
7049
    let testStorage496: 'test496 = &mut testArena496 in {
7050
        let mut a = testResolver(testStorage496);
7051
        let program = "record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() { } }";
7052
        let result = try resolveProgramStr(&mut a, program);
7053
        let err = try expectError(&result);
7054
        let case super::ErrorKind::TypeMismatch(_) = err.kind
7055
            else throw testing::TestError::Failed;
7056
    }
7057
}
7058
7059
/// Instance method declares throws but the trait method does not throw.
7060
@test unsafe fn testResolveInstanceThrowsMismatchExtra() throws (testing::TestError) {
7061
    let mut testArena497 = testArena();
7062
    let testStorage497: 'test497 = &mut testArena497 in {
7063
        let mut a = testResolver(testStorage497);
7064
        let program = "union E { Fail } record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() -> i32 throws (E) { return r.x; } }";
7065
        let result = try resolveProgramStr(&mut a, program);
7066
        let err = try expectError(&result);
7067
        let case super::ErrorKind::FnThrowCountMismatch(_) = err.kind
7068
            else throw testing::TestError::Failed;
7069
    }
7070
}
7071
7072
/// Instance method declares a different throws type than the trait.
7073
@test unsafe fn testResolveInstanceThrowsMismatchWrongType() throws (testing::TestError) {
7074
    let mut testArena498 = testArena();
7075
    let testStorage498: 'test498 = &mut testArena498 in {
7076
        let mut a = testResolver(testStorage498);
7077
        let program = "union E1 { Fail } union E2 { Oops } record R { x: i32 } trait T { fn (*T) get() -> i32 throws (E1); } instance T for R { fn (r: *R) get() -> i32 throws (E2) { return r.x; } }";
7078
        let result = try resolveProgramStr(&mut a, program);
7079
        let err = try expectError(&result);
7080
        let case super::ErrorKind::TypeMismatch(_) = err.kind
7081
            else throw testing::TestError::Failed;
7082
    }
7083
}
7084
7085
/// Instance method omits throws clause when trait declares throws.
7086
/// This is rejected -- the throws clause must match exactly.
7087
@test unsafe fn testResolveInstanceThrowsOmitted() throws (testing::TestError) {
7088
    let mut testArena499 = testArena();
7089
    let testStorage499: 'test499 = &mut testArena499 in {
7090
        let mut a = testResolver(testStorage499);
7091
        let program = "union E { Fail } record R { x: i32 } trait T { fn (*T) get() -> i32 throws (E); } instance T for R { fn (r: *R) get() -> i32 { throw E::Fail; return r.x; } }";
7092
        let result = try resolveProgramStr(&mut a, program);
7093
        let err = try expectError(&result);
7094
        let case super::ErrorKind::FnThrowCountMismatch(_) = err.kind
7095
            else throw testing::TestError::Failed;
7096
    }
7097
}
7098
7099
/// Instance method correctly matches the trait's throws clause.
7100
@test unsafe fn testResolveInstanceThrowsMatch() throws (testing::TestError) {
7101
    let mut testArena500 = testArena();
7102
    let testStorage500: 'test500 = &mut testArena500 in {
7103
        let mut a = testResolver(testStorage500);
7104
        let program = "union E { Fail } record R { x: i32 } trait T { fn (*T) get() -> i32 throws (E); } instance T for R { fn (r: *R) get() -> i32 throws (E) { throw E::Fail; return r.x; } }";
7105
        let result = try resolveProgramStr(&mut a, program);
7106
        try expectNoErrors(&result);
7107
    }
7108
}
7109
7110
// Constant expression folding tests //////////////////////////////////////////
7111
7112
/// Resolve a program and verify that the constant at the given statement index
7113
/// has the expected integer magnitude.
7114
unsafe fn expectConstFold(program: *[u8], stmtIdx: u32, expected: u64)
7115
    throws (testing::TestError)
7116
{
7117
    let mut testArena501 = testArena();
7118
    let testStorage501: 'test501 = &mut testArena501 in {
7119
        let mut a = testResolver(testStorage501);
7120
        let result = try resolveProgramStr(&mut a, program);
7121
        try expectNoErrors(&result);
7122
7123
        let stmt = try getBlockStmt(result.root, stmtIdx);
7124
        let sym = super::symbolFor(&a, stmt)
7125
            else throw testing::TestError::Failed;
7126
        let case super::SymbolData::Constant { value, .. } = sym.data
7127
            else throw testing::TestError::Failed;
7128
        let val = value else throw testing::TestError::Failed;
7129
        let case super::ConstValue::Int(intVal) = val
7130
            else throw testing::TestError::Failed;
7131
        try testing::expect(intVal.magnitude == expected);
7132
    }
7133
}
7134
7135
/// Test arithmetic constant folding: add, sub, mul, div.
7136
@test unsafe fn testConstExprArithmetic() throws (testing::TestError) {
7137
    try expectConstFold("constant A: i32 = 10; constant B: i32 = 20; constant C: i32 = A + B;", 2, 30);
7138
    try expectConstFold("constant A: i32 = 50; constant B: i32 = 20; constant C: i32 = A - B;", 2, 30);
7139
    try expectConstFold("constant A: i32 = 6; constant B: i32 = 7; constant C: i32 = A * B;", 2, 42);
7140
    try expectConstFold("constant A: i32 = 100; constant B: i32 = 5; constant C: i32 = A / B;", 2, 20);
7141
}
7142
7143
/// Test bitwise constant folding: and, or, xor.
7144
@test unsafe fn testConstExprBitwise() throws (testing::TestError) {
7145
    try expectConstFold("constant A: i32 = 0xFF; constant B: i32 = 0x0F; constant C: i32 = A & B;", 2, 0x0F);
7146
    try expectConstFold("constant A: i32 = 0xF0; constant B: i32 = 0x0F; constant C: i32 = A | B;", 2, 0xFF);
7147
    try expectConstFold("constant A: i32 = 0xFF; constant B: i32 = 0x0F; constant C: i32 = A ^ B;", 2, 0xF0);
7148
}
7149
7150
/// Test shift constant folding.
7151
@test unsafe fn testConstExprShift() throws (testing::TestError) {
7152
    try expectConstFold("constant A: i32 = 1; constant B: i32 = A << 4;", 1, 16);
7153
    try expectConstFold("constant A: i32 = 32; constant B: i32 = A >> 2;", 1, 8);
7154
}
7155
7156
/// Test chained constant expressions (C depends on A + B, D depends on C).
7157
@test unsafe fn testConstExprChained() throws (testing::TestError) {
7158
    try expectConstFold("constant A: i32 = 10; constant B: i32 = 20; constant C: i32 = A + B; constant D: i32 = C * 2;", 3, 60);
7159
}
7160
7161
/// Test constant expression used as array size.
7162
@test unsafe fn testConstExprAsArraySize() throws (testing::TestError) {
7163
    let mut testArena502 = testArena();
7164
    let testStorage502: 'test502 = &mut testArena502 in {
7165
        let mut a = testResolver(testStorage502);
7166
        let program = "constant A: u32 = 2; constant B: u32 = 3; constant SIZE: u32 = A + B; constant ARR: [i32; SIZE] = [1, 2, 3, 4, 5];";
7167
        let result = try resolveProgramStr(&mut a, program);
7168
        try expectNoErrors(&result);
7169
7170
        let arrStmt = try getBlockStmt(result.root, 3);
7171
        let sym = super::symbolFor(&a, arrStmt)
7172
            else throw testing::TestError::Failed;
7173
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
7174
            else throw testing::TestError::Failed;
7175
        try testing::expect(arrType.length == 5);
7176
    }
7177
}
7178
7179
/// Test cross-module constant expression: a constant in one module references
7180
/// a constant from another module via scope access.
7181
@test unsafe fn testCrossModuleConstExpr() throws (testing::TestError) {
7182
    let mut testArena503 = testArena();
7183
    let testStorage503: 'test503 = &mut testArena503 in {
7184
        let mut a = testResolver(testStorage503);
7185
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
7186
7187
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
7188
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant BASE: i32 = 100;", &mut arena);
7189
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; constant DERIVED: i32 = consts::BASE + 50;", &mut arena);
7190
7191
        let result = try resolveModuleTree(&mut a, rootId);
7192
        try expectNoErrors(&result);
7193
    }
7194
}
7195
7196
/// Test cross-module constant expression used as array size.
7197
@test unsafe fn testCrossModuleConstExprArraySize() throws (testing::TestError) {
7198
    let mut testArena504 = testArena();
7199
    let testStorage504: 'test504 = &mut testArena504 in {
7200
        let mut a = testResolver(testStorage504);
7201
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
7202
7203
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
7204
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant WIDTH: u32 = 8; export constant HEIGHT: u32 = 4;", &mut arena);
7205
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; constant TOTAL: u32 = consts::WIDTH * consts::HEIGHT; static BUF: [u8; TOTAL] = [0; TOTAL];", &mut arena);
7206
7207
        let result = try resolveModuleTree(&mut a, rootId);
7208
        try expectNoErrors(&result);
7209
    }
7210
}
7211
7212
/// Test that non-constant expressions in constant declarations are still rejected.
7213
@test unsafe fn testConstExprNonConstRejected() throws (testing::TestError) {
7214
    let mut testArena505 = testArena();
7215
    let testStorage505: 'test505 = &mut testArena505 in {
7216
        let mut a = testResolver(testStorage505);
7217
        let program = "fn value() -> i32 { return 1; } constant BAD: i32 = value() + 1;";
7218
        let result = try resolveProgramStr(&mut a, program);
7219
        let err = try expectError(&result);
7220
        let case super::ErrorKind::ConstExprRequired = err.kind
7221
            else throw testing::TestError::Failed;
7222
    }
7223
}
7224
7225
/// Test unary negation in constant expressions.
7226
@test unsafe fn testConstExprUnaryNeg() throws (testing::TestError) {
7227
    let mut testArena506 = testArena();
7228
    let testStorage506: 'test506 = &mut testArena506 in {
7229
        let mut a = testResolver(testStorage506);
7230
        let program = "constant A: i32 = 10; constant B: i32 = -A;";
7231
        let result = try resolveProgramStr(&mut a, program);
7232
        try expectNoErrors(&result);
7233
    }
7234
}
7235
7236
/// Test unary not in constant expressions.
7237
@test unsafe fn testConstExprUnaryNot() throws (testing::TestError) {
7238
    let mut testArena507 = testArena();
7239
    let testStorage507: 'test507 = &mut testArena507 in {
7240
        let mut a = testResolver(testStorage507);
7241
        let program = "constant A: bool = true; constant B: bool = not A;";
7242
        let result = try resolveProgramStr(&mut a, program);
7243
        try expectNoErrors(&result);
7244
    }
7245
}
7246
7247
/// Test `as` casts in constant expressions: widening, narrowing, sign changes, chaining.
7248
@test unsafe fn testConstExprCast() throws (testing::TestError) {
7249
    try expectConstFold("constant A: i32 = 42; constant B: u64 = A as u64;", 1, 42);
7250
    try expectConstFold("constant A: u64 = 10; constant B: u8 = A as u8;", 1, 10);
7251
    try expectConstFold("constant A: i32 = 7; constant B: u32 = A as u32;", 1, 7);
7252
    try expectConstFold("constant A: u32 = 100; constant B: i32 = A as i32;", 1, 100);
7253
    try expectConstFold("constant A: u8 = 5; constant B: u64 = (A as u32) as u64;", 1, 5);
7254
    try expectConstFold("constant A: u8 = 3; constant B: u8 = 4; constant C: i32 = (A as i32) + (B as i32);", 2, 7);
7255
    // Cast of unsuffixed literal arithmetic.
7256
    try expectConstFold("constant A: u32 = (3 + 4) as u32;", 0, 7);
7257
    try expectConstFold("constant A: u32 = ((3 + 4) as u64) as u32;", 0, 7);
7258
    try expectConstFold("constant A: u32 = (3 + 4) as u32 + 1;", 0, 8);
7259
    try expectConstFold("constant A: i32 = (2 as i32) * (3 + 4);", 0, 14);
7260
}
7261
7262
/// Test `as` cast in constant expressions used as array size.
7263
@test unsafe fn testConstExprCastAsArraySize() throws (testing::TestError) {
7264
    let mut testArena508 = testArena();
7265
    let testStorage508: 'test508 = &mut testArena508 in {
7266
        let mut a = testResolver(testStorage508);
7267
        let program = "constant LEN: u64 = 4; constant SIZE: u32 = LEN as u32; constant ARR: [i32; SIZE] = [1, 2, 3, 4];";
7268
        let result = try resolveProgramStr(&mut a, program);
7269
        try expectNoErrors(&result);
7270
7271
        let arrStmt = try getBlockStmt(result.root, 2);
7272
        let sym = super::symbolFor(&a, arrStmt)
7273
            else throw testing::TestError::Failed;
7274
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
7275
            else throw testing::TestError::Failed;
7276
        try testing::expect(arrType.length == 4);
7277
    }
7278
}
7279
7280
/// Test unsuffixed integer literals in constant expressions.
7281
@test unsafe fn testConstExprUnsuffixedLiterals() throws (testing::TestError) {
7282
    try expectConstFold("constant A: u32 = 4 * 4;", 0, 16);
7283
    try expectConstFold("constant B: u32 = 10; constant C: u32 = B * 2;", 1, 20);
7284
    try expectConstFold("constant D: u32 = 3 + 7;", 0, 10);
7285
    try expectConstFold("constant E: u32 = 2 * 3 + 4;", 0, 10);
7286
    try expectConstFold("constant F: i32 = -(3 + 4);", 0, 7);
7287
}
7288
7289
/// References cannot escape through return types.
7290
@test unsafe fn testRefReturnRejected() throws (testing::TestError) {
7291
    let mut testArena509 = testArena();
7292
    let testStorage509: 'test509 = &mut testArena509 in {
7293
        let mut a = testResolver(testStorage509);
7294
        let program = "record Marker: Once {} fn bad(value: &u32) -> &u32 { return value; }";
7295
        let result = try resolveProgramStr(&mut a, program);
7296
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7297
    }
7298
}
7299
7300
/// Case-pattern fallbacks must terminate instead of synthesizing bindings.
7301
@test unsafe fn testCaseLetElseFallbackMustTerminate() throws (testing::TestError) {
7302
    let mut testArena510 = testArena();
7303
    let testStorage510: 'test510 = &mut testArena510 in {
7304
        let mut a = testResolver(testStorage510);
7305
        let program = "union Value { Item(u32) } fn run(value: Value) { let case Value::Item(item) = value else value; item; }";
7306
        let result = try resolveProgramStr(&mut a, program);
7307
        try expectErrorKind(&result, super::ErrorKind::LinearLetElseMustTerminate);
7308
    }
7309
}
7310
7311
/// Case bindings are unavailable on the pattern-failure path.
7312
@test unsafe fn testCaseLetElseFallbackCannotUseBinding() throws (testing::TestError) {
7313
    let mut testArena511 = testArena();
7314
    let testStorage511: 'test511 = &mut testArena511 in {
7315
        let mut a = testResolver(testStorage511);
7316
        let program = "union Value { Item(u32) } fn run(value: Value) { let case Value::Item(item) = value else item; }";
7317
        let result = try resolveProgramStr(&mut a, program);
7318
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("item"));
7319
    }
7320
}
7321
7322
/// Unsafe pointer dereference requires an unsafe declaration.
7323
@test unsafe fn testUnsafePointerOperationRejected() throws (testing::TestError) {
7324
    let mut testArena512 = testArena();
7325
    let testStorage512: 'test512 = &mut testArena512 in {
7326
        let mut a = testResolver(testStorage512);
7327
        let program = "record Marker: Once {} fn load(pointer: *unsafe u32) -> u32 { return *pointer; }";
7328
        let result = try resolveProgramStr(&mut a, program);
7329
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7330
    }
7331
}
7332
7333
/// Unsafe pointers remain freely copyable inside an unsafe declaration.
7334
@test unsafe fn testUnsafePointerOperationAllowed() throws (testing::TestError) {
7335
    let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; }";
7336
    try expectAnalyzeOk(program);
7337
}
7338
7339
/// Safe code cannot call a function that accepts unsafe operations.
7340
@test unsafe fn testUnsafeFunctionCallRejected() throws (testing::TestError) {
7341
    let mut testArena513 = testArena();
7342
    let testStorage513: 'test513 = &mut testArena513 in {
7343
        let mut a = testResolver(testStorage513);
7344
        let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } fn run(pointer: *unsafe u32) -> u32 { return load(pointer); }";
7345
        let result = try resolveProgramStr(&mut a, program);
7346
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7347
    }
7348
}
7349
7350
/// Unsafe function values retain their call-site safety requirement.
7351
@test unsafe fn testUnsafeFunctionAliasCallRejected() throws (testing::TestError) {
7352
    let mut testArena514 = testArena();
7353
    let testStorage514: 'test514 = &mut testArena514 in {
7354
        let mut a = testResolver(testStorage514);
7355
        let program = "unsafe fn dangerous() -> u32 { return 42; } fn run() -> u32 { let alias = dangerous; return alias(); }";
7356
        let result = try resolveProgramStr(&mut a, program);
7357
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7358
    }
7359
}
7360
7361
/// References cannot be embedded in aggregate fields.
7362
@test unsafe fn testRefFieldRejected() throws (testing::TestError) {
7363
    let mut testArena515 = testArena();
7364
    let testStorage515: 'test515 = &mut testArena515 in {
7365
        let mut a = testResolver(testStorage515);
7366
        let program = "record Marker: Once {} record Bad { value: &u32 }";
7367
        let result = try resolveProgramStr(&mut a, program);
7368
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7369
    }
7370
}
7371
7372
/// Trait methods may use reference receivers.
7373
@test unsafe fn testTraitRefReceiver() throws (testing::TestError) {
7374
    let program = "record Marker: Once {} record Value { number: i32 } trait Read { fn (&Read) get() -> i32; } instance Read for Value { fn (value: &Value) get() -> i32 { return value.number; } } fn inspect(object: &opaque Read) -> i32 { return object.get(); } fn call(value: &Value) -> i32 { return inspect(value); }";
7375
    try expectAnalyzeOk(program);
7376
}
7377
7378
/// Trait implementations must preserve the receiver pointer class.
7379
@test unsafe fn testTraitReceiverClassMismatch() throws (testing::TestError) {
7380
    let mut testArena516 = testArena();
7381
    let testStorage516: 'test516 = &mut testArena516 in {
7382
        let mut a = testResolver(testStorage516);
7383
        let program = "record Value { number: i32 } trait Read { fn (&Read) get() -> i32; } instance Read for Value { fn (value: *Value) get() -> i32 { return value.number; } }";
7384
        let result = try resolveProgramStr(&mut a, program);
7385
        try expectErrorKind(&result, super::ErrorKind::TraitReceiverMismatch);
7386
    }
7387
}
7388
7389
/// Unmarked composite values may be discarded.
7390
@test unsafe fn testAffineCompositeMayBeDiscarded() throws (testing::TestError) {
7391
    let program = "record Value { number: u32 } fn run() { let value = Value { number: 1 }; }";
7392
    try expectAnalyzeOk(program);
7393
}
7394
7395
/// A by-value use moves an unmarked composite value.
7396
@test unsafe fn testAffineCompositeUseAfterMoveRejected() throws (testing::TestError) {
7397
    let mut testArena517 = testArena();
7398
    let testStorage517: 'test517 = &mut testArena517 in {
7399
        let mut a = testResolver(testStorage517);
7400
        let program = "record Value { number: u32 } fn take(value: Value) {} fn run() { let value = Value { number: 1 }; take(value); take(value); }";
7401
        let result = try resolveProgramStr(&mut a, program);
7402
        try expectErrorKind(&result, super::ErrorKind::AffineUseAfterMove("value"));
7403
    }
7404
}
7405
7406
/// Affine values may move on only one branch when not used later.
7407
@test unsafe fn testAffineConditionalMoveMayBeDiscarded() throws (testing::TestError) {
7408
    let program = "record Value { number: u32 } fn take(value: Value) {} fn run(condition: bool) { let value = Value { number: 1 }; if condition { take(value); } }";
7409
    try expectAnalyzeOk(program);
7410
}
7411
7412
/// A `Copy` composite remains available after a by-value use.
7413
@test unsafe fn testCopyCompositeMayBeReused() throws (testing::TestError) {
7414
    let program = "record Value: Copy { number: u32 } fn take(value: Value) {} fn run() { let value = Value { number: 1 }; take(value); take(value); }";
7415
    try expectAnalyzeOk(program);
7416
}
7417
7418
/// A `Copy` composite may contain only copy values.
7419
@test unsafe fn testCopyCompositeRejectsAffineField() throws (testing::TestError) {
7420
    let mut testArena518 = testArena();
7421
    let testStorage518: 'test518 = &mut testArena518 in {
7422
        let mut a = testResolver(testStorage518);
7423
        let program = "record Inner { number: u32 } record Outer: Copy { inner: Inner }";
7424
        let result = try resolveProgramStr(&mut a, program);
7425
        try expectErrorKind(&result, super::ErrorKind::CopyContainsNonCopy);
7426
    }
7427
}
7428
7429
/// A composite cannot carry conflicting ownership markers.
7430
@test unsafe fn testConflictingOwnershipMarkersRejected() throws (testing::TestError) {
7431
    let mut testArena519 = testArena();
7432
    let testStorage519: 'test519 = &mut testArena519 in {
7433
        let mut a = testResolver(testStorage519);
7434
        let program = "record Value: Copy + Once { number: u32 }";
7435
        let result = try resolveProgramStr(&mut a, program);
7436
        try expectErrorKind(&result, super::ErrorKind::ConflictingOwnershipMarkers);
7437
    }
7438
}
7439
7440
/// Linear composites still require one consuming use.
7441
@test unsafe fn testLinearCompositeMustBeConsumed() throws (testing::TestError) {
7442
    let mut testArena520 = testArena();
7443
    let testStorage520: 'test520 = &mut testArena520 in {
7444
        let mut a = testResolver(testStorage520);
7445
        let program = "record Token: Once { number: u32 } fn run() { let token = Token { number: 1 }; }";
7446
        let result = try resolveProgramStr(&mut a, program);
7447
        try expectErrorKind(&result, super::ErrorKind::LinearNotConsumed("token"));
7448
    }
7449
}
7450
7451
/// The compiler-known marker cannot be derived more than once.
7452
@test unsafe fn testDuplicateOnceMarkerRejected() throws (testing::TestError) {
7453
    let mut testArena521 = testArena();
7454
    let testStorage521: 'test521 = &mut testArena521 in {
7455
        let mut a = testResolver(testStorage521);
7456
        let program = "record Token: Once + Once { value: u32 }";
7457
        let result = try resolveProgramStr(&mut a, program);
7458
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("Once"));
7459
    }
7460
}
7461
7462
/// Stack storage cannot produce a safe stored pointer or slice.
7463
@test unsafe fn testStackPointerRejected() throws (testing::TestError) {
7464
    let programs = &[
7465
        "fn run() { let value: u32 = 0; let pointer: *u32 = &value; }",
7466
        "fn run() -> *u32 { let value: u32 = 0; return &value; }",
7467
        "fn run(value: u32) -> *u32 { return &value; }",
7468
        "record Cell { value: u32 } fn run() { let cell = Cell { value: 1 }; let pointer: *u32 = &(cell.value); }",
7469
        "fn run() { let values = [1, 2]; let pointer: *i32 = &values[0]; }",
7470
        "fn run() { let values = [1, 2]; let slice: *[i32] = &values[..]; }",
7471
        "fn run(value: i32) { let slice: *[i32] = &[value]; }",
7472
        "fn run(value: &u32) -> *u32 { return value; }",
7473
        "fn run(value: &u32) -> *u32 { return &*value; }",
7474
        "fn run(values: &[u32]) -> *[u32] { return values; }",
7475
        "fn run(values: &[u32]) -> *[u32] { return &values[..]; }",
7476
        "fn run(values: &[u32]) -> *u32 { return values.ptr; }",
7477
        "fn run() -> *i32 { return &[1, 2][0]; }",
7478
        "fn run() -> *[i32] { return &[1, 2][..]; }",
7479
        "fn run(value: *u32) -> **u32 { return &value; }",
7480
        "fn run(values: *[u32]) -> *u32 { return &values.len; }",
7481
        "unsafe fn run(value: *unsafe u32) -> *u32 { return &*value; }",
7482
        "fn run() { let value: u32 = 7; let pointer: *unsafe u32 = &value; }",
7483
        "record Cell { value: u32 } fn run(value: &Cell) -> *u32 { return &value.value; }",
7484
        "record Cell { value: *u32 } fn run(value: &u32) -> Cell { return Cell { value }; }",
7485
        "fn run(value: &u32) -> *[u32] { return @sliceOf(value, 1); }",
7486
    ];
7487
    for program in programs {
7488
        let mut testArena522 = testArena();
7489
        let testStorage522: 'test522 = &mut testArena522 in {
7490
            let mut resolver = testResolver(testStorage522);
7491
            let result = try resolveProgramStr(&mut resolver, program);
7492
            let _ = try expectError(&result);
7493
        }
7494
    }
7495
}
7496
7497
/// Stack values can be borrowed for a call.
7498
@test unsafe fn testStackBorrowAllowed() throws (testing::TestError) {
7499
    try expectAnalyzeOk("fn read(value: &u32) -> u32 { return *value; } fn run() -> u32 { let value: u32 = 7; return read(&value); }");
7500
    try expectAnalyzeOk("fn write(values: &mut [u32]) { set values[0] = 7; } fn run() { let mut values: [u32; 2] = [1, 2]; write(&mut values[..]); }");
7501
}
7502
7503
/// Raw pointers and slices can be borrowed in an unsafe context.
7504
@test unsafe fn testImplicitRawBorrowAllowed() throws (testing::TestError) {
7505
    let programs = &[
7506
        "fn read(p: &u32) -> u32 { return *p; } unsafe fn run(p: *unsafe u32) -> u32 { return read(p); }",
7507
        "fn write(p: &mut u32) { set *p = 7; } fn run(p: *unsafe mut u32) { unsafe { write(p); write(p); } }",
7508
        "fn read(p: &[u32]) -> u32 { return p[0]; } unsafe fn run(p: *unsafe [u32]) -> u32 { return read(p); }",
7509
        "fn write(p: &mut [u32]) { set p[0] = 7; } unsafe fn run(p: *unsafe mut [u32]) { write(p); write(p); }",
7510
        "fn read(p: &u32) {} unsafe fn run(p: *unsafe mut u32) { read(p); }",
7511
        "trait Read { fn (&Read) get(); } fn read(p: &opaque Read) {} unsafe fn run(p: *unsafe opaque Read) { read(p); }",
7512
    ];
7513
    for program in programs {
7514
        try expectAnalyzeOk(program);
7515
    }
7516
}
7517
7518
/// An implicit borrow of raw storage requires an unsafe context.
7519
@test unsafe fn testImplicitRawBorrowRequiresUnsafe() throws (testing::TestError) {
7520
    let programs = &[
7521
        "fn read(p: &u32) {} fn run(p: *unsafe u32) { read(p); }",
7522
        "fn write(p: &mut u32) {} fn run(p: *unsafe mut u32) { write(p); }",
7523
        "fn read(p: &[u32]) {} fn run(p: *unsafe [u32]) { read(p); }",
7524
        "fn write(p: &mut [u32]) {} fn run(p: *unsafe mut [u32]) { write(p); }",
7525
        "trait Read { fn (&Read) get(); } fn read(p: &opaque Read) {} fn run(p: *unsafe opaque Read) { read(p); }",
7526
        "fn read(p: &u32) {} fn run(p: *unsafe u32) { unsafe { read(p); } read(p); }",
7527
    ];
7528
    for program in programs {
7529
        let mut testArena523 = testArena();
7530
        let testStorage523: 'test523 = &mut testArena523 in {
7531
            let mut a = testResolver(testStorage523);
7532
            let result = try resolveProgramStr(&mut a, program);
7533
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7534
        }
7535
    }
7536
}
7537
7538
/// Raw borrows preserve mutability, storage type, and ownership constraints.
7539
@test unsafe fn testImplicitRawBorrowPreservesTypes() throws (testing::TestError) {
7540
    let programs = &[
7541
        "fn write(p: &mut u32) {} unsafe fn run(p: *unsafe u32) { write(p); }",
7542
        "fn write(p: &mut [u32]) {} unsafe fn run(p: *unsafe [u32]) { write(p); }",
7543
        "fn read(p: &u64) {} unsafe fn run(p: *unsafe u32) { read(p); }",
7544
        "fn read(p: &[u64]) {} unsafe fn run(p: *unsafe [u32]) { read(p); }",
7545
        "fn take(p: *u32) {} unsafe fn run(p: *unsafe u32) { take(p); }",
7546
        "fn take(p: *[u32]) {} unsafe fn run(p: *unsafe [u32]) { take(p); }",
7547
        "fn read(p: &*u32) {} unsafe fn run(p: *unsafe *unsafe u32) { read(p); }",
7548
    ];
7549
    for program in programs {
7550
        let mut testArena524 = testArena();
7551
        let testStorage524: 'test524 = &mut testArena524 in {
7552
            let mut a = testResolver(testStorage524);
7553
            let result = try resolveProgramStr(&mut a, program);
7554
            let err = try expectError(&result);
7555
            let case super::ErrorKind::TypeMismatch(_) = err.kind
7556
                else throw testing::TestError::Failed;
7557
        }
7558
    }
7559
}
7560
7561
/// Implicit raw borrows retain the call's exclusive-borrow checks.
7562
@test unsafe fn testImplicitRawBorrowConflict() throws (testing::TestError) {
7563
    let mut testArena525 = testArena();
7564
    let testStorage525: 'test525 = &mut testArena525 in {
7565
        let mut a = testResolver(testStorage525);
7566
        let result = try resolveProgramStr(&mut a,
7567
            "fn useBoth(a: &mut u32, b: &u32) {} unsafe fn run(p: *unsafe mut u32) { useBoth(p, p); }");
7568
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("p"));
7569
    }
7570
}
7571
7572
/// Unsafe declarations can store raw pointers to stack values.
7573
@test unsafe fn testUnsafeStackPointerAllowed() throws (testing::TestError) {
7574
    try expectAnalyzeOk("unsafe fn run() { let mut value: u32 = 0; let pointer: *unsafe mut u32 = &mut value as *unsafe mut u32; set *pointer = 7; }");
7575
    try expectAnalyzeOk("unsafe fn run() { let mut values: [u32; 2] = [1, 2]; let slice: *unsafe mut [u32] = &mut values[..] as *unsafe mut [u32]; set slice[0] = 7; }");
7576
    try expectAnalyzeOk("unsafe fn run() { let value: u32 = 7; let pointer: *unsafe u32 = &value; }");
7577
    try expectAnalyzeOk("unsafe fn run() { let values: [u32; 2] = [1, 2]; let slice: *unsafe [u32] = &values[..]; }");
7578
}
7579
7580
/// Permanent storage can produce safe stored pointers and slices.
7581
@test unsafe fn testPermanentPointerAllowed() throws (testing::TestError) {
7582
    try expectAnalyzeOk("static VALUE: u32 = 7; fn run() -> *u32 { return &VALUE; }");
7583
    try expectAnalyzeOk("static VALUES: [u32; 2] = [1, 2]; fn run() -> *[u32] { return &VALUES[..]; }");
7584
    try expectAnalyzeOk("fn run() -> *[u32] { return &[1, 2]; }");
7585
    try expectAnalyzeOk("fn run(value: *u32) -> *u32 { return &*value; }");
7586
    try expectAnalyzeOk("fn run(values: *[u32]) -> *[u32] { return &values[..]; }");
7587
    try expectAnalyzeOk("record Cell { value: u32 } fn run(value: *Cell) -> *u32 { return &value.value; }");
7588
    try expectAnalyzeOk("fn run(values: *[u32]) -> *u32 { return &values[0]; }");
7589
    try expectAnalyzeOk("unsafe fn run(values: *[u32]) -> *u32 { return values.ptr; }");
7590
    try expectAnalyzeOk("unsafe fn run(value: *u32) -> *[u32] { return @sliceOf(value, 1); }");
7591
}
7592
7593
/// References are rejected from every nested or storable type position.
7594
@test unsafe fn testNestedRefPositionsRejected() throws (testing::TestError) {
7595
    {
7596
        let mut testArena526 = testArena();
7597
        let testStorage526: 'test526 = &mut testArena526 in {
7598
            let mut a = testResolver(testStorage526);
7599
            let program = "record Marker: Once {} union Bad { Value(&u32) }";
7600
            let result = try resolveProgramStr(&mut a, program);
7601
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7602
        }
7603
    } {
7604
        let mut testArena527 = testArena();
7605
        let testStorage527: 'test527 = &mut testArena527 in {
7606
            let mut a = testResolver(testStorage527);
7607
            let program = "record Marker: Once {} fn bad(value: ?&u32) {}";
7608
            let result = try resolveProgramStr(&mut a, program);
7609
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7610
        }
7611
    } {
7612
        let mut testArena528 = testArena();
7613
        let testStorage528: 'test528 = &mut testArena528 in {
7614
            let mut a = testResolver(testStorage528);
7615
            let program = "record Marker: Once {} fn bad(value: [&u32; 1]) {}";
7616
            let result = try resolveProgramStr(&mut a, program);
7617
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7618
        }
7619
    } {
7620
        let mut testArena529 = testArena();
7621
        let testStorage529: 'test529 = &mut testArena529 in {
7622
            let mut a = testResolver(testStorage529);
7623
            let program = "record Marker: Once {} fn bad(value: *&u32) {}";
7624
            let result = try resolveProgramStr(&mut a, program);
7625
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7626
        }
7627
    } {
7628
        let mut testArena530 = testArena();
7629
        let testStorage530: 'test530 = &mut testArena530 in {
7630
            let mut a = testResolver(testStorage530);
7631
            let program = "record Marker: Once {} static BAD: &u32 = undefined;";
7632
            let result = try resolveProgramStr(&mut a, program);
7633
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7634
        }
7635
    } {
7636
        let mut testArena531 = testArena();
7637
        let testStorage531: 'test531 = &mut testArena531 in {
7638
            let mut a = testResolver(testStorage531);
7639
            let program = "record Marker: Once {} fn bad(callback: fn() -> &u32) {}";
7640
            let result = try resolveProgramStr(&mut a, program);
7641
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7642
        }
7643
    }
7644
}
7645
7646
/// Function pointer parameter references remain call-scoped and valid.
7647
@test unsafe fn testFunctionPointerRefParameterAllowed() throws (testing::TestError) {
7648
    let program = "record Marker: Once {} fn invoke(callback: fn(&u32), value: &u32) { callback(value); }";
7649
    try expectAnalyzeOk(program);
7650
}
7651
7652
/// Pointer and slice casts cannot change reference ownership.
7653
@test unsafe fn testRefCastClassPreserved() throws (testing::TestError) {
7654
    {
7655
        let mut testArena532 = testArena();
7656
        let testStorage532: 'test532 = &mut testArena532 in {
7657
            let mut a = testResolver(testStorage532);
7658
            let program = "record Marker: Once {} fn cast(value: &u32) { value as *u32; }";
7659
            let result = try resolveProgramStr(&mut a, program);
7660
            let err = try expectError(&result);
7661
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
7662
                else throw testing::TestError::Failed;
7663
        }
7664
    } {
7665
        let mut testArena533 = testArena();
7666
        let testStorage533: 'test533 = &mut testArena533 in {
7667
            let mut a = testResolver(testStorage533);
7668
            let program = "record Marker: Once {} fn cast(values: &[u32]) { values as *[u32]; }";
7669
            let result = try resolveProgramStr(&mut a, program);
7670
            let err = try expectError(&result);
7671
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
7672
                else throw testing::TestError::Failed;
7673
        }
7674
    }
7675
}
7676
7677
/// Every operation that interprets an unsafe address requires an unsafe declaration.
7678
@test unsafe fn testUnsafePointerOperationsRejected() throws (testing::TestError) {
7679
    {
7680
        let mut testArena534 = testArena();
7681
        let testStorage534: 'test534 = &mut testArena534 in {
7682
            let mut a = testResolver(testStorage534);
7683
            let program = "record Marker: Once {} fn cast(pointer: *unsafe u32) -> u64 { return pointer as u64; }";
7684
            let result = try resolveProgramStr(&mut a, program);
7685
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7686
        }
7687
    } {
7688
        let mut testArena535 = testArena();
7689
        let testStorage535: 'test535 = &mut testArena535 in {
7690
            let mut a = testResolver(testStorage535);
7691
            let program = "record Marker: Once {} fn compare(pointer: *unsafe u32) -> bool { return pointer == pointer; }";
7692
            let result = try resolveProgramStr(&mut a, program);
7693
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7694
        }
7695
    } {
7696
        let mut testArena536 = testArena();
7697
        let testStorage536: 'test536 = &mut testArena536 in {
7698
            let mut a = testResolver(testStorage536);
7699
            let program = "record Marker: Once {} fn offset(pointer: *unsafe u32) -> *unsafe u32 { return pointer + 1; }";
7700
            let result = try resolveProgramStr(&mut a, program);
7701
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7702
        }
7703
    } {
7704
        let mut testArena537 = testArena();
7705
        let testStorage537: 'test537 = &mut testArena537 in {
7706
            let mut a = testResolver(testStorage537);
7707
            let program = "record Marker: Once {} fn index(values: *unsafe [u32]) -> u32 { return values[0]; }";
7708
            let result = try resolveProgramStr(&mut a, program);
7709
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7710
        }
7711
    } {
7712
        let mut testArena538 = testArena();
7713
        let testStorage538: 'test538 = &mut testArena538 in {
7714
            let mut a = testResolver(testStorage538);
7715
            let program = "record Marker: Once {} record Cell { value: u32 } fn field(cell: *unsafe Cell) -> u32 { return cell.value; }";
7716
            let result = try resolveProgramStr(&mut a, program);
7717
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7718
        }
7719
    } {
7720
        let mut testArena539 = testArena();
7721
        let testStorage539: 'test539 = &mut testArena539 in {
7722
            let mut a = testResolver(testStorage539);
7723
            let program = "record Marker: Once {} fn store(pointer: *unsafe mut u32) { set *pointer = 1; }";
7724
            let result = try resolveProgramStr(&mut a, program);
7725
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7726
        }
7727
    } {
7728
        let mut testArena540 = testArena();
7729
        let testStorage540: 'test540 = &mut testArena540 in {
7730
            let mut a = testResolver(testStorage540);
7731
            let program = "record Marker: Once {} fn cast() { let value: u32 = 0; let pointer = &value as *unsafe u32; }";
7732
            let result = try resolveProgramStr(&mut a, program);
7733
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7734
        }
7735
    }
7736
}
7737
7738
/// Pointer offsets require an unsafe function for either operand order.
7739
@test unsafe fn testPointerArithmeticRequiresUnsafe() throws (testing::TestError) {
7740
    let programs = &[
7741
        "fn run(p: *u8) -> *u8 { return p + 1; }",
7742
        "fn run(p: *u8) -> *u8 { return 1 + p; }",
7743
        "fn run(p: *u8) -> *u8 { return p - 1; }",
7744
        "fn run(input: *mut u8) { let mut p = input; set p += 1; }",
7745
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let p = &DATA[0]; return *(p + 1); }",
7746
    ];
7747
    for program in programs {
7748
        let mut testArena541 = testArena();
7749
        let testStorage541: 'test541 = &mut testArena541 in {
7750
            let mut a = testResolver(testStorage541);
7751
            let result = try resolveProgramStr(&mut a, program);
7752
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7753
        }
7754
    }
7755
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return p + 1; }");
7756
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return 1 + p; }");
7757
    try expectAnalyzeOk("unsafe fn run(p: *mut u8) -> *mut u8 { return p - 1; }");
7758
    try expectAnalyzeOk("fn run(value: u32) -> u32 { return value + 1; }");
7759
}
7760
7761
/// Casts that reinterpret storage require an unsafe function.
7762
@test unsafe fn testStorageCastsRequireUnsafe() throws (testing::TestError) {
7763
    let programs = &[
7764
        "fn run(p: *u8) -> *u64 { return p as *u64; }",
7765
        "fn run(p: &u8) -> u64 { return *(p as &u64); }",
7766
        "fn run(p: *mut u8) -> *mut u64 { return p as *mut u64; }",
7767
        "fn run(p: *opaque) -> *u64 { return p as *u64; }",
7768
        "fn run(p: **u8) -> **u64 { return p as **u64; }",
7769
        "fn run(s: *[u8]) -> *[u64] { return s as *[u64]; }",
7770
        "fn run(s: *[opaque]) -> *[u64] { return s as *[u64]; }",
7771
        "fn run(s: &mut [u64]) { let _ = s as &mut [u8]; }",
7772
        "static DATA: [u8; 1] = [42]; fn run() -> u64 { return *(&DATA[0] as *u64); }",
7773
    ];
7774
    for program in programs {
7775
        let mut testArena542 = testArena();
7776
        let testStorage542: 'test542 = &mut testArena542 in {
7777
            let mut a = testResolver(testStorage542);
7778
            let result = try resolveProgramStr(&mut a, program);
7779
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7780
        }
7781
    }
7782
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u64 { return p as *u64; }");
7783
    try expectAnalyzeOk("unsafe fn run(p: &u8) -> u64 { return *(p as &u64); }");
7784
    try expectAnalyzeOk("unsafe fn run(s: *[u8]) -> *[u64] { return s as *[u64]; }");
7785
    try expectAnalyzeOk("fn run(p: *u8) -> *u8 { return p as *u8; }");
7786
    try expectAnalyzeOk("fn run(p: *u8) -> *opaque { return p as *opaque; }");
7787
    try expectAnalyzeOk("fn run(s: *[u8]) -> *[opaque] { return s as *[opaque]; }");
7788
    try expectAnalyzeOk("fn run(p: *mut u8) -> *u8 { return p as *u8; }");
7789
}
7790
7791
/// Explicit slice bounds require an unsafe function.
7792
@test unsafe fn testSliceConstructionRequiresUnsafe() throws (testing::TestError) {
7793
    let programs = &[
7794
        "fn run(p: *u8) -> *[u8] { return @sliceOf(p, 100); }",
7795
        "fn run(p: *mut u8) -> *mut [u8] { return @sliceOf(p, 0, 100); }",
7796
        "fn run(p: &u8) -> u8 { return @sliceOf(p, 100)[99]; }",
7797
        "fn run(p: &mut u8) { set @sliceOf(p, 100)[99] = 1; }",
7798
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let s = @sliceOf(&DATA[0], 100); return s[99]; }",
7799
    ];
7800
    for program in programs {
7801
        let mut testArena543 = testArena();
7802
        let testStorage543: 'test543 = &mut testArena543 in {
7803
            let mut a = testResolver(testStorage543);
7804
            let result = try resolveProgramStr(&mut a, program);
7805
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7806
        }
7807
    }
7808
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *[u8] { return @sliceOf(p, 100); }");
7809
    try expectAnalyzeOk("unsafe fn run(p: *mut u8) -> *mut [u8] { return @sliceOf(p, 0, 100); }");
7810
    try expectAnalyzeOk("unsafe fn run(p: &u8) -> u8 { return @sliceOf(p, 1)[0]; }");
7811
    try expectAnalyzeOk("fn run(s: *[u8]) -> *[u8] { return &s[..]; }");
7812
}
7813
7814
/// Slice header writes and mutable field borrows require an unsafe function.
7815
@test unsafe fn testSliceHeaderMutationRequiresUnsafe() throws (testing::TestError) {
7816
    let programs = &[
7817
        "fn run(s: *mut [u8]) { set s.len = 100; }",
7818
        "fn run(s: *mut [u8]) { set s.cap = 100; }",
7819
        "fn run(s: *mut [u8], p: *mut u8) { set s.ptr = p; }",
7820
        "fn run(s: *mut [u8]) { set s.len += 1; }",
7821
        "fn change(n: &mut u32) { set *n = 100; } fn run(s: *mut [u8]) { change(&mut s.len); }",
7822
        "fn change(n: &mut u32) { set *n = 100; } fn run(s: *mut [u8]) { change(&mut s.cap); }",
7823
        "fn change(p: &mut *u8, q: *u8) { set *p = q; } fn run(q: *u8) { let mut s: *[u8] = &[]; change(&mut s.ptr, q); }",
7824
        "fn run(s: &mut *[u8]) { set s.len = 100; }",
7825
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let mut s = &DATA[..]; set s.len = 100; return s[99]; }",
7826
    ];
7827
    for program in programs {
7828
        let mut testArena544 = testArena();
7829
        let testStorage544: 'test544 = &mut testArena544 in {
7830
            let mut a = testResolver(testStorage544);
7831
            let result = try resolveProgramStr(&mut a, program);
7832
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7833
        }
7834
    }
7835
    try expectAnalyzeOk("unsafe fn run(s: *mut [u8]) { set s.len = 0; set s.cap = 0; }");
7836
    try expectAnalyzeOk("unsafe fn run(s: *mut [u8], p: *mut u8) { set s.ptr = p; }");
7837
    try expectAnalyzeOk("fn change(n: &mut u32) { set *n = 0; } unsafe fn run(s: *mut [u8]) { change(&mut s.len); }");
7838
    try expectAnalyzeOk("fn run(s: *mut [u8]) { set s[0] = 1; }");
7839
    try expectAnalyzeOk("record R { len: u32 } fn run(r: &mut R) { set r.len = 1; }");
7840
}
7841
7842
/// Unsafe blocks permit operations within a safe function.
7843
@test unsafe fn testUnsafeBlocksAllowed() throws (testing::TestError) {
7844
    try expectAnalyzeOk("fn run(p: *u8) -> *u8 { unsafe { return p + 1; } }");
7845
    try expectAnalyzeOk("unsafe fn read(p: *unsafe u8) -> u8 { return *p; } fn run(p: *unsafe u8) -> u8 { unsafe { return read(p); } }");
7846
    try expectAnalyzeOk("fn run(p: *u8) -> *[u8] { unsafe { { return @sliceOf(p, 1); } } }");
7847
    try expectAnalyzeOk("fn run(p: *u8) -> *u64 { unsafe { unsafe { return p as *u64; } } }");
7848
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { unsafe {} return p + 1; }");
7849
}
7850
7851
/// Unsafe permission ends at the closing brace and at function boundaries.
7852
@test unsafe fn testUnsafeBlockContextRestored() throws (testing::TestError) {
7853
    let programs = &[
7854
        "fn run(p: *u8) -> *u8 { unsafe { let q = p + 1; } return p + 1; }",
7855
        "fn run(p: *u8) -> *u8 { unsafe { unsafe {} } return p + 1; }",
7856
        "unsafe fn first(p: *u8) -> *u8 { return p + 1; } fn second(p: *u8) -> *u8 { return p + 1; }",
7857
    ];
7858
    for program in programs {
7859
        let mut testArena545 = testArena();
7860
        let testStorage545: 'test545 = &mut testArena545 in {
7861
            let mut a = testResolver(testStorage545);
7862
            let result = try resolveProgramStr(&mut a, program);
7863
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7864
        }
7865
    }
7866
    let mut testArena546 = testArena();
7867
    let testStorage546: 'test546 = &mut testArena546 in {
7868
        let mut a = testResolver(testStorage546);
7869
        let result = try resolveProgramStr(&mut a, "unsafe fn act() {} fn run() { unsafe { act(); } act(); }");
7870
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7871
    }
7872
}
7873
7874
/// Resolution errors do not extend an unsafe block's permission.
7875
@test unsafe fn testUnsafeBlockErrorRestoresContext() throws (testing::TestError) {
7876
    let mut testArena547 = testArena();
7877
    let testStorage547: 'test547 = &mut testArena547 in {
7878
        let mut a = testResolver(testStorage547);
7879
        let result = try resolveProgramStr(&mut a, "fn run(p: *u8) { unsafe { missing; } let q = p + 1; }");
7880
        let mut found = false;
7881
        for err in result.diagnostics.errors {
7882
            if let case super::ErrorKind::UnsafeOperation = err.kind {
7883
                set found = true;
7884
            }
7885
        }
7886
        try testing::expect(found);
7887
    }
7888
}
7889
7890
/// Unsafe blocks preserve reference lifetime checks.
7891
@test unsafe fn testUnsafeBlockPreservesReferences() throws (testing::TestError) {
7892
    let mut testArena548 = testArena();
7893
    let testStorage548: 'test548 = &mut testArena548 in {
7894
        let mut a = testResolver(testStorage548);
7895
        let result = try resolveProgramStr(&mut a, "fn run() { let mut n: u32 = 1; let p = &n; unsafe { set n = 2; } }");
7896
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("n"));
7897
    }
7898
}
7899
7900
/// Slice pointer access requires an unsafe context for every slice class.
7901
@test unsafe fn testSlicePointerRequiresUnsafe() throws (testing::TestError) {
7902
    let programs = &[
7903
        "fn run(s: *[u8]) -> *u8 { return s.ptr; }",
7904
        "fn run(s: *mut [u8]) -> *mut u8 { return s.ptr; }",
7905
        "fn run(s: &[u8]) -> u8 { return *s.ptr; }",
7906
        "fn run(s: &mut [u8]) { set *s.ptr = 1; }",
7907
        "fn run(s: &*[u8]) -> *u8 { return s.ptr; }",
7908
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let s = &DATA[1..]; return *s.ptr; }",
7909
        "fn run(s: *[u8]) -> u64 { return s.ptr as u64; }",
7910
    ];
7911
    for program in programs {
7912
        let mut testArena549 = testArena();
7913
        let testStorage549: 'test549 = &mut testArena549 in {
7914
            let mut a = testResolver(testStorage549);
7915
            let result = try resolveProgramStr(&mut a, program);
7916
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7917
        }
7918
    }
7919
    try expectAnalyzeOk("unsafe fn run(s: *[u8]) -> *u8 { return s.ptr; }");
7920
    try expectAnalyzeOk("fn run(s: *[u8]) -> u64 { unsafe { return s.ptr as u64; } }");
7921
    try expectAnalyzeOk("fn run(s: *[u8]) -> *u8 { return &s[0]; }");
7922
    try expectAnalyzeOk("fn run(s: *[u8]) -> u32 { return s.len + s.cap; }");
7923
    try expectAnalyzeOk("record R { ptr: u32 } fn run(r: R) -> u32 { return r.ptr; }");
7924
}
7925
7926
/// Unsafe statics require unsafe permission for reads, writes, and addresses.
7927
@test unsafe fn testUnsafeStaticAccessRejected() throws (testing::TestError) {
7928
    let programs = &[
7929
        "unsafe static VALUE: u32 = 7; fn run() -> u32 { return VALUE; }",
7930
        "unsafe static VALUE: u32 = 7; fn run() { set VALUE = 8; }",
7931
        "unsafe static VALUE: u32 = 7; fn run() -> *u32 { return &VALUE; }",
7932
        "unsafe static VALUE: u32 = 7; fn run() -> *mut u32 { return &mut VALUE; }",
7933
        "unsafe static DATA: [u8; 1] = [42]; fn run() -> u8 { return DATA[0]; }",
7934
        "unsafe static DATA: [u8; 1] = [42]; fn run() -> u32 { return DATA.len; }",
7935
        "record R { value: u32 } unsafe static DATA: R = R { value: 7 }; fn run() -> u32 { return DATA.value; }",
7936
    ];
7937
    for program in programs {
7938
        let mut testArena550 = testArena();
7939
        let testStorage550: 'test550 = &mut testArena550 in {
7940
            let mut a = testResolver(testStorage550);
7941
            let result = try resolveProgramStr(&mut a, program);
7942
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7943
        }
7944
    }
7945
}
7946
7947
/// Unsafe blocks and functions can access unsafe statics.
7948
@test unsafe fn testUnsafeStaticAccessAllowed() throws (testing::TestError) {
7949
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; unsafe fn run() -> u32 { set VALUE = 8; return VALUE; }");
7950
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; fn run() -> u32 { unsafe { return VALUE; } }");
7951
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; unsafe fn run() -> *mut u32 { return &mut VALUE; }");
7952
    try expectAnalyzeOk("static VALUE: u32 = 7; fn run() -> u32 { return VALUE; }");
7953
    try expectAnalyzeOk("constant BYTES: *[u8] = \"x\"; unsafe static DATA: *[u64] = BYTES as *[u64];");
7954
}
7955
7956
/// Imports preserve the unsafe access requirement of a static.
7957
@test unsafe fn testUnsafeStaticImportsRejected() throws (testing::TestError) {
7958
    let programs = &[
7959
        "use root::storage; fn run() -> u32 { return storage::VALUE; }",
7960
        "use root::storage::*; fn run() -> u32 { return VALUE; }",
7961
    ];
7962
    for program in programs {
7963
        let mut testArena551 = testArena();
7964
        let testStorage551: 'test551 = &mut testArena551 in {
7965
            let mut a = testResolver(testStorage551);
7966
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
7967
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod storage; mod app;", &mut arena);
7968
            let _ = try registerModule(&mut MODULE_GRAPH, rootId, "storage", "export unsafe static VALUE: u32 = 7;", &mut arena);
7969
            let _ = try registerModule(&mut MODULE_GRAPH, rootId, "app", program, &mut arena);
7970
            let result = try resolveModuleTree(&mut a, rootId);
7971
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7972
        }
7973
    }
7974
}
7975
7976
/// An invalid unsafe static initializer does not grant permission to other initializers.
7977
@test unsafe fn testUnsafeStaticInitializerRestoresContext() throws (testing::TestError) {
7978
    let mut testArena552 = testArena();
7979
    let testStorage552: 'test552 = &mut testArena552 in {
7980
        let mut a = testResolver(testStorage552);
7981
        let result = try resolveProgramStr(&mut a, "unsafe static BAD: u32 = true; static DATA: *[u64] = &[1 as u8] as *[u64];");
7982
        let _ = try expectError(&result);
7983
        try testing::expect(not a.inUnsafeContext);
7984
7985
        let mut testArena553 = testArena();
7986
        let testStorage553: 'test553 = &mut testArena553 in {
7987
            let mut b = testResolver(testStorage553);
7988
            let next = try resolveProgramStr(&mut b, "constant BYTES: *[u8] = \"x\"; unsafe static VALUE: u32 = 7; static DATA: *[u64] = BYTES as *[u64];");
7989
            try expectErrorKind(&next, super::ErrorKind::UnsafeOperation);
7990
        }
7991
    }
7992
}
7993
7994
/// Uninitialized values require an explicit unsafe context in every value position.
7995
@test unsafe fn testUndefinedRequiresUnsafe() throws (testing::TestError) {
7996
    let programs = &[
7997
        "fn run() -> u8 { let pointers: [*u8; 1] = undefined; return *pointers[0]; }",
7998
        "fn run() { let n: u32 = undefined; }",
7999
        "fn run() -> *u8 { return undefined; }",
8000
        "fn take(p: *u8) {} fn run() { take(undefined); }",
8001
        "fn run(p: *u8) { let mut q = p; set q = undefined; }",
8002
        "fn run() { let pointers: [*u8; 1] = [undefined]; }",
8003
        "fn run() { let pointers: [*u8; 2] = [undefined; 2]; }",
8004
        "record R: Copy { p: *u8 } fn run() { let r = R { p: undefined }; }",
8005
        "union U: Copy { Value { p: *u8 } } fn run() { let u = U::Value { p: undefined }; }",
8006
        "static P: *u8 = undefined;",
8007
        "constant P: *u8 = undefined;",
8008
        "static DATA: [u8; 4] = undefined;",
8009
        "record R: Copy { p: *u8 } static VALUE: R = R { p: undefined };",
8010
    ];
8011
    for program in programs {
8012
        let mut testArena554 = testArena();
8013
        let testStorage554: 'test554 = &mut testArena554 in {
8014
            let mut a = testResolver(testStorage554);
8015
            let result = try resolveProgramStr(&mut a, program);
8016
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
8017
        }
8018
    }
8019
    try expectAnalyzeOk("unsafe fn run() { let p: *u8 = undefined; }");
8020
    try expectAnalyzeOk("fn run() -> u32 { unsafe { let mut n: u32 = undefined; set n = 7; return n; } }");
8021
    try expectAnalyzeOk("unsafe static P: *u8 = undefined;");
8022
    try expectAnalyzeOk("record R: Copy { p: *u8 } unsafe static VALUE: R = R { p: undefined };");
8023
    try expectAnalyzeOk("fn run() { let data: [u8; 4] = [0; 4]; let pointer: ?*u8 = nil; }");
8024
    try expectAnalyzeOk("static DATA: [u8; 4] = [0; 4];");
8025
}
8026
8027
/// Unsafe initialization does not grant permission to subsequent safe expressions.
8028
@test unsafe fn testUndefinedContextRestored() throws (testing::TestError) {
8029
    let mut testArena555 = testArena();
8030
    let testStorage555: 'test555 = &mut testArena555 in {
8031
        let mut a = testResolver(testStorage555);
8032
        let result = try resolveProgramStr(&mut a, "fn run() { unsafe { let p: *u8 = undefined; } let q: *u8 = undefined; }");
8033
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
8034
        let mut testArena556 = testArena();
8035
        let testStorage556: 'test556 = &mut testArena556 in {
8036
            let mut b = testResolver(testStorage556);
8037
            let next = try resolveProgramStr(&mut b, "unsafe static P: *u8 = undefined; static Q: *u8 = undefined;");
8038
            try expectErrorKind(&next, super::ErrorKind::UnsafeOperation);
8039
        }
8040
    }
8041
}
8042
8043
/// Unsafe declarations may compose unsafe operations and calls.
8044
@test unsafe fn testUnsafePointerOperationsAllowed() throws (testing::TestError) {
8045
    let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } unsafe fn run(pointer: *unsafe u32) -> u32 { let next = pointer + 1; let same = pointer == next; return load(pointer); }";
8046
    try expectAnalyzeOk(program);
8047
}
8048
8049
/// Unsafe code may drop a checked reference to an unsafe pointer.
8050
@test unsafe fn testUnsafePointerFromReference() throws (testing::TestError) {
8051
    let program = "record Marker: Once {} unsafe fn store(pointer: *unsafe mut u32) { set *pointer = 42; } unsafe fn run() { let mut value: u32 = 0; store(&mut value as *unsafe mut u32); }";
8052
    try expectAnalyzeOk(program);
8053
}
8054
8055
/// Dropping a reference to an unsafe pointer cannot add mutability.
8056
@test unsafe fn testUnsafePointerCastCannotAddMutability() throws (testing::TestError) {
8057
    let mut testArena557 = testArena();
8058
    let testStorage557: 'test557 = &mut testArena557 in {
8059
        let mut a = testResolver(testStorage557);
8060
        let program = "record Marker: Once {} unsafe fn run(value: &u32) { value as *unsafe mut u32; }";
8061
        let result = try resolveProgramStr(&mut a, program);
8062
        let err = try expectError(&result);
8063
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
8064
            else throw testing::TestError::Failed;
8065
    }
8066
}
8067
8068
/// Recursive cast validation cannot hide a checked-to-unsafe transition.
8069
@test unsafe fn testNestedUnsafePointerCastRejected() throws (testing::TestError) {
8070
    let mut testArena558 = testArena();
8071
    let testStorage558: 'test558 = &mut testArena558 in {
8072
        let mut a = testResolver(testStorage558);
8073
        let program = "record Marker: Once {} fn run(value: **u32) { value as **unsafe u32; }";
8074
        let result = try resolveProgramStr(&mut a, program);
8075
        let err = try expectError(&result);
8076
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
8077
            else throw testing::TestError::Failed;
8078
    }
8079
}
8080
8081
/// Unsafe code may drop a checked slice reference to an unsafe slice.
8082
@test unsafe fn testUnsafeSliceFromReference() throws (testing::TestError) {
8083
    let program = "record Marker: Once {} unsafe fn run(values: &[u32]) { let raw: *unsafe [u32] = values as *unsafe [u32]; }";
8084
    try expectAnalyzeOk(program);
8085
}
8086
8087
/// Slice casts cannot add mutability.
8088
@test unsafe fn testSliceCastCannotAddMutability() throws (testing::TestError) {
8089
    let mut testArena559 = testArena();
8090
    let testStorage559: 'test559 = &mut testArena559 in {
8091
        let mut a = testResolver(testStorage559);
8092
        let program = "record Marker: Once {} fn run(values: &[u32]) { values as &mut [u32]; }";
8093
        let result = try resolveProgramStr(&mut a, program);
8094
        let err = try expectError(&result);
8095
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
8096
            else throw testing::TestError::Failed;
8097
    }
8098
}
8099
8100
/// Mutable unsafe receivers do not create checked exclusive loans.
8101
@test unsafe fn testUnsafeReceiverDoesNotBorrowExclusively() throws (testing::TestError) {
8102
    let program = "record Marker: Once {} record Value { number: u32 } unsafe fn (value: *unsafe mut Value) update(other: *unsafe mut Value) {} unsafe fn run(value: *unsafe mut Value) { value.update(value); }";
8103
    try expectAnalyzeOk(program);
8104
}
8105
8106
/// Unsafe instance-method attributes enable unsafe operations in the body.
8107
@test unsafe fn testUnsafeInstanceMethodBody() throws (testing::TestError) {
8108
    let program = "record Marker: Once {} record Value { number: u32 } trait Read { unsafe fn (*unsafe Read) get() -> u32; } instance Read for Value { unsafe fn (value: *unsafe Value) get() -> u32 { return value.number; } }";
8109
    try expectAnalyzeOk(program);
8110
}
8111
8112
/// Unsafe instance methods cannot implement safe trait contracts.
8113
@test unsafe fn testUnsafeInstanceMethodSafetyMismatch() throws (testing::TestError) {
8114
    let mut testArena560 = testArena();
8115
    let testStorage560: 'test560 = &mut testArena560 in {
8116
        let mut a = testResolver(testStorage560);
8117
        let program = "record Value {} trait Read { fn (&Read) get(); } instance Read for Value { unsafe fn (value: &Value) get() {} }";
8118
        let result = try resolveProgramStr(&mut a, program);
8119
        try expectErrorKind(&result, super::ErrorKind::TraitMethodSafetyMismatch);
8120
    }
8121
}
8122
8123
/// Unsafe trait methods retain their call-site requirement through dispatch.
8124
@test unsafe fn testUnsafeTraitMethodCallRejected() throws (testing::TestError) {
8125
    let mut testArena561 = testArena();
8126
    let testStorage561: 'test561 = &mut testArena561 in {
8127
        let mut a = testResolver(testStorage561);
8128
        let program = "record Marker: Once {} record Value { number: u32 } trait Read { unsafe fn (&Read) get() -> u32; } instance Read for Value { unsafe fn (value: &Value) get() -> u32 { return value.number; } } fn inspect(object: &opaque Read) -> u32 { return object.get(); }";
8129
        let result = try resolveProgramStr(&mut a, program);
8130
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
8131
    }
8132
}
8133
8134
/// An unsafe callback retains its requirement at an indirect call.
8135
@test unsafe fn testUnsafeCallbackCallRejected() throws (testing::TestError) {
8136
    let mut testArena562 = testArena();
8137
    let testStorage562: 'test562 = &mut testArena562 in {
8138
        let mut a = testResolver(testStorage562);
8139
        let result = try resolveProgramStr(&mut a,
8140
            "fn run(callback: unsafe fn() -> u32) -> u32 { return callback(); }");
8141
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
8142
    }
8143
}
8144
8145
/// An unsafe function cannot enter a safe callback slot.
8146
@test unsafe fn testUnsafeCallbackAssignmentRejected() throws (testing::TestError) {
8147
    let mut testArena563 = testArena();
8148
    let testStorage563: 'test563 = &mut testArena563 in {
8149
        let mut a = testResolver(testStorage563);
8150
        let result = try resolveProgramStr(&mut a,
8151
            "unsafe fn load() -> u32 { return 1; } fn run() { let callback: fn() -> u32 = load; }");
8152
        let err = try expectError(&result);
8153
        let case super::ErrorKind::TypeMismatch(_) = err.kind
8154
            else throw testing::TestError::Failed;
8155
    }
8156
}
8157
8158
/// A safe function can enter an unsafe callback slot.
8159
@test unsafe fn testSafeCallbackIntoUnsafeSlot() throws (testing::TestError) {
8160
    try expectAnalyzeOk(
8161
        "fn load() -> u32 { return 1; } unsafe fn run() -> u32 { let callback: unsafe fn() -> u32 = load; return callback(); }");
8162
}
8163
8164
/// Borrowed callback storage must preserve its function safety type.
8165
@test unsafe fn testBorrowedCallbackSafetyInvariant() throws (testing::TestError) {
8166
    let mut testArena564 = testArena();
8167
    let testStorage564: 'test564 = &mut testArena564 in {
8168
        let mut a = testResolver(testStorage564);
8169
        let result = try resolveProgramStr(&mut a,
8170
            "fn replace(slot: &mut unsafe fn()) {} fn load() {} fn run() { let mut callback: fn() = load; replace(&mut callback); }");
8171
        let err = try expectError(&result);
8172
        let case super::ErrorKind::TypeMismatch(_) = err.kind
8173
            else throw testing::TestError::Failed;
8174
    }
8175
}
8176
8177
/// Referenced storage must preserve its exact element type in every context.
8178
@test unsafe fn testPointerStorageCoercionsRejected() throws (testing::TestError) {
8179
    let programs = &[
8180
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; fn run() { let mut p = &DATA; replace(&mut p); }",
8181
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; unsafe fn run() { let mut p = &DATA; replace(&mut p); }",
8182
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; fn run() { let mut p = &DATA; unsafe { replace(&mut p); } }",
8183
        "fn take(p: *?u32) {} fn run(p: *u32) { take(p); }",
8184
        "unsafe fn take(p: *unsafe mut ?*u8) {} unsafe fn run(p: *unsafe mut *u8) { take(p); }",
8185
        "fn take(p: *[?*u8]) {} fn run(p: *[*u8]) { take(p); }",
8186
        "unsafe fn take(p: *mut [?*u8]) {} unsafe fn run(p: *mut [*u8]) { take(p); }",
8187
        "fn take(p: &mut **u8) {} fn run(p: &mut *mut *u8) { take(p); }",
8188
    ];
8189
    for program in programs {
8190
        let mut testArena565 = testArena();
8191
        let testStorage565: 'test565 = &mut testArena565 in {
8192
            let mut a = testResolver(testStorage565);
8193
            let result = try resolveProgramStr(&mut a, program);
8194
            let err = try expectError(&result);
8195
            let case super::ErrorKind::TypeMismatch(_) = err.kind
8196
                else throw testing::TestError::Failed;
8197
        }
8198
    }
8199
    try expectAnalyzeOk("fn take(p: &mut ?*u8) {} fn run() { let mut p: ?*u8 = nil; take(&mut p); }");
8200
    try expectAnalyzeOk("fn run(p: *mut u8) -> *u8 { return p; }");
8201
    try expectAnalyzeOk("fn run(p: *u8) -> *opaque { return p; }");
8202
}
8203
8204
/// Casts cannot add or remove optionality in referenced storage.
8205
@test unsafe fn testPointerOptionalStorageCastsRejected() throws (testing::TestError) {
8206
    let programs = &[
8207
        "fn run(p: **u8) { p as *?*u8; }",
8208
        "unsafe fn run(p: *mut *u8) { p as *mut ?*u8; }",
8209
        "fn run(p: *mut *u8) { unsafe { p as *mut ?*u8; } }",
8210
        "unsafe fn run(p: *mut ?*u8) { p as *mut *u8; }",
8211
        "unsafe fn run(p: *unsafe mut *u8) { p as *unsafe mut ?*u8; }",
8212
        "unsafe fn run(p: *mut [*u8]) { p as *mut [?*u8]; }",
8213
    ];
8214
    for program in programs {
8215
        let mut testArena566 = testArena();
8216
        let testStorage566: 'test566 = &mut testArena566 in {
8217
            let mut a = testResolver(testStorage566);
8218
            let result = try resolveProgramStr(&mut a, program);
8219
            let err = try expectError(&result);
8220
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
8221
                else throw testing::TestError::Failed;
8222
        }
8223
    }
8224
}
8225
8226
/// Pattern references prevent replacement of their source in every context.
8227
@test unsafe fn testPatternLoanMutationRejected() throws (testing::TestError) {
8228
    let programs = &[
8229
        "union U: Copy { A(u64), B(u64) } fn run() { let mut u = U::A(7); match &u { case U::A(p) => { set u = U::B(1); *p; } else => {} } }",
8230
        "union U: Copy { A(u64), B(u64) } unsafe fn run() { let mut u = U::A(7); match &u { case U::A(p) => { set u = U::B(1); *p; } else => {} } }",
8231
        "union U: Copy { A(u64), B(u64) } fn run() { let mut u = U::A(7); match &mut u { case U::A(p) => { unsafe { set u = U::B(1); } *p; } else => {} } }",
8232
        "union U: Copy { A(u64), B(u64) } fn change(u: &mut U) { set *u = U::B(1); } fn run() { let mut u = U::A(7); match &u { case U::A(p) => { change(&mut u); *p; } else => {} } }",
8233
        "union U: Copy { A(u64), B(u64) } fn run() { let mut u = U::A(7); if let case U::A(p) = &u { set u = U::B(1); *p; } }",
8234
        "union U: Copy { A(u64), B(u64) } fn run() { let mut u = U::A(7); while let case U::A(p) = &u { set u = U::B(1); *p; } }",
8235
        "union U: Copy { A(u64), B(u64) } fn run(u: *mut U) { match u { case U::A(p) => { let moved = u; *p; } else => {} } }",
8236
        "record R: 'r + Copy { p: &'r u32 } fn run 'r (p: &'r u32) { let mut u = R 'r { p }; match &u { case R { p: q } => { set u = R 'r { p }; **q; } else => {} } }",
8237
        "record R: 'r + Copy { p: &'r u32 } unsafe fn run 'r (p: &'r u32) { let mut u = R 'r { p }; match &u { case R { p: q } => { set u = R 'r { p }; **q; } else => {} } }",
8238
    ];
8239
    for program in programs {
8240
        let mut testArena567 = testArena();
8241
        let testStorage567: 'test567 = &mut testArena567 in {
8242
            let mut a = testResolver(testStorage567);
8243
            let result = try resolveProgramStr(&mut a, program);
8244
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
8245
        }
8246
    }
8247
}
8248
8249
/// Pattern loans end at their scope and permit writes through mutable payload references.
8250
@test unsafe fn testPatternLoanScopeAllowed() throws (testing::TestError) {
8251
    try expectAnalyzeOk("union U: Copy { A(u64), B(u64) } fn run() { let mut u = U::A(7); match &u { case U::A(p) => { *p; } else => {} } set u = U::B(1); }");
8252
    try expectAnalyzeOk("union U: Copy { A(u64), B(u64) } fn run() { let mut u = U::A(7); match &mut u { case U::A(p) => { set *p = 8; } else => {} } set u = U::B(1); }");
8253
    try expectAnalyzeOk("union U: Copy { A(u64), B(u64) } fn run() { let mut u = U::A(7); if let case U::A(p) = &u { *p; } else { set u = U::A(1); } set u = U::B(1); }");
8254
}
8255
8256
/// Replacing a borrowed pointer payload cannot forge an address.
8257
@test unsafe fn testBorrowedPointerPayloadReplacementRejected() throws (testing::TestError) {
8258
    let programs = &[
8259
        "static DATA: u8 = 7; union U: Copy { A(*u8), B(u64) } fn run() -> u8 { let mut u = U::A(&DATA); match &u { case U::A(p) => { set u = U::B(1); return **p; } else => return 0, } }",
8260
        "static DATA: u8 = 7; union U: Copy { A(*u8), B(u64) } unsafe fn run() -> u8 { let mut u = U::A(&DATA); match &u { case U::A(p) => { set u = U::B(1); return **p; } else => return 0, } }",
8261
    ];
8262
    for program in programs {
8263
        let mut testArena568 = testArena();
8264
        let testStorage568: 'test568 = &mut testArena568 in {
8265
            let mut a = testResolver(testStorage568);
8266
            let result = try resolveProgramStr(&mut a, program);
8267
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
8268
        }
8269
    }
8270
}
8271
8272
/// Guards, nested patterns, and unsafe calls must preserve pattern source storage.
8273
@test unsafe fn testPatternLoanIndirectMutationRejected() throws (testing::TestError) {
8274
    let programs = &[
8275
        "fn run() { let mut u: ?u64 = 7; match &u { p => { set u = nil; *p; } else => {} } }",
8276
        "union U: Copy { A(u64), B(u64) } fn change(u: &mut U) -> bool { set *u = U::B(1); return true; } fn run() { let mut u = U::A(7); match &u { case U::A(p) if change(&mut u) => { *p; } else => {} } }",
8277
        "union U: Copy { A(u64), B(u64) } unsafe fn change(u: *unsafe mut U) { set *u = U::B(1); } unsafe fn run(u: *unsafe mut U) { match u { case U::A(p) => { change(u); *p; } else => {} } }",
8278
        "union U: Copy { A(u64), B(u64) } record R: Copy { value: U } fn run() { let mut u = R { value: U::A(7) }; match &u.value { case U::A(p) => { set u.value = U::B(1); *p; } else => {} } }",
8279
        "union U: Copy { A(u64), B(u64) } fn run() { let mut u = [U::A(7)]; match &u[0] { case U::A(p) => { set u[0] = U::B(1); *p; } else => {} } }",
8280
        "union U: Copy { A(u64), B(u64) } unsafe fn (u: *unsafe mut U) change() { set *u = U::B(1); } unsafe fn run(u: *unsafe mut U) { match u { case U::A(p) => { u.change(); *p; } else => {} } }",
8281
    ];
8282
    for program in programs {
8283
        let mut testArena569 = testArena();
8284
        let testStorage569: 'test569 = &mut testArena569 in {
8285
            let mut a = testResolver(testStorage569);
8286
            let result = try resolveProgramStr(&mut a, program);
8287
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
8288
        }
8289
    }
8290
}
8291
8292
/// Binding mutability does not permit writes through immutable pointers.
8293
@test unsafe fn testMutableBindingImmutableTargetRejected() throws (testing::TestError) {
8294
    let programs = &[
8295
        "record R: Copy { n: u8 } fn run(input: *R) { let mut p = input; set p.n = 1; }",
8296
        "record R: Copy { n: u8 } fn run(input: *R) { let mut p = input; let q = &mut p.n; }",
8297
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; set p[0] = 1; }",
8298
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; set p[..] = 1; }",
8299
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; let q = &mut p[0]; }",
8300
        "record R: Copy { n: u8 } fn (r: &mut R) change() { set r.n = 1; } fn run(input: *R) { let mut p = input; p.change(); }",
8301
        "fn run(p: *mut u8, q: *mut u8) { set p = q; }",
8302
    ];
8303
    for program in programs {
8304
        let mut testArena570 = testArena();
8305
        let testStorage570: 'test570 = &mut testArena570 in {
8306
            let mut a = testResolver(testStorage570);
8307
            let result = try resolveProgramStr(&mut a, program);
8308
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
8309
        }
8310
    }
8311
}
8312
8313
/// Mutable targets support access through fixed and mutable pointer bindings.
8314
@test unsafe fn testMutablePointerTargetsAllowed() throws (testing::TestError) {
8315
    try expectAnalyzeOk("record R: Copy { n: u8 } fn (r: &mut R) change() { set r.n = 2; } fn run(p: *mut R) { set p.n = 1; p.change(); let q = &mut p.n; set *q = 3; }");
8316
    try expectAnalyzeOk("static DATA: [u8; 2] = [0, 0]; fn run() { let p = &mut DATA; set p[0] = 1; set p[..] = 2; let q = &mut p[0]; set *q = 3; }");
8317
    try expectAnalyzeOk("fn run(first: *u8, second: *u8) { let mut p = first; set p = second; }");
8318
}
8319
8320
/// Pattern access through raw pointers requires an unsafe context.
8321
@test unsafe fn testRawPointerPatternRejected() throws (testing::TestError) {
8322
    let programs = &[
8323
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { match p { case U::A(n) => { *n; } else => {} } }",
8324
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { if let case U::A(n) = p { *n; } }",
8325
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { while let case U::A(n) = p { *n; break; } }",
8326
        "record R: Copy { n: u8 } fn run(p: *unsafe R) { let case R { n } = p else return; }",
8327
    ];
8328
    for program in programs {
8329
        let mut testArena571 = testArena();
8330
        let testStorage571: 'test571 = &mut testArena571 in {
8331
            let mut a = testResolver(testStorage571);
8332
            let result = try resolveProgramStr(&mut a, program);
8333
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
8334
        }
8335
    }
8336
}
8337
8338
/// Unsafe contexts permit pattern access through raw pointers.
8339
@test unsafe fn testRawPointerPatternsAllowed() throws (testing::TestError) {
8340
    try expectAnalyzeOk("union U: Copy { A(u8), B } unsafe fn run(p: *unsafe U) { match p { case U::A(n) => { *n; } else => {} } if let case U::A(n) = p { *n; } while let case U::A(n) = p { *n; break; } }");
8341
    try expectAnalyzeOk("record R: Copy { n: u8 } unsafe fn run(p: *unsafe R) { let case R { n } = p else return; }");
8342
}
8343
8344
/// Slice append requires the allocator layout and callback signature.
8345
@test unsafe fn testSliceAppendAllocatorRejected() throws (testing::TestError) {
8346
    let programs = &[
8347
        "record A {} fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8348
        "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8349
        "record A(fn(*mut opaque, u32, u32) -> *mut opaque, *mut opaque); fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8350
        "fn run(s: *mut [u8]) { s.append(1, 0); }",
8351
        "record A { ctx: *mut opaque, func: fn(*mut opaque, u32, u32) -> *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8352
        "record A { func: u64, ctx: u64 } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8353
        "record A { func: fn(*mut opaque, u64, u32) -> *mut opaque, ctx: *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8354
        "record A { func: fn(*mut opaque, u32, u32) -> *opaque, ctx: *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8355
        "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: u64 } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8356
        "union E: Copy { Bad } record A { func: fn(*mut opaque, u32, u32) -> *mut opaque throws (E), ctx: *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8357
    ];
8358
    for program in programs {
8359
        let mut testArena572 = testArena();
8360
        let testStorage572: 'test572 = &mut testArena572 in {
8361
            let mut a = testResolver(testStorage572);
8362
            let result = try resolveProgramStr(&mut a, program);
8363
            try expectErrorKind(&result, super::ErrorKind::InvalidSliceAllocator);
8364
        }
8365
    }
8366
}
8367
8368
/// Slice allocators can use raw context pointers.
8369
@test unsafe fn testSliceAppendRawContextAllowed() throws (testing::TestError) {
8370
    try expectAnalyzeOk("record A: Copy { func: unsafe fn(*unsafe mut opaque, u32, u32) -> *mut opaque, ctx: *unsafe mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }");
8371
}
8372
8373
/// A live pattern reference protects its payload from writes through copied pointers.
8374
@test unsafe fn testPatternPayloadPointerAliasesRejected() throws (testing::TestError) {
8375
    let programs = &[
8376
        "union U: Copy { A(u8), B } fn run(p: *mut U) { let q = p; match p { case U::A(n) => { set *q = U::B; *n; } else => {} } }",
8377
        "union U: Copy { A(*u8), B(u64) } fn run(p: *mut U) -> u8 { let q = p; match p { case U::A(n) => { set *q = U::B(1); return **n; } else => return 0, } }",
8378
        "union U: Copy { A(u8), B } fn change(p: &mut U) { set *p = U::B; } fn run(p: *mut U) { let q = p; if let case U::A(n) = p { change(q); *n; } }",
8379
        "union U: Copy { A(u8), B } fn run(p: *mut U) { let q = p; let r = q; while let case U::A(n) = p { set *r = U::B; *n; break; } }",
8380
    ];
8381
    for program in programs {
8382
        let mut testArena573 = testArena();
8383
        let testStorage573: 'test573 = &mut testArena573 in {
8384
            let mut a = testResolver(testStorage573);
8385
            let result = try resolveProgramStr(&mut a, program);
8386
            let _ = try expectError(&result);
8387
        }
8388
    }
8389
}
8390
8391
/// Every access to a moved safe mutable pointer is rejected.
8392
@test unsafe fn testMutablePointerMovesRejected() throws (testing::TestError) {
8393
    let programs = &[
8394
        "fn run(p: *mut u8) { let q = p; *p; }",
8395
        "fn run(p: *mut u8) { let q = p; set *p = 1; }",
8396
        "fn run(p: *mut u8) { let q = p; let r = &*p; }",
8397
        "fn read(p: &u8) {} fn run(p: *mut u8) { let q = p; read(p); }",
8398
        "fn run(p: &mut u8) { let q = p; *p; }",
8399
        "fn run(p: *mut [u8]) { let q = p; p.len; }",
8400
        "fn run(p: &mut [u8]) { let q = p; p[0]; }",
8401
        "record R { value: u8 } fn run(p: *mut R) { let q = p; p.value; }",
8402
        "trait T { fn (&T) read(); } fn run(p: *mut opaque T) { let q = p; p.read(); }",
8403
        "fn run(p: *mut u8, flag: bool) { if flag { let q = p; } *p; }",
8404
        "fn run(p: *mut u8) { loop { let q = p; } }",
8405
    ];
8406
    for program in programs {
8407
        let mut testArena574 = testArena();
8408
        let testStorage574: 'test574 = &mut testArena574 in {
8409
            let mut a = testResolver(testStorage574);
8410
            let result = try resolveProgramStr(&mut a, program);
8411
            let _ = try expectError(&result);
8412
        }
8413
    }
8414
}
8415
8416
/// Copy composites cannot contain safe mutable owners or their containers.
8417
@test unsafe fn testCopyMutablePointerFieldsRejected() throws (testing::TestError) {
8418
    let programs = &[
8419
        "record R: Copy { p: *mut u8 }",
8420
        "union U: Copy { A(*mut u8), B }",
8421
        "record R: Copy { p: ?*mut u8 }",
8422
        "record R: Copy { p: [*mut u8; 2] }",
8423
        "record R: Copy { p: *mut [u8] }",
8424
        "trait T {} record R: Copy { p: *mut opaque T }",
8425
        "record Inner { p: *mut u8 } record Outer: Copy { inner: Inner }",
8426
    ];
8427
    for program in programs {
8428
        let mut testArena575 = testArena();
8429
        let testStorage575: 'test575 = &mut testArena575 in {
8430
            let mut a = testResolver(testStorage575);
8431
            let result = try resolveProgramStr(&mut a, program);
8432
            try expectErrorKind(&result, super::ErrorKind::CopyContainsNonCopy);
8433
        }
8434
    }
8435
}
8436
8437
/// Moves transfer safe mutable pointers, and calls can borrow them temporarily.
8438
@test unsafe fn testMutablePointerMovesAllowed() throws (testing::TestError) {
8439
    try expectAnalyzeOk("fn run(p: *mut u8) -> u8 { let q = p; set *q = 1; return *q; }");
8440
    try expectAnalyzeOk("fn setValue(p: &mut u8) { set *p = 1; } fn run(p: *mut u8) { setValue(p); setValue(p); *p; }");
8441
    try expectAnalyzeOk("fn run(p: *u8) { let q = p; *p; *q; }");
8442
    try expectAnalyzeOk("fn run(p: *mut u8, q: *mut u8) { unsafe { p == q; p as u64; } set *p = 1; set *q = 2; }");
8443
    try expectAnalyzeOk("record R: Copy { p: *unsafe mut u8 } unsafe fn run(p: *unsafe mut u8) { let q = p; set *p = 1; set *q = 2; }");
8444
    try expectAnalyzeOk("record R: Copy { p: *unsafe mut [u8] } unsafe fn run(p: *unsafe mut [u8]) { let q = p; set p[0] = 1; set q[0] = 2; }");
8445
}
8446
8447
/// Function signature inspection uses immutable descriptors in safe code.
8448
fn expectImmutableFunctionSignatures 'arena (res: &super::Resolver 'arena, root: *ast::Node) throws (testing::TestError) {
8449
    let first = try typeOf(res, try getBlockStmt(root, 0));
8450
    let equivalent = try typeOf(res, try getBlockStmt(root, 1));
8451
    let throwing = try typeOf(res, try getBlockStmt(root, 2));
8452
    let unsafeCall = try typeOf(res, try getBlockStmt(root, 3));
8453
    try testing::expect(super::typesEqual(first, equivalent));
8454
    try testing::expect(not super::typesEqual(first, throwing));
8455
    try testing::expect(not super::typesEqual(first, unsafeCall));
8456
}
8457
8458
/// Local analysis state does not change function signature identity.
8459
@test unsafe fn testImmutableFunctionSignatures() throws (testing::TestError) {
8460
    let mut testArena576 = testArena();
8461
    let testStorage576: 'test576 = &mut testArena576 in {
8462
        let mut res = testResolver(testStorage576);
8463
        let result = try resolveProgramStr(&mut res,
8464
            "fn first(x: u8) -> u32 { return 0; } fn equivalent(y: u8) -> u32 { let a: u32 = 1; return a; } fn throwing(x: u8) -> u32 throws (u8) { throw x; } unsafe fn unsafeCall(x: u8) -> u32 { return 0; }");
8465
        try expectNoErrors(&result);
8466
        try expectImmutableFunctionSignatures(&res, result.root);
8467
    }
8468
}
8469
8470
/// A diagnostic snapshot keeps its contents when the resolver buffer changes.
8471
@test unsafe fn testDiagnosticSnapshotOwnsItsErrors() throws (testing::TestError) {
8472
    let mut testArena577 = testArena();
8473
    let testStorage577: 'test577 = &mut testArena577 in {
8474
        let mut res = testResolver(testStorage577);
8475
        let result = try resolveProgramStr(&mut res, "fn run() { missing; }");
8476
        let snapshot = result.diagnostics;
8477
        let original = super::errorAt(snapshot.errors, 0) else throw testing::TestError::Failed;
8478
        set res.errors.entries[0] = super::Error {
8479
            kind: super::ErrorKind::Internal, node: nil, moduleId: 0,
8480
        };
8481
        let later = super::diagnostics(&mut res);
8482
        try testing::expect(snapshot.errors.len == 1);
8483
        try testing::expect(later.errors.len == 1);
8484
        let first = super::errorAt(snapshot.errors, 0) else throw testing::TestError::Failed;
8485
        try testing::expect(first.kind == original.kind);
8486
        try testing::expect(later.errors[0].kind == super::ErrorKind::Internal);
8487
        try testing::expect(super::errorAt(snapshot.errors, 1) == nil);
8488
    }
8489
}
8490
8491
/// Prefixes, equal fields, and uncertain element locations must conflict.
8492
@test unsafe fn testOverlappingFieldBorrows() throws (testing::TestError) {
8493
    let programs = &[
8494
        "record R: Copy { a: u32, b: u32 } fn take(a: &mut u32, b: &u32) {} fn run(r: &mut R) { take(&mut r.a, &r.a); }",
8495
        "record R: Copy { a: u32, b: u32 } fn take(a: &mut R, b: &u32) {} fn run(r: &mut R) { take(r, &r.b); }",
8496
        "record R: Copy { a: [u8; 2], b: [u8; 2] } fn take(a: &mut u8, b: &u8) {} fn run(r: &mut R) { take(&mut r.a[0], &r.a[1]); }",
8497
        "record R: Copy { a: u32, b: u32 } fn take(a: &mut u32, b: u32) {} fn run(r: &mut R) { take(&mut r.a, r.a); }",
8498
    ];
8499
    for program in programs {
8500
        let mut testArena578 = testArena();
8501
        let testStorage578: 'test578 = &mut testArena578 in {
8502
            let mut a = testResolver(testStorage578);
8503
            let result = try resolveProgramStr(&mut a, program);
8504
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8505
        }
8506
    }
8507
}
8508
8509
/// Local loans exclude writes, competing references, and source reads.
8510
@test unsafe fn testLocalReferenceConflicts() throws (testing::TestError) {
8511
    let programs = &[
8512
        "fn run() { let mut n: u32 = 4; let p = &n; set n = 1; }",
8513
        "fn run() { let mut n: u32 = 4; let p = &mut n; n; }",
8514
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &n; }",
8515
        "fn run() { let mut n: u32 = 4; let p = &n; let q = &mut n; }",
8516
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &mut *p; set *p = 1; }",
8517
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &*p; set *p = 1; }",
8518
        "fn take(p: &mut u32) {} fn run() { let mut n: u32 = 4; let p = &n; take(&mut n); }",
8519
        "fn run() { let mut n: u32 = 4; let p = &n; unsafe { set n = 1; } }",
8520
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &*p; let moved = p; }",
8521
    ];
8522
    for program in programs {
8523
        let mut testArena579 = testArena();
8524
        let testStorage579: 'test579 = &mut testArena579 in {
8525
            let mut a = testResolver(testStorage579);
8526
            let result = try resolveProgramStr(&mut a, program);
8527
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("n"));
8528
        }
8529
    }
8530
}
8531
8532
/// Reference bindings cannot outlive temporary storage or change their source.
8533
@test unsafe fn testLocalReferenceStorage() throws (testing::TestError) {
8534
    let programs = &[
8535
        "fn f 'r (p: &'r mut u32) { let mut cursor = p; }",
8536
        "unsafe fn f 'r (p: &'r mut u32) { let mut cursor = p; }",
8537
        "fn run() { let n: u32 = 4; let mut p: &u32 = &n; }",
8538
        "record R: Copy { n: u32 } fn make() -> R { return R { n: 4 }; } fn run() { let p: &u32 = &make().n; }",
8539
    ];
8540
    for program in programs {
8541
        let mut testArena580 = testArena();
8542
        let testStorage580: 'test580 = &mut testArena580 in {
8543
            let mut a = testResolver(testStorage580);
8544
            let result = try resolveProgramStr(&mut a, program);
8545
            try expectErrorKind(&result, super::ErrorKind::RefBinding);
8546
        }
8547
    }
8548
}
8549
8550
/// Stored and returned values cannot contain a local reference.
8551
@test unsafe fn testLocalReferenceEscapeRejected() throws (testing::TestError) {
8552
    let programs = &[
8553
        "fn run() -> *u32 { let n: u32 = 1; let p = &n; return p; }",
8554
        "fn run() -> *u32 { let n: u32 = 1; let p = &n; return p as *u32; }",
8555
        "static DATA: u32 = 0; static P: *u32 = &DATA; fn run() { let n: u32 = 1; let p = &n; set P = p; }",
8556
        "record R: Copy { p: *u32 } fn run() { let n: u32 = 1; let p = &n; let r = R { p }; }",
8557
    ];
8558
    for program in programs {
8559
        let mut testArena581 = testArena();
8560
        let testStorage581: 'test581 = &mut testArena581 in {
8561
            let mut a = testResolver(testStorage581);
8562
            let result = try resolveProgramStr(&mut a, program);
8563
            let _ = try expectError(&result);
8564
        }
8565
    }
8566
}
8567
8568
/// Pointer indirection cannot prove that sibling pointees are disjoint.
8569
@test unsafe fn testIndirectFieldBorrowConflict() throws (testing::TestError) {
8570
    let programs = &[
8571
        "record R: Copy { a: *unsafe mut u32, b: *unsafe mut u32 } fn take(a: &mut u32, b: &mut u32) {} unsafe fn run(r: &mut R) { take(&mut *r.a, &mut *r.b); }",
8572
        "record R: Copy { a: *unsafe mut u32, b: *unsafe mut u32 } unsafe fn run(r: &mut R) { let a: &mut u32 = &mut *r.a; let b: &mut u32 = &mut *r.b; }",
8573
    ];
8574
    for program in programs {
8575
        let mut testArena582 = testArena();
8576
        let testStorage582: 'test582 = &mut testArena582 in {
8577
            let mut a = testResolver(testStorage582);
8578
            let result = try resolveProgramStr(&mut a, program);
8579
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8580
        }
8581
    }
8582
}
8583
8584
/// Pattern references protect their field and permit writes to disjoint fields.
8585
@test unsafe fn testDisjointPatternFieldBorrow() throws (testing::TestError) {
8586
    let mut testArena583 = testArena();
8587
    let testStorage583: 'test583 = &mut testArena583 in {
8588
        let mut a = testResolver(testStorage583);
8589
        let result = try resolveProgramStr(&mut a,
8590
            "union U: Copy { A(u32), B } record R: Copy { u: U, n: u32 } fn run(r: &mut R) { let alias = &mut r.u; match alias { case U::A(p) => { set *alias = U::B; *p; } else => {} } }");
8591
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8592
    }
8593
}
8594
8595
/// Slice mutations must preserve storage held by a local reference.
8596
@test unsafe fn testLocalReferenceSliceMutationRejected() throws (testing::TestError) {
8597
    let programs = &[
8598
        "fn run(s: *mut [u8]) { let p: &u8 = &s[0]; s.delete(0); }",
8599
        "record A: Copy { func: unsafe fn(*unsafe mut opaque, u32, u32) -> *mut opaque, ctx: *unsafe mut opaque } fn run(s: *mut [u8], a: A) { let p: &u8 = &s[0]; s.append(1, a); }",
8600
    ];
8601
    for program in programs {
8602
        let mut testArena584 = testArena();
8603
        let testStorage584: 'test584 = &mut testArena584 in {
8604
            let mut a = testResolver(testStorage584);
8605
            let result = try resolveProgramStr(&mut a, program);
8606
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("s"));
8607
        }
8608
    }
8609
}
8610
8611
/// Owner moves and mutable methods cannot invalidate a local loan.
8612
@test unsafe fn testLocalReferenceOwnerMutationRejected() throws (testing::TestError) {
8613
    let programs = &[
8614
        "fn run(p: *mut u32) { let r: &u32 = &*p; let moved = p; }",
8615
        "record R: Copy { a: u32 } fn (p: &mut R) change() { set p.a = 1; } fn run(p: &mut R) { let r = &p.a; p.change(); }",
8616
    ];
8617
    for program in programs {
8618
        let mut testArena585 = testArena();
8619
        let testStorage585: 'test585 = &mut testArena585 in {
8620
            let mut a = testResolver(testStorage585);
8621
            let result = try resolveProgramStr(&mut a, program);
8622
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("p"));
8623
        }
8624
    }
8625
}
8626
8627
/// Reference locals require a function scope and a reachable initializer result.
8628
@test unsafe fn testLocalReferenceDeclarationContext() throws (testing::TestError) {
8629
    let mut testArena586 = testArena();
8630
    let testStorage586: 'test586 = &mut testArena586 in {
8631
        let mut a = testResolver(testStorage586);
8632
        let result = try resolveProgramStr(&mut a, "let n: u32 = 1; let p: &u32 = &n;");
8633
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
8634
    }
8635
}
8636
8637
/// Test-only imports do not require their modules in a normal build.
8638
@test unsafe fn testConditionalUse() throws (testing::TestError) {
8639
    let mut testArena587 = testArena();
8640
    let testStorage587: 'test587 = &mut testArena587 in {
8641
        let mut a = testResolver(testStorage587);
8642
        set a.config.buildTest = false;
8643
        let source = "@test use missing::testing; fn value() -> u32 { return 1; }";
8644
        let result = try resolveProgramStr(&mut a, source);
8645
        try expectNoErrors(&result);
8646
        set a.config.buildTest = true;
8647
        let enabled = try resolveProgramStr(&mut a, source);
8648
        try testing::expect(enabled.diagnostics.errors.len > 0);
8649
    }
8650
}
8651
8652
/// Retained module identities are accessible through safe lookup.
8653
fn checkModuleQueries 'arena (
8654
    res: &super::Resolver 'arena, root: u16, child: u16
8655
) throws (testing::TestError) {
8656
    let rootEntry = super::moduleFor(res, root) else throw testing::TestError::Failed;
8657
    let childEntry = super::moduleFor(res, child) else throw testing::TestError::Failed;
8658
    assert rootEntry.id == root;
8659
    assert childEntry.id == child;
8660
    let parent = childEntry.parent else throw testing::TestError::Failed;
8661
    assert parent == root;
8662
    try testing::expectBytesEq(rootEntry.name, "root");
8663
    try testing::expectBytesEq(childEntry.name, "child");
8664
    if let _ = super::moduleFor(res, 0xffff) {
8665
        throw testing::TestError::Failed;
8666
    }
8667
}
8668
8669
/// Module identities remain valid independently of the graph container.
8670
@test unsafe fn testSafeModuleQueries() throws (testing::TestError) {
8671
    let mut arena = testArena();
8672
    let storage: 'test = &mut arena in {
8673
        let mut res = testResolver(storage);
8674
        if let _ = super::moduleFor(&res, 0) {
8675
            throw testing::TestError::Failed;
8676
        }
8677
        set MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]);
8678
        let mut root: u16 = 0;
8679
        let mut child: u16 = 0;
8680
        let mut owner = module::Permission {};
8681
        let permission: 'permission = &mut owner in {
8682
            let mut graph = module::moduleGraph(
8683
                &mut MODULE_ENTRIES[..], &mut MODULE_ARENA, permission
8684
            );
8685
            set root = try! module::registerRootWithName(
8686
                &mut graph, &mut STRING_POOL, 0, "root", "/root.rad"
8687
            );
8688
            set child = try! module::registerChild(
8689
                &mut graph, &mut STRING_POOL, root, "child", "/child.rad"
8690
            );
8691
            let diagnostics = try! super::resolve(&mut res, &graph, &[]);
8692
            assert super::success(&diagnostics);
8693
        }
8694
        let mut emptyOwner = module::Permission {};
8695
        let emptyPermission: 'empty = &mut emptyOwner in {
8696
            let graph = module::moduleGraph(
8697
                &mut MODULE_ENTRIES[..], &mut MODULE_ARENA, emptyPermission
8698
            );
8699
            try checkModuleQueries(&res, root, child);
8700
            let empty = try! super::resolve(&mut res, &graph, &[]);
8701
            assert super::success(&empty);
8702
        }
8703
        if let _ = super::moduleFor(&res, root) {
8704
            throw testing::TestError::Failed;
8705
        }
8706
    }
8707
}
8708
8709
/// Resolver metadata retains its caller's arena when the context moves.
8710
unsafe fn relocateResolver 'arena (context: super::Resolver 'arena) -> super::Resolver 'arena {
8711
    return context;
8712
}
8713
8714
@test unsafe fn testResolverRelocation() throws (testing::TestError) {
8715
    static DATA: [u8; 65536] = [0; 65536];
8716
    static AST_DATA: [u8; 8192] = [0; 8192];
8717
    static NODES: [super::NodeData; 128] = undefined;
8718
    static ERRORS: [super::Error; 8] = undefined;
8719
    static SCOPE: super::Scope = undefined;
8720
    static POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
8721
    let mut arena = alloc::new(&mut DATA[..]);
8722
    let mut astArena = ast::nodeArena(&mut AST_DATA[..]);
8723
    let root = try! parser::parse(scanner::SourceLoc::String,
8724
        "fn answer() -> u32 { return 42; }", &mut astArena, &mut POOL);
8725
    let storage = super::ResolverStorage {
8726
        nodeData: &mut NODES[..], pkgScope: &mut SCOPE, errors: &mut ERRORS[..],
8727
    };
8728
    let arenaRef: 'arena = &mut arena in {
8729
        let context = super::resolver(arenaRef, storage, super::Config { buildTest: false });
8730
        let initialized = alloc::used(context.arena);
8731
        try testing::expect(initialized > 0);
8732
        let mut moved = relocateResolver(context);
8733
        let diagnostics = try! super::resolveModuleRoot(&mut moved, root);
8734
        try testing::expect(super::success(&diagnostics));
8735
        try testing::expect(alloc::used(moved.arena) > initialized);
8736
        try testing::expect(moved.arena.offset == alloc::used(moved.arena));
8737
        let output = try! alloc::alloc(&mut *moved.arena, @sizeOf(u32), @alignOf(u32)) as *mut u32;
8738
        set *output = 42;
8739
        try testing::expect(*output == 42);
8740
    }
8741
}