lib/std/lang/resolver/tests.rad 406.6 KiB raw
1
//! Resolver tests.
2
3
/// Region identity, borrowing, and nominal application tests.
4
@test mod regions;
5
6
use std::mem;
7
use std::testing;
8
use std::lang::alloc;
9
use std::lang::ast;
10
use std::lang::types;
11
use std::lang::parser;
12
use std::lang::scanner;
13
use std::lang::module;
14
use std::lang::strings;
15
16
/// Interning preserves exact identity across populated collision chains.
17
@test unsafe fn testTypeInterningIdentity() throws (testing::TestError) {
18
    let mut arena = testArena();
19
    let storage: 'test = &mut arena in {
20
        let mut res = testResolver(storage);
21
        let item = super::allocType(&mut res, super::Type::U32);
22
        let mut entries: [?*super::Type; 2048] = [nil; 2048];
23
        for i in 0..entries.len {
24
            let ty = super::Type::Array(super::ArrayType { item, length: i });
25
            set entries[i] = super::allocType(&mut res, ty);
26
        }
27
        for i in 0..entries.len {
28
            let ty = super::Type::Array(super::ArrayType { item, length: i });
29
            let entry = entries[i] else throw testing::TestError::Failed;
30
            assert super::allocType(&mut res, ty) == entry;
31
            assert *entry == ty;
32
        }
33
        let values = [
34
            super::Type::U32, super::Type::U64,
35
            super::Type::Optional(item),
36
            super::Type::Range { start: nil, end: nil },
37
            super::Type::Range { start: item, end: nil },
38
            super::Type::Range { start: nil, end: item },
39
            super::Type::Range { start: item, end: item },
40
            super::Type::Cell { class: types::PointerClass::Ref, payload: item },
41
            super::Type::Pointer { class: types::PointerClass::Ref, target: item, mutable: false },
42
            super::Type::Pointer { class: types::PointerClass::Ref, target: item, mutable: true },
43
            super::Type::Pointer { class: types::PointerClass::Owned, target: item, mutable: false },
44
            super::Type::Pointer { class: types::PointerClass::Unsafe, target: item, mutable: false },
45
            super::Type::Slice { class: types::PointerClass::Ref, item, mutable: false },
46
            super::Type::Slice { class: types::PointerClass::Ref, item, mutable: true },
47
        ];
48
        for ty, i in values {
49
            let entry = super::allocType(&mut res, ty);
50
            assert super::allocType(&mut res, ty) == entry;
51
            for other, j in values {
52
                assert (entry == super::allocType(&mut res, other)) == (i == j);
53
            }
54
        }
55
    }
56
}
57
58
/// Reused ownership slots retain the current binding's exact-use diagnostics.
59
@test unsafe fn testLinearScratchSlotReuse() throws (testing::TestError) {
60
    let mut arena = testArena();
61
    let storage: 'test = &mut arena in {
62
        let mut res = testResolver(storage);
63
        let result = try resolveProgramStr(&mut res,
64
            "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); }"
65
        );
66
        try expectErrorKind(&result, super::ErrorKind::LinearUseAfterConsume("second"));
67
    }
68
    let mut branchArena = testArena();
69
    let branchStorage: 'branch = &mut branchArena in {
70
        let mut res = testResolver(branchStorage);
71
        let result = try resolveProgramStr(&mut res,
72
            "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); } }"
73
        );
74
        try expectErrorKind(&result, super::ErrorKind::LinearBranchMismatch("second"));
75
    }
76
}
77
78
/// Nested loops keep separate break state and restore the stack after errors.
79
@test unsafe fn testLoopContextState() throws (testing::TestError) {
80
    for program, index in [
81
        "fn f() { loop { break; } loop { loop { break; } continue; } }",
82
        "fn f() { loop { loop { missing; } } }",
83
        "fn f() { loop { break; } break; }",
84
        "fn f() { loop { break; } continue; }",
85
        "break;",
86
        "continue;",
87
        "loop { break }",
88
        "while true { continue }",
89
    ] {
90
        let mut arena = testArena();
91
        let storage: 'test = &mut arena in {
92
            let mut res = testResolver(storage);
93
            let result = try resolveProgramStr(&mut res, program);
94
            assert res.loopDepth == 0;
95
            if index == 0 {
96
                try expectNoErrors(&result);
97
                let body = try getFnBody(&res, result.root, "f");
98
                let first = super::typeFor(&res, body.statements[0]) else throw testing::TestError::Failed;
99
                let second = super::typeFor(&res, body.statements[1]) else throw testing::TestError::Failed;
100
                let case super::Type::Void = first else throw testing::TestError::Failed;
101
                let case super::Type::Never = second else throw testing::TestError::Failed;
102
            } else if index == 1 {
103
                try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("missing"));
104
            } else if index < 6 {
105
                try expectErrorKind(&result, super::ErrorKind::InvalidLoopControl);
106
            } else {
107
                try expectNoErrors(&result);
108
            }
109
        }
110
    }
111
}
112
113
/// Loop bindings and lowering metadata retain the same item type and names.
114
@test unsafe fn testForLoopMetadata() throws (testing::TestError) {
115
    let mut arena = testArena();
116
    let storage: 'test = &mut arena in {
117
        let mut res = testResolver(storage);
118
        let result = try resolveProgramStr(&mut res,
119
            "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 {} }"
120
        );
121
        try expectNoErrors(&result);
122
        let body = try getFnBody(&res, result.root, "f");
123
        for index in [1 as u32, 2, 3] {
124
            let node = body.statements[index];
125
            let case ast::NodeValue::For(loopNode) = node.value else throw testing::TestError::Failed;
126
            let info = super::forLoopInfoFor(&res, node) else throw testing::TestError::Failed;
127
            let bindingType = super::typeFor(&res, loopNode.binding) else throw testing::TestError::Failed;
128
            match info {
129
                case super::ForLoopInfo::Collection { elemType, length, bindingName, indexName } => {
130
                    assert bindingType == *elemType;
131
                    let name = bindingName else throw testing::TestError::Failed;
132
                    if index == 1 {
133
                        assert *elemType == super::Type::U16;
134
                        let count = length else throw testing::TestError::Failed;
135
                        assert count == 2;
136
                        assert mem::eq(name, "value");
137
                        let name = indexName else throw testing::TestError::Failed;
138
                        assert mem::eq(name, "idx");
139
                    } else {
140
                        assert index == 2;
141
                        assert *elemType == super::Type::U8;
142
                        assert length == nil;
143
                        assert mem::eq(name, "byte");
144
                        assert indexName == nil;
145
                    }
146
                }
147
                case super::ForLoopInfo::Range { valType, range, bindingName, indexName } => {
148
                    assert index == 3;
149
                    assert bindingType == *valType;
150
                    assert *valType == super::Type::U64;
151
                    assert bindingName == nil;
152
                    let name = indexName else throw testing::TestError::Failed;
153
                    assert mem::eq(name, "idx");
154
                    let case ast::NodeValue::Range(source) = loopNode.iterable.value else throw testing::TestError::Failed;
155
                    assert range == source;
156
                }
157
            }
158
            if let binding = loopNode.index {
159
                let ty = super::typeFor(&res, binding) else throw testing::TestError::Failed;
160
                assert ty == super::Type::U32;
161
            }
162
        }
163
    }
164
}
165
166
/// Invalid iterables and unsafe slice iteration retain their diagnostics.
167
@test unsafe fn testForLoopMetadataErrors() throws (testing::TestError) {
168
    for program in [
169
        "fn f() { for x in true {} }",
170
        "fn f(end: u32) { for x in ..end {} }",
171
        "fn f(start: u32, end: u32) { let range = start..end; for x in range {} }",
172
    ] {
173
        let mut arena = testArena();
174
        let storage: 'test = &mut arena in {
175
            let mut res = testResolver(storage);
176
            let result = try resolveProgramStr(&mut res, program);
177
            try expectErrorKind(&result, super::ErrorKind::ExpectedIterable);
178
        }
179
    }
180
    let mut arena = testArena();
181
    let storage: 'test = &mut arena in {
182
        let mut res = testResolver(storage);
183
        let result = try resolveProgramStr(&mut res, "fn f(s: *unsafe [u32]) { for x in s {} }");
184
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
185
    }
186
    try expectAnalyzeOk("unsafe fn f(s: *unsafe [u32]) { for x in s {} }");
187
}
188
189
/// Slice operations retain initialized element, capacity, and access metadata.
190
@test unsafe fn testSliceRangeMetadata() throws (testing::TestError) {
191
    let mut arena = testArena();
192
    let storage: 'test = &mut arena in {
193
        let mut res = testResolver(storage);
194
        let result = try resolveProgramStr(&mut res,
195
            "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[..]; }"
196
        );
197
        try expectNoErrors(&result);
198
        let body = try getFnBody(&res, result.root, "f");
199
        for index in [1 as u32, 3] {
200
            let stmt = body.statements[index];
201
            let case ast::NodeValue::Assign(_) = stmt.value else throw testing::TestError::Failed;
202
            let info = super::sliceRangeInfoFor(&res, stmt) else throw testing::TestError::Failed;
203
            assert *info.itemType == super::Type::U32;
204
            assert info.mutable;
205
            let capacity: ?u32 = 4 if index == 1 else nil;
206
            assert info.capacity == capacity;
207
        }
208
        for index in [2 as u32, 4] {
209
            let stmt = body.statements[index];
210
            let case ast::NodeValue::Let(binding) = stmt.value else throw testing::TestError::Failed;
211
            let case ast::NodeValue::AddressOf(_) = binding.value.value else throw testing::TestError::Failed;
212
            let info = super::sliceRangeInfoFor(&res, binding.value) else throw testing::TestError::Failed;
213
            assert *info.itemType == super::Type::U32;
214
            assert info.mutable == (index == 2);
215
            let capacity: ?u32 = 4 if index == 2 else nil;
216
            assert info.capacity == capacity;
217
        }
218
    }
219
}
220
221
/// Slice assignment and borrowing enforce static bounds and source access.
222
@test unsafe fn testSliceRangeErrors() throws (testing::TestError) {
223
    for program in [
224
        "fn f() { let mut xs: [u32; 2] = [1, 2]; set xs[..3] = 0; }",
225
        "fn f() { let mut xs: [u32; 2] = [1, 2]; set xs[2..1] = 0; }",
226
        "fn f() { let mut xs: [u32; 2] = [1, 2]; let view = &mut xs[..3]; }",
227
    ] {
228
        let mut arena = testArena();
229
        let storage: 'test = &mut arena in {
230
            let mut res = testResolver(storage);
231
            let result = try resolveProgramStr(&mut res, program);
232
            let err = try expectError(&result);
233
            assert err.kind == super::ErrorKind::SliceRangeOutOfBounds, program;
234
        }
235
    }
236
    for program in [
237
        "fn f() { let mut value: u32 = 1; set value[..] = 0; }",
238
        "fn f() { let mut value: u32 = 1; let view = &value[..]; }",
239
    ] {
240
        let mut arena = testArena();
241
        let storage: 'test = &mut arena in {
242
            let mut res = testResolver(storage);
243
            let result = try resolveProgramStr(&mut res, program);
244
            let err = try expectError(&result);
245
            assert err.kind == super::ErrorKind::ExpectedIndexable, program;
246
        }
247
    }
248
    for program in [
249
        "fn f() { let xs: [u32; 2] = [1, 2]; let view = &xs[..]; set view[..] = 0; }",
250
        "fn f() { let xs: [u32; 2] = [1, 2]; let view = &xs[..]; let other = &mut view[..]; }",
251
    ] {
252
        let mut arena = testArena();
253
        let storage: 'test = &mut arena in {
254
            let mut res = testResolver(storage);
255
            let result = try resolveProgramStr(&mut res, program);
256
            let err = try expectError(&result);
257
            assert err.kind == super::ErrorKind::ImmutableBinding, program;
258
        }
259
    }
260
}
261
262
/// Fixed and result layouts cover primitive and pointer-like representations.
263
@test unsafe fn testFixedTypeLayouts() throws (testing::TestError) {
264
    for ty in [super::Type::Void, super::Type::Never] {
265
        checkFixedTypeLayout(ty, 0, 0);
266
    }
267
    for ty in [super::Type::Bool, super::Type::U8, super::Type::I8] {
268
        checkFixedTypeLayout(ty, 1, 1);
269
    }
270
    for ty in [super::Type::U16, super::Type::I16] { checkFixedTypeLayout(ty, 2, 2); }
271
    for ty in [super::Type::U32, super::Type::I32] { checkFixedTypeLayout(ty, 4, 4); }
272
    for ty in [super::Type::Int, super::Type::U64, super::Type::I64] { checkFixedTypeLayout(ty, 8, 8); }
273
    let mut arena = testArena();
274
    let itemStorage = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type;
275
    set *itemStorage = super::Type::U32;
276
    let item: *super::Type = itemStorage;
277
    let region = types::Region { id: 1, origin: types::RegionOrigin::Block, name: "r", parent: nil };
278
    let traitInfo = super::TraitType { name: "T", moduleId: 0, methods: &mut [], supertraits: &mut [] };
279
    let signature = try! alloc::alloc(&mut arena, @sizeOf(super::FnType), @alignOf(super::FnType)) as *mut super::FnType;
280
    set *signature = super::FnType {
281
        regions: nil, paramTypes: &[], returnType: item, throwList: &[], isUnsafe: false,
282
    };
283
    checkFixedTypeLayout(super::Type::Fn(signature), 8, 8);
284
    checkFixedTypeLayout(super::Type::Session(&region), 16, 8);
285
    for class in [types::PointerClass::Owned, types::PointerClass::Ref,
286
                  types::PointerClass::Unsafe, types::PointerClass::Region(&region)] {
287
        checkFixedTypeLayout(super::Type::Cell { class, payload: item }, 8, 8);
288
        for mutable in [false, true] {
289
            checkFixedTypeLayout(super::Type::Pointer { class, target: item, mutable }, 8, 8);
290
            checkFixedTypeLayout(super::Type::Slice { class, item, mutable }, 16, 8);
291
            checkFixedTypeLayout(super::Type::TraitObject { class, traitInfo: &traitInfo, mutable }, 16, 8);
292
        }
293
    }
294
    /// Result layouts retain the tag and the largest success or error payload.
295
    let errors = try! alloc::allocSlice(&mut arena, @sizeOf(*super::Type), @alignOf(*super::Type), 3)
296
        as *mut [*super::Type];
297
    for ty, i in [super::Type::Void, super::Type::U8, super::Type::U64] {
298
        let slot = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type;
299
        set *slot = ty;
300
        set errors[i] = slot;
301
    }
302
    let throwList: *[*super::Type] = errors;
303
    let payloads = [super::Type::Void, super::Type::U8,
304
        super::Type::Array(super::ArrayType { item: throwList[2], length: 3 })];
305
    let emptySizes: [u32; 3] = [8, 9, 32];
306
    let errorSizes: [u32; 3] = [16, 16, 32];
307
    for payload, i in payloads {
308
        let empty = super::getResultLayout(payload, &[]);
309
        assert empty.size == emptySizes[i] and empty.alignment == 8;
310
        let result = super::getResultLayout(payload, throwList);
311
        assert result.size == errorSizes[i] and result.alignment == 8;
312
    }
313
}
314
315
/// Check a fixed layout through direct, array, and optional type traversal.
316
unsafe fn checkFixedTypeLayout(ty: super::Type, size: u32, alignment: u32) {
317
    let layout = super::getTypeLayout(ty);
318
    assert layout.size == size and layout.alignment == alignment;
319
    let mut arena = alloc::new(&mut FIXED_LAYOUT_STORAGE[..]);
320
    let itemStorage = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type;
321
    set *itemStorage = ty;
322
    let item: *super::Type = itemStorage;
323
    for length in [0 as u32, 1, 3] {
324
        let array = super::getTypeLayout(super::Type::Array(super::ArrayType { item, length }));
325
        assert array.size == size * length and array.alignment == alignment;
326
    }
327
    let optional = super::getTypeLayout(super::Type::Optional(item));
328
    let expected = layout if super::isNullableType(ty) else super::getOptionalAggregateLayout(layout);
329
    assert optional.size == expected.size and optional.alignment == expected.alignment;
330
    let optionalStorage = try! alloc::alloc(&mut arena, @sizeOf(super::Type), @alignOf(super::Type)) as *mut super::Type;
331
    set *optionalStorage = super::Type::Optional(item);
332
    let optionalItem: *super::Type = optionalStorage;
333
    for length in [0 as u32, 1, 3] {
334
        let array = super::getTypeLayout(super::Type::Array(super::ArrayType { item: optionalItem, length }));
335
        assert array.size == optional.size * length and array.alignment == optional.alignment;
336
    }
337
    let nested = super::getTypeLayout(super::Type::Optional(optionalItem));
338
    let nestedExpected = super::getOptionalAggregateLayout(optional);
339
    assert nested.size == nestedExpected.size and nested.alignment == nestedExpected.alignment;
340
}
341
342
/// Storage for owned types used by array and optional layout fixtures.
343
static FIXED_LAYOUT_STORAGE: [u8; 256] = [0; 256];
344
345
/// Array layouts retain element alignment for empty and populated arrays.
346
@test fn testArrayLayoutFromElementLayout() throws (testing::TestError) {
347
    for alignment in [1 as u32, 2, 4, 8, 16] {
348
        let item = super::Layout { size: alignment, alignment };
349
        for count in [0 as u32, 1, 3] {
350
            let result = super::getArrayLayout(item, count);
351
            assert result.size == alignment * count;
352
            assert result.alignment == alignment;
353
        }
354
    }
355
}
356
357
/// Synthetic file path used for resolver tests.
358
constant MODULE_PATH: *[u8] = "/dev/test.rad";
359
360
/// Optional aggregate layouts align the tag and payload for safe callers.
361
@test fn testOptionalAggregateLayouts() throws (testing::TestError) {
362
    for alignment in [1 as u32, 2, 4, 8, 16] {
363
        for length in [0 as u32, 1, 3] {
364
            let payload = super::Layout { size: length * alignment, alignment };
365
            let layout = super::getOptionalAggregateLayout(payload);
366
            assert layout.size == (length + 1) * alignment;
367
            assert layout.alignment == alignment;
368
        }
369
    }
370
}
371
372
/// AST arena storage used by resolver tests.
373
static AST_ARENA: [u8; 2097152] = [0; 2097152];
374
375
/// Resolver arena storage used by resolver tests.
376
static ARENA_STORAGE: [u8; 2097152] = [0; 2097152];
377
378
/// Node metadata storage used by resolver tests.
379
unsafe static NODE_DATA_STORAGE: [super::NodeData; 256] = undefined;
380
381
/// Diagnostic storage used by resolver tests.
382
unsafe static ERROR_STORAGE: [super::Error; 16] = undefined;
383
384
/// Package scope used by resolver tests.
385
unsafe static PKG_SCOPE: super::Scope = undefined;
386
387
/// Module entries used by resolver tests.
388
unsafe static MODULE_ENTRIES: [?*module::ModuleEntry; 8] = [nil; 8];
389
390
/// Module graph used by resolver tests.
391
unsafe static MODULE_GRAPH: module::ModuleGraph = undefined;
392
393
/// Module AST arena storage used by resolver tests.
394
static MODULE_ARENA_STORAGE: [u8; 16384] = [0; 16384];
395
396
/// Module AST arena used by resolver tests.
397
unsafe static MODULE_ARENA: ast::NodeArena = undefined;
398
399
/// Interned string pool used by resolver tests.
400
unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
401
402
/// String literals used in tests.
403
constant LITERALS: [*[u8]; 15] = [
404
    "Ok", "Error", "R", "S",
405
    "f", "Status", "Pending",
406
    "Some", "None", "First",
407
    "Second", "Opt", "x",
408
    "value", "idx"
409
];
410
411
/// Resolver result with AST, used by test helpers.
412
export record TestResult: Copy {
413
    /// Diagnostics from semantic analysis.
414
    diagnostics: super::Diagnostics,
415
    /// Root of the parsed test program.
416
    root: *ast::Node,
417
}
418
419
/// Create isolated storage for tests to avoid conflicts with global resolver storage.
420
unsafe fn testStorage() -> super::ResolverStorage {
421
    return super::ResolverStorage {
422
        nodeData: &mut NODE_DATA_STORAGE[..],
423
        pkgScope: &mut PKG_SCOPE,
424
        errors: &mut ERROR_STORAGE[..],
425
    };
426
}
427
428
/// Create an arena owner for one resolver test scope.
429
export unsafe fn testArena() -> alloc::Arena {
430
    return alloc::new(&mut ARENA_STORAGE[..]);
431
}
432
433
/// Construct a resolver backed by test storage and a synthetic module graph.
434
export unsafe fn testResolver 'arena (arena: &'arena mut alloc::Arena) -> super::Resolver 'arena {
435
    // TODO: This should be initialized only once.
436
    for i in 0..LITERALS.len {
437
        strings::intern(&mut STRING_POOL, LITERALS[i]);
438
    }
439
    // TODO: Use local static for this.
440
    // Reset the module graph for each test.
441
    set MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]);
442
    set MODULE_GRAPH = module::moduleGraph(&mut MODULE_ENTRIES[..], &mut MODULE_ARENA);
443
    let config = super::Config { buildTest: true };
444
    let res = super::resolver(arena, testStorage(), config);
445
446
    return res;
447
}
448
449
/// Resolve a block of statements by wrapping them in a synthetic function.
450
unsafe fn resolveStatements 'arena (
451
    self: &mut super::Resolver 'arena, block: ast::Block, arena: &mut ast::NodeArena
452
) -> TestResult throws (super::ResolveError) {
453
    let module = ast::synthFnModule(arena, super::ANALYZE_BLOCK_FN_NAME, block.statements);
454
    let diagnostics = try super::resolveModuleRoot(self, module.modBody) catch {
455
        return TestResult { diagnostics: super::diagnostics(self), root: module.modBody };
456
    };
457
    return TestResult { diagnostics, root: module.fnBody };
458
}
459
460
/// Parse and analyze an expression string for testing.
461
unsafe fn resolveExprStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
462
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
463
    let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in {
464
        let mut p = parser::mkParser(scanner::SourceLoc::String, stmt, arenaRef, poolRef);
465
        parser::advance(&mut p);
466
467
        let expr = try parser::parseExpr(&mut p) catch {
468
            panic "resolveExprStr: parsing failed";
469
        };
470
        let diagnostics = try super::resolveExpr(self, expr, p.arena) catch {
471
            throw testing::TestError::Failed;
472
        };
473
        return TestResult { diagnostics, root: expr };
474
    }
475
}
476
477
/// Parse and analyze a module string for testing.
478
/// Use this for code with `fn`, `record`, `union`, etc. at the top level.
479
export unsafe fn resolveProgramStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
480
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
481
    let stmt: *ast::Node = try parser::parse(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL) catch {
482
        panic "resolveProgramStr: parsing failed";
483
    };
484
    let diagnostics = try super::resolveModuleRoot(self, stmt) catch {
485
        throw testing::TestError::Failed;
486
    };
487
    return TestResult { diagnostics, root: stmt };
488
}
489
490
/// Resolve session diagnostics against the standard allocator declaration contract.
491
export unsafe fn resolveSessionProgramStr 'arena (self: &mut super::Resolver 'arena, program: *[u8]) -> TestResult
492
    throws (testing::TestError)
493
{
494
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
495
    let root = try registerModule(&mut MODULE_GRAPH, nil, "std", "export mod lang; mod app;", &mut arena);
496
    let lang = try registerModule(&mut MODULE_GRAPH, root, "lang", "export mod alloc;", &mut arena);
497
    let allocator = try registerModule(&mut MODULE_GRAPH, lang, "alloc",
498
        "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; } }",
499
        &mut arena);
500
    let app = try registerModule(&mut MODULE_GRAPH, root, "app", program, &mut arena);
501
    return try resolveModuleTree(self, root);
502
}
503
504
/// Parse and analyze a block of statements (eg. inside a function body) for testing.
505
/// Use this for code with `let` bindings and expressions, not module-level declarations.
506
unsafe fn resolveBlockStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
507
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
508
    let parsed = try parser::parse(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL) catch {
509
        panic "resolveBlockStr: parsing failed";
510
    };
511
    let case ast::NodeValue::Block(block) = parsed.value
512
        else panic "resolveBlockStr: expected block root";
513
514
    let analysis = try resolveStatements(self, block, &mut arena) catch {
515
        throw testing::TestError::Failed;
516
    };
517
    return TestResult {
518
        diagnostics: analysis.diagnostics,
519
        root: analysis.root,
520
    };
521
}
522
523
/// Resolve a module with the full resolution process.
524
unsafe fn resolveModuleTree 'arena (
525
    res: &mut super::Resolver 'arena,
526
    rootId: u16
527
) -> TestResult throws (testing::TestError) {
528
    let root = module::get(&MODULE_GRAPH, rootId)
529
        else throw testing::TestError::Failed;
530
    let rootAst = module::astFor(root)
531
        else throw testing::TestError::Failed;
532
    let packages = [super::Pkg {
533
        rootEntry: root,
534
        rootAst,
535
    }];
536
    let diagnostics = try super::resolve(res, &MODULE_GRAPH, &packages[..]) catch {
537
        throw testing::TestError::Failed;
538
    };
539
    return TestResult { diagnostics, root: rootAst };
540
}
541
542
/// Register a module in the graph and attach a parsed AST to it.
543
/// If parentId is nil, registers as a root module.
544
unsafe fn registerModule(
545
    graph: &mut module::ModuleGraph,
546
    parentId: ?u16,
547
    name: *[u8],
548
    code: *[u8],
549
    arena: &mut ast::NodeArena
550
) -> u16 throws (testing::TestError) {
551
    let filePath = "<test>";
552
    let mut modId: u16 = undefined;
553
    if let parent = parentId {
554
        set modId = try module::registerChild(graph, &mut STRING_POOL, parent, name, filePath) catch {
555
            throw testing::TestError::Failed;
556
        };
557
    } else {
558
        set modId = try module::registerRootWithName(graph, &mut STRING_POOL, 0, name, filePath) catch {
559
            throw testing::TestError::Failed;
560
        };
561
    }
562
    let root = try parser::parse(scanner::SourceLoc::String, code, arena, &mut STRING_POOL) catch {
563
        panic "registerModule: parsing failed";
564
    };
565
    try module::setAst(graph, modId, root) catch {
566
        panic "registerModule: module not found";
567
    };
568
    return modId;
569
}
570
571
/// Ensure an expression statement produces the expected type and return the expression node.
572
fn expectExprStmtType 'arena (self: &super::Resolver 'arena, node: *ast::Node, expected: super::Type) -> *ast::Node
573
    throws (testing::TestError)
574
{
575
    let case ast::NodeValue::ExprStmt(expr) = node.value
576
        else throw testing::TestError::Failed;
577
    try expectType(self, expr, expected);
578
579
    return expr;
580
}
581
582
/// Assert that the test result contains no diagnostic errors.
583
export fn expectNoErrors(r: &TestResult) throws (testing::TestError) {
584
    try testing::expect(super::success(&r.diagnostics));
585
}
586
587
/// Extract the first error from a test result, failing if none exists.
588
export fn expectError(result: &TestResult) -> super::Error throws (testing::TestError) {
589
    let err = super::errorAt(&result.diagnostics.errors[..], 0)
590
        else throw testing::TestError::Failed;
591
    return err;
592
}
593
594
/// Check if two error kinds match.
595
fn errorKindMatches(actual: &super::ErrorKind, expected: super::ErrorKind) -> bool {
596
    if let case super::ErrorKind::DuplicateBinding(expectedName) = expected {
597
        if let case super::ErrorKind::DuplicateBinding(actualName) = *actual {
598
            return mem::eq(actualName, expectedName);
599
        }
600
        return false;
601
    }
602
    if let case super::ErrorKind::UnresolvedSymbol(expectedName) = expected {
603
        if let case super::ErrorKind::UnresolvedSymbol(actualName) = *actual {
604
            return mem::eq(actualName, expectedName);
605
        }
606
        return false;
607
    }
608
    if let case super::ErrorKind::RecordFieldMissing(expectedName) = expected {
609
        if let case super::ErrorKind::RecordFieldMissing(actualName) = *actual {
610
            return mem::eq(actualName, expectedName);
611
        }
612
        return false;
613
    }
614
    if let case super::ErrorKind::RecordFieldUnknown(expectedName) = expected {
615
        if let case super::ErrorKind::RecordFieldUnknown(actualName) = *actual {
616
            return mem::eq(actualName, expectedName);
617
        }
618
        return false;
619
    }
620
    if let case super::ErrorKind::ArrayFieldUnknown(expectedName) = expected {
621
        if let case super::ErrorKind::ArrayFieldUnknown(actualName) = *actual {
622
            return mem::eq(actualName, expectedName);
623
        }
624
        return false;
625
    }
626
    if let case super::ErrorKind::SliceFieldUnknown(expectedName) = expected {
627
        if let case super::ErrorKind::SliceFieldUnknown(actualName) = *actual {
628
            return mem::eq(actualName, expectedName);
629
        }
630
        return false;
631
    }
632
    if let case super::ErrorKind::UnionVariantPayloadMissing(expectedName) = expected {
633
        if let case super::ErrorKind::UnionVariantPayloadMissing(actualName) = *actual {
634
            return mem::eq(actualName, expectedName);
635
        }
636
        return false;
637
    }
638
    if let case super::ErrorKind::UnionVariantPayloadUnexpected(expectedName) = expected {
639
        if let case super::ErrorKind::UnionVariantPayloadUnexpected(actualName) = *actual {
640
            return mem::eq(actualName, expectedName);
641
        }
642
        return false;
643
    }
644
    if let case super::ErrorKind::UnionMatchNonExhaustive(expectedName) = expected {
645
        if let case super::ErrorKind::UnionMatchNonExhaustive(actualName) = *actual {
646
            return mem::eq(actualName, expectedName);
647
        }
648
        return false;
649
    }
650
    if let case super::ErrorKind::MissingTraitMethod(expectedName) = expected {
651
        if let case super::ErrorKind::MissingTraitMethod(actualName) = *actual {
652
            return mem::eq(actualName, expectedName);
653
        }
654
        return false;
655
    }
656
    if let case super::ErrorKind::MissingSupertraitInstance(expectedName) = expected {
657
        if let case super::ErrorKind::MissingSupertraitInstance(actualName) = *actual {
658
            return mem::eq(actualName, expectedName);
659
        }
660
        return false;
661
    }
662
    if let case super::ErrorKind::AffineUseAfterMove(expectedName) = expected {
663
        if let case super::ErrorKind::AffineUseAfterMove(actualName) = *actual {
664
            return mem::eq(actualName, expectedName);
665
        }
666
        return false;
667
    }
668
    if let case super::ErrorKind::LinearUseAfterConsume(expectedName) = expected {
669
        if let case super::ErrorKind::LinearUseAfterConsume(actualName) = *actual {
670
            return mem::eq(actualName, expectedName);
671
        }
672
        return false;
673
    }
674
    if let case super::ErrorKind::LinearNotConsumed(expectedName) = expected {
675
        if let case super::ErrorKind::LinearNotConsumed(actualName) = *actual {
676
            return mem::eq(actualName, expectedName);
677
        }
678
        return false;
679
    }
680
    if let case super::ErrorKind::LinearBranchMismatch(expectedName) = expected {
681
        if let case super::ErrorKind::LinearBranchMismatch(actualName) = *actual {
682
            return mem::eq(actualName, expectedName);
683
        }
684
        return false;
685
    }
686
    if let case super::ErrorKind::BorrowConflict(expectedName) = expected {
687
        if let case super::ErrorKind::BorrowConflict(actualName) = *actual {
688
            return mem::eq(actualName, expectedName);
689
        }
690
        return false;
691
    }
692
    return *actual == expected;
693
}
694
695
/// Extract the first error and ensure it has the expected kind.
696
export fn expectErrorKind(result: &TestResult, kind: super::ErrorKind) -> super::Error
697
    throws (testing::TestError)
698
{
699
    let err = try expectError(result);
700
    try testing::expect(errorKindMatches(&err.kind, kind));
701
    return err;
702
}
703
704
/// Ensure an expression resolves to the expected type annotation.
705
fn expectType 'arena (self: &super::Resolver 'arena, expr: *ast::Node, expected: super::Type)
706
    throws (testing::TestError)
707
{
708
    let actual = super::typeFor(self, expr)
709
        else throw testing::TestError::Failed;
710
711
    if actual <> expected {
712
        throw testing::TestError::Failed;
713
    }
714
}
715
716
/// Verify that an error represents a specific type mismatch.
717
fn expectTypeMismatch(err: super::Error, expected: super::Type, actual: super::Type)
718
    throws (testing::TestError)
719
{
720
    let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
721
        else throw testing::TestError::Failed;
722
    try testing::expect(mismatch.expected == expected);
723
    try testing::expect(mismatch.actual == actual);
724
}
725
726
/// Resolve a program and require successful analysis.
727
unsafe fn expectAnalyzeOk(program: *[u8]) throws (testing::TestError) {
728
    let mut testArena1 = testArena();
729
    let testStorage1: 'test1 = &mut testArena1 in {
730
        let mut a = testResolver(testStorage1);
731
        let result = try resolveProgramStr(&mut a, program);
732
        try expectNoErrors(&result);
733
    }
734
}
735
736
/// Require an inferred integer type mismatch.
737
unsafe fn expectIntMismatch(program: *[u8], expected: super::Type)
738
    throws (testing::TestError)
739
{
740
    let mut testArena2 = testArena();
741
    let testStorage2: 'test2 = &mut testArena2 in {
742
        let mut a = testResolver(testStorage2);
743
        let result = try resolveProgramStr(&mut a, program);
744
        let err = try expectError(&result);
745
        try expectTypeMismatch(err, expected, super::Type::Int);
746
    }
747
}
748
749
/// Retrieve the nth statement from a block node.
750
export fn getBlockStmt(block: *ast::Node, index: u32) -> *ast::Node
751
    throws (testing::TestError)
752
{
753
    let case ast::NodeValue::Block(body) = block.value
754
        else throw testing::TestError::Failed;
755
756
    if index >= body.statements.len {
757
        throw testing::TestError::Failed;
758
    }
759
    return body.statements[index];
760
}
761
762
/// Retrieve a function body block by function name from the program scope.
763
unsafe fn getFnBody 'arena (a: &super::Resolver 'arena, root: *ast::Node, name: *[u8]) -> ast::Block
764
    throws (testing::TestError)
765
{
766
    let scope = super::scopeFor(a, root)
767
        else throw testing::TestError::Failed;
768
    let sym = super::findSymbolInScope(scope, name)
769
        else throw testing::TestError::Failed;
770
    // Verify it's a value symbol by pattern matching.
771
    let case super::SymbolData::Value { .. } = sym.data
772
        else throw testing::TestError::Failed;
773
774
    let case ast::NodeValue::FnDecl(fnDecl) = sym.node.value
775
        else throw testing::TestError::Failed;
776
777
    let body = fnDecl.body
778
        else throw testing::TestError::Failed;
779
    let case ast::NodeValue::Block(blk) = body.value
780
        else throw testing::TestError::Failed;
781
782
    return blk;
783
}
784
785
/// Get the payload type of a union variant, if it has one.
786
/// For single-field unlabeled variants like `Variant(i32)`, unwraps to return the inner type.
787
unsafe fn getUnionVariantPayload(nominalTy: *unsafe super::NominalType, variantName: *[u8]) -> super::Type {
788
    let case super::NominalType::Union(unionType) = *nominalTy
789
        else panic "getUnionVariantPayload: not a union";
790
    for i in 0..unionType.variants.len {
791
        if mem::eq(unionType.variants[i].name, variantName) {
792
            let payloadType = unionType.variants[i].valueType;
793
            // Unwrap single-field unlabeled records to get the inner type.
794
            if let case super::Type::Nominal(super::NominalType::Record(recInfo)) = payloadType {
795
                if not recInfo.labeled and recInfo.fields.len == 1 {
796
                    return recInfo.fields[0].fieldType;
797
                }
798
            }
799
            return payloadType;
800
        }
801
    }
802
    panic "getUnionVariantPayload: variant not found";
803
}
804
805
/// Get a nominal type by name, in the scope of the given block node.
806
unsafe fn getTypeInScopeOf 'arena (a: &super::Resolver 'arena, blk: *ast::Node, name: *[u8]) -> *unsafe super::NominalType
807
    throws (testing::TestError)
808
{
809
    let scope = super::scopeFor(a, blk)
810
        else throw testing::TestError::Failed;
811
    let sym = super::findSymbolInScope(scope, name)
812
        else throw testing::TestError::Failed;
813
    let case super::SymbolData::Type(ty) = sym.data
814
        else throw testing::TestError::Failed;
815
    return ty;
816
}
817
818
/// Return the resolved type of a syntax node.
819
fn typeOf 'arena (a: &super::Resolver 'arena, node: *ast::Node) -> super::Type
820
    throws (testing::TestError)
821
{
822
    let ty = super::typeFor(a, node)
823
        else throw testing::TestError::Failed;
824
    return ty;
825
}
826
827
/// Require an array type and return its element type.
828
fn expectArrayType(ty: super::Type, length: u32) -> super::Type
829
    throws (testing::TestError)
830
{
831
    let case super::Type::Array(info) = ty
832
        else throw testing::TestError::Failed;
833
    try testing::expect(info.length == length);
834
835
    return *info.item;
836
}
837
838
/// Require a slice type and return its element type.
839
fn expectSliceType(ty: super::Type, mutable: bool) -> super::Type
840
    throws (testing::TestError)
841
{
842
    let case super::Type::Slice { item, mutable: sliceMut, .. } = ty
843
        else throw testing::TestError::Failed;
844
    try testing::expect(sliceMut == mutable);
845
846
    return *item;
847
}
848
849
/// Require a pointer type and return its target type.
850
fn expectPointerType(ty: super::Type, mutable: bool) -> super::Type
851
    throws (testing::TestError)
852
{
853
    let case super::Type::Pointer { target, mutable: ptrMut, .. } = ty
854
        else throw testing::TestError::Failed;
855
    try testing::expect(ptrMut == mutable);
856
857
    return *target;
858
}
859
860
/// Verify that a node has a constant integer value with the expected magnitude.
861
fn expectConstInt 'arena (a: &super::Resolver 'arena, node: *ast::Node, expected: u32)
862
    throws (testing::TestError)
863
{
864
    let constVal = super::constValueEntry(a, node)
865
        else throw testing::TestError::Failed;
866
867
    let case super::ConstValue::Int(int) = constVal
868
        else throw testing::TestError::Failed;
869
870
    try testing::expect(int.magnitude == expected);
871
}
872
873
/// Resolve an expression that should evaluate to a constant, and verify it equals the expected value.
874
unsafe fn resolveAndExpectConstExpr(expr: *[u8], expected: u32)
875
    throws (testing::TestError)
876
{
877
    let mut testArena3 = testArena();
878
    let testStorage3: 'test3 = &mut testArena3 in {
879
        let mut a = testResolver(testStorage3);
880
        let result = try resolveExprStr(&mut a, expr);
881
        try expectNoErrors(&result);
882
        try expectType(&a, result.root, super::Type::U32);
883
        try expectConstInt(&a, result.root, expected);
884
    }
885
}
886
887
/// Resolve a statement that should evaluate to a constant, and verify it equals the expected value.
888
unsafe fn resolveAndExpectConstStmt(expr: *[u8], expected: u32)
889
    throws (testing::TestError)
890
{
891
    let mut testArena4 = testArena();
892
    let testStorage4: 'test4 = &mut testArena4 in {
893
        let mut a = testResolver(testStorage4);
894
        let result = try resolveProgramStr(&mut a, expr);
895
        try expectNoErrors(&result);
896
        let stmt = try getBlockStmt(result.root, 1);
897
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
898
        try expectConstInt(&a, expr, expected);
899
    }
900
}
901
902
// Tests ///////////////////////////////////////////////////////////////////////
903
904
@test unsafe fn testResolveLit() throws (testing::TestError) {
905
    let mut testArena5 = testArena();
906
    let testStorage5: 'test5 = &mut testArena5 in {
907
        let mut a = testResolver(testStorage5);
908
        let result = try resolveExprStr(&mut a, "true");
909
910
        try expectNoErrors(&result);
911
        try expectType(&a, result.root, super::Type::Bool);
912
    }
913
}
914
915
@test unsafe fn testResolveStringLiteralType() throws (testing::TestError) {
916
    let mut testArena6 = testArena();
917
    let testStorage6: 'test6 = &mut testArena6 in {
918
        let mut a = testResolver(testStorage6);
919
        let result = try resolveExprStr(&mut a, "\"hello\"");
920
921
        try expectNoErrors(&result);
922
        let ty = try typeOf(&a, result.root);
923
        let elemTy = try expectSliceType(ty, false);
924
        try testing::expect(elemTy == super::Type::U8);
925
    }
926
}
927
928
@test unsafe fn testResolveAsNumeric() throws (testing::TestError) {
929
    {
930
        let mut testArena7 = testArena();
931
        let testStorage7: 'test7 = &mut testArena7 in {
932
            let mut a = testResolver(testStorage7);
933
            let result = try resolveExprStr(&mut a, "1 as u32");
934
            try expectNoErrors(&result);
935
            try expectType(&a, result.root, super::Type::U32);
936
        }
937
    } {
938
        let mut testArena8 = testArena();
939
        let testStorage8: 'test8 = &mut testArena8 in {
940
            let mut a = testResolver(testStorage8);
941
            let result = try resolveBlockStr(&mut a, "let x: u32 = 913; x as u8;");
942
            try expectNoErrors(&result);
943
944
            let x = try getBlockStmt(result.root, 1);
945
            try expectExprStmtType(&a, x, super::Type::U8);
946
        }
947
    }
948
}
949
950
@test unsafe fn testResolveAsInvalid() throws (testing::TestError) {
951
    let mut testArena9 = testArena();
952
    let testStorage9: 'test9 = &mut testArena9 in {
953
        let mut a = testResolver(testStorage9);
954
        let result = try resolveProgramStr(&mut a, "true as u32");
955
956
        try expectErrorKind(
957
            &result,
958
            super::ErrorKind::InvalidAsCast(super::InvalidAsCast {
959
                from: super::Type::Bool,
960
                to: super::Type::U32,
961
        })
962
        );
963
    }
964
}
965
966
@test unsafe fn testResolveAsUnionToInt() throws (testing::TestError) {
967
    let mut testArena10 = testArena();
968
    let testStorage10: 'test10 = &mut testArena10 in {
969
        let mut a = testResolver(testStorage10);
970
        let program = "union Color { Red } Color::Red as u32;";
971
        let result = try resolveProgramStr(&mut a, program);
972
        try expectNoErrors(&result);
973
974
        let red = try getBlockStmt(result.root, 1);
975
        try expectExprStmtType(&a, red, super::Type::U32);
976
    }
977
}
978
979
@test unsafe fn testResolveBinding() throws (testing::TestError) {
980
    let mut testArena11 = testArena();
981
    let testStorage11: 'test11 = &mut testArena11 in {
982
        let mut a = testResolver(testStorage11);
983
        let result = try resolveBlockStr(&mut a, "let x: bool = true; x;");
984
        let stmt = try parser::tests::getBlockLastStmt(result.root);
985
986
        try expectNoErrors(&result);
987
        try expectType(&a, stmt, super::Type::Void);
988
        try expectExprStmtType(&a, stmt, super::Type::Bool);
989
990
        let case ast::NodeValue::ExprStmt(x) = stmt.value
991
            else throw testing::TestError::Failed;
992
993
        let sym = super::symbolFor(&a, x)
994
            else throw testing::TestError::Failed;
995
        let case super::SymbolData::Value { type: valType, .. } = sym.data
996
            else throw testing::TestError::Failed;
997
        try testing::expect(valType == super::Type::Bool);
998
    }
999
}
1000
1001
@test unsafe fn testResolveBindingInvalid() throws (testing::TestError) {
1002
    let mut testArena12 = testArena();
1003
    let testStorage12: 'test12 = &mut testArena12 in {
1004
        let mut a = testResolver(testStorage12);
1005
        let result = try resolveBlockStr(&mut a, "let x: i32 = true;");
1006
        let err = try expectError(&result);
1007
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
1008
    }
1009
}
1010
1011
@test unsafe fn testResolveDuplicateBinding() throws (testing::TestError) {
1012
    let mut testArena13 = testArena();
1013
    let testStorage13: 'test13 = &mut testArena13 in {
1014
        let mut a = testResolver(testStorage13);
1015
        let result = try resolveBlockStr(&mut a, "let x: bool = true; let x: u8 = 1;");
1016
        let stmt = try parser::tests::getBlockLastStmt(result.root);
1017
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("x"));
1018
    }
1019
}
1020
1021
@test unsafe fn testResolveConstLiteralValue() throws (testing::TestError) {
1022
    let mut testArena14 = testArena();
1023
    let testStorage14: 'test14 = &mut testArena14 in {
1024
        let mut a = testResolver(testStorage14);
1025
        let program = "constant ANSWER: i32 = 42;";
1026
        let result = try resolveProgramStr(&mut a, program);
1027
        try expectNoErrors(&result);
1028
1029
        let constNode = try getBlockStmt(result.root, 0);
1030
        let sym = super::symbolFor(&a, constNode)
1031
            else throw testing::TestError::Failed;
1032
        let case super::SymbolData::Constant { type: constType, .. } = sym.data
1033
            else throw testing::TestError::Failed;
1034
        try testing::expect(constType == super::Type::I32);
1035
    }
1036
}
1037
1038
@test unsafe fn testResolveConstRequiresConstantExpr() throws (testing::TestError) {
1039
    let mut testArena15 = testArena();
1040
    let testStorage15: 'test15 = &mut testArena15 in {
1041
        let mut a = testResolver(testStorage15);
1042
        let program = "fn value() -> i32 { return 1 } fn main() { constant ANSWER: i32 = value(); }";
1043
        let result = try resolveProgramStr(&mut a, program);
1044
        let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
1045
1046
        let errNode = err.node
1047
            else throw testing::TestError::Failed;
1048
        let case ast::NodeValue::Call(_) = errNode.value
1049
            else throw testing::TestError::Failed;
1050
    }
1051
}
1052
1053
@test unsafe fn testResolveStaticLiteralValue() throws (testing::TestError) {
1054
    let mut testArena16 = testArena();
1055
    let testStorage16: 'test16 = &mut testArena16 in {
1056
        let mut a = testResolver(testStorage16);
1057
        let program = "static COUNTER: i32 = 0;";
1058
        let result = try resolveProgramStr(&mut a, program);
1059
        try expectNoErrors(&result);
1060
1061
        let staticNode = try getBlockStmt(result.root, 0);
1062
        let sym = super::symbolFor(&a, staticNode)
1063
            else throw testing::TestError::Failed;
1064
        let case super::SymbolData::Value { type: valType, .. } = sym.data
1065
            else throw testing::TestError::Failed;
1066
        try testing::expect(valType == super::Type::I32);
1067
    }
1068
}
1069
1070
@test unsafe fn testResolveStaticRequiresConstantExpr() throws (testing::TestError) {
1071
    let mut testArena17 = testArena();
1072
    let testStorage17: 'test17 = &mut testArena17 in {
1073
        let mut a = testResolver(testStorage17);
1074
        let program = "fn seed() -> i32 { return 1; } static COUNTER: i32 = seed();";
1075
        let result = try resolveProgramStr(&mut a, program);
1076
        let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
1077
1078
        let errNode = err.node
1079
            else throw testing::TestError::Failed;
1080
        let case ast::NodeValue::Call(_) = errNode.value
1081
            else throw testing::TestError::Failed;
1082
    }
1083
}
1084
1085
@test unsafe fn testSymbolStoresFnAttributes() throws (testing::TestError) {
1086
    let mut testArena18 = testArena();
1087
    let testStorage18: 'test18 = &mut testArena18 in {
1088
        let mut a = testResolver(testStorage18);
1089
        let program = "@default export fn f() { return; }";
1090
        let result = try resolveProgramStr(&mut a, program);
1091
        try expectNoErrors(&result);
1092
1093
        let scope = super::scopeFor(&a, result.root)
1094
            else throw testing::TestError::Failed;
1095
        let sym = super::findSymbolInScope(scope, "f")
1096
            else throw testing::TestError::Failed;
1097
1098
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Export));
1099
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Default));
1100
        try testing::expectNot(ast::hasAttribute(sym.attrs, ast::Attribute::Extern));
1101
    }
1102
}
1103
1104
@test unsafe fn testSymbolStoresRecordAttributes() throws (testing::TestError) {
1105
    let mut testArena19 = testArena();
1106
    let testStorage19: 'test19 = &mut testArena19 in {
1107
        let mut a = testResolver(testStorage19);
1108
        let program = "export record S { value: i32 }";
1109
        let result = try resolveProgramStr(&mut a, program);
1110
        try expectNoErrors(&result);
1111
1112
        let scope = super::scopeFor(&a, result.root)
1113
            else throw testing::TestError::Failed;
1114
        let sym = super::findSymbolInScope(scope, "S")
1115
            else throw testing::TestError::Failed;
1116
1117
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Export));
1118
        try testing::expectNot(ast::hasAttribute(sym.attrs, ast::Attribute::Default));
1119
    }
1120
}
1121
1122
@test unsafe fn testDefaultAttributeRejectedOnRecord() throws (testing::TestError) {
1123
    let mut testArena20 = testArena();
1124
    let testStorage20: 'test20 = &mut testArena20 in {
1125
        let mut a = testResolver(testStorage20);
1126
        let program = "@default record T { value: i32 }";
1127
        let result = try resolveProgramStr(&mut a, program);
1128
        try expectErrorKind(&result, super::ErrorKind::DefaultAttrOnlyOnFn);
1129
    }
1130
}
1131
1132
@test unsafe fn testDefaultAttributeRejectedOnUnion() throws (testing::TestError) {
1133
    let mut testArena21 = testArena();
1134
    let testStorage21: 'test21 = &mut testArena21 in {
1135
        let mut a = testResolver(testStorage21);
1136
        let program = "@default union Result { Ok, Err }";
1137
        let result = try resolveProgramStr(&mut a, program);
1138
        try expectErrorKind(&result, super::ErrorKind::DefaultAttrOnlyOnFn);
1139
    }
1140
}
1141
1142
@test unsafe fn testResolveArrayLiteralTyped() throws (testing::TestError) {
1143
    let mut testArena22 = testArena();
1144
    let testStorage22: 'test22 = &mut testArena22 in {
1145
        let mut a = testResolver(testStorage22);
1146
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1, 2];");
1147
        try expectNoErrors(&result);
1148
1149
        let stmt = try getBlockStmt(result.root, 0);
1150
        let case ast::NodeValue::Let(decl) = stmt.value
1151
            else throw testing::TestError::Failed;
1152
        let arrayTy = try typeOf(&a, decl.value);
1153
        let elemTy = try expectArrayType(arrayTy, 2);
1154
        try testing::expect(elemTy == super::Type::I32);
1155
    }
1156
}
1157
1158
@test unsafe fn testResolveArrayLiteralElementMismatch() throws (testing::TestError) {
1159
    let mut testArena23 = testArena();
1160
    let testStorage23: 'test23 = &mut testArena23 in {
1161
        let mut a = testResolver(testStorage23);
1162
        let result = try resolveProgramStr(&mut a, "let xs: [bool; 2] = [true, 1];");
1163
        let err = try expectError(&result);
1164
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1165
    }
1166
}
1167
1168
@test unsafe fn testResolveArrayLiteralCannotInfer() throws (testing::TestError) {
1169
    let mut testArena24 = testArena();
1170
    let testStorage24: 'test24 = &mut testArena24 in {
1171
        let mut a = testResolver(testStorage24);
1172
        let result = try resolveProgramStr(&mut a, "let xs = [1, 2];");
1173
        try expectErrorKind(&result, super::ErrorKind::CannotInferType);
1174
    }
1175
}
1176
1177
@test unsafe fn testResolveArrayLiteralOverflow() throws (testing::TestError) {
1178
    let mut testArena25 = testArena();
1179
    let testStorage25: 'test25 = &mut testArena25 in {
1180
        let mut a = testResolver(testStorage25);
1181
        let result = try resolveProgramStr(&mut a, "let xs: [u8; 2] = [1, 256];");
1182
        let err = try expectError(&result);
1183
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1184
            else throw testing::TestError::Failed;
1185
    }
1186
}
1187
1188
@test unsafe fn testResolveArrayLiteralTooFewElements() throws (testing::TestError) {
1189
    let mut testArena26 = testArena();
1190
    let testStorage26: 'test26 = &mut testArena26 in {
1191
        let mut a = testResolver(testStorage26);
1192
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1];");
1193
        let err = try expectError(&result);
1194
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1195
            else throw testing::TestError::Failed;
1196
    }
1197
}
1198
1199
@test unsafe fn testResolveArrayLiteralTooManyElements() throws (testing::TestError) {
1200
    let mut testArena27 = testArena();
1201
    let testStorage27: 'test27 = &mut testArena27 in {
1202
        let mut a = testResolver(testStorage27);
1203
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1, 2, 3];");
1204
        let err = try expectError(&result);
1205
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1206
            else throw testing::TestError::Failed;
1207
    }
1208
}
1209
1210
@test unsafe fn testResolveArrayLiteralEmptyWithAnnotation() throws (testing::TestError) {
1211
    let mut testArena28 = testArena();
1212
    let testStorage28: 'test28 = &mut testArena28 in {
1213
        let mut a = testResolver(testStorage28);
1214
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 0] = [];");
1215
        try expectNoErrors(&result);
1216
    }
1217
}
1218
1219
@test unsafe fn testResolveNestedArrayLiteralTyped() throws (testing::TestError) {
1220
    let mut testArena29 = testArena();
1221
    let testStorage29: 'test29 = &mut testArena29 in {
1222
        let mut a = testResolver(testStorage29);
1223
        let result = try resolveProgramStr(&mut a, "let grid: [[i32; 2]; 2] = [[1, 2], [3, 4]];");
1224
        try expectNoErrors(&result);
1225
1226
        let stmt = try getBlockStmt(result.root, 0);
1227
        let case ast::NodeValue::Let(decl) = stmt.value
1228
            else throw testing::TestError::Failed;
1229
        let gridTy = try typeOf(&a, decl.value);
1230
        let rowTy = try expectArrayType(gridTy, 2);
1231
        let elemTy = try expectArrayType(rowTy, 2);
1232
        try testing::expect(elemTy == super::Type::I32);
1233
    }
1234
}
1235
1236
@test unsafe fn testResolveArrayLiteralWithOptionalElems() throws (testing::TestError) {
1237
    let mut testArena30 = testArena();
1238
    let testStorage30: 'test30 = &mut testArena30 in {
1239
        let mut a = testResolver(testStorage30);
1240
        let result = try resolveProgramStr(&mut a, "let xs: [?i32; 2] = [1, 2];");
1241
        try expectNoErrors(&result);
1242
1243
        let stmt = try getBlockStmt(result.root, 0);
1244
        let case ast::NodeValue::Let(decl) = stmt.value
1245
            else throw testing::TestError::Failed;
1246
        let arrayTy = try typeOf(&a, decl.value);
1247
        let elemTy = try expectArrayType(arrayTy, 2);
1248
        let case super::Type::Optional(inner) = elemTy
1249
            else throw testing::TestError::Failed;
1250
        try testing::expect(*inner == super::Type::I32);
1251
    }
1252
}
1253
1254
@test unsafe fn testResolveArrayLiteralOptionalMismatch() throws (testing::TestError) {
1255
    let mut testArena31 = testArena();
1256
    let testStorage31: 'test31 = &mut testArena31 in {
1257
        let mut a = testResolver(testStorage31);
1258
        let result = try resolveProgramStr(&mut a, "let xs: [?bool; 2] = [1, 2];");
1259
        let err = try expectError(&result);
1260
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1261
            else throw testing::TestError::Failed;
1262
    }
1263
}
1264
1265
@test unsafe fn testResolveArrayRepeatBasic() throws (testing::TestError) {
1266
    let mut testArena32 = testArena();
1267
    let testStorage32: 'test32 = &mut testArena32 in {
1268
        let mut a = testResolver(testStorage32);
1269
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 3] = [42; 3];");
1270
        try expectNoErrors(&result);
1271
1272
        let stmt = try getBlockStmt(result.root, 0);
1273
        let case ast::NodeValue::Let(decl) = stmt.value
1274
            else throw testing::TestError::Failed;
1275
        let arrayTy = try typeOf(&a, decl.value);
1276
        let elemTy = try expectArrayType(arrayTy, 3);
1277
        try testing::expect(elemTy == super::Type::I32);
1278
    }
1279
}
1280
1281
@test unsafe fn testResolveArrayRepeatWithExpression() throws (testing::TestError) {
1282
    let mut testArena33 = testArena();
1283
    let testStorage33: 'test33 = &mut testArena33 in {
1284
        let mut a = testResolver(testStorage33);
1285
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 5] = [3 + 2; 5];");
1286
        try expectNoErrors(&result);
1287
1288
        let stmt = try getBlockStmt(result.root, 0);
1289
        let case ast::NodeValue::Let(decl) = stmt.value
1290
            else throw testing::TestError::Failed;
1291
        let arrayTy = try typeOf(&a, decl.value);
1292
        let elemTy = try expectArrayType(arrayTy, 5);
1293
        try testing::expect(elemTy == super::Type::I32);
1294
    }
1295
}
1296
1297
@test unsafe fn testResolveArrayRepeatLiteralArithmetic() throws (testing::TestError) {
1298
    let mut testArena34 = testArena();
1299
    let testStorage34: 'test34 = &mut testArena34 in {
1300
        let mut a = testResolver(testStorage34);
1301
        // `3 * 1` folds to a compile-time constant, so the repeat count is valid.
1302
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 3] = [42; 3 * 1];");
1303
        try expectNoErrors(&result);
1304
    }
1305
}
1306
1307
@test unsafe fn testResolveArrayRepeatNonConstCount() throws (testing::TestError) {
1308
    let mut testArena35 = testArena();
1309
    let testStorage35: 'test35 = &mut testArena35 in {
1310
        let mut a = testResolver(testStorage35);
1311
        // A function call is not a constant expression.
1312
        let result = try resolveProgramStr(&mut a, "fn f() -> u32 { return 3; } let xs: [i32; 3] = [42; f()];");
1313
        try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
1314
    }
1315
}
1316
1317
@test unsafe fn testResolveArrayRepeatCountMismatch() throws (testing::TestError) {
1318
    let mut testArena36 = testArena();
1319
    let testStorage36: 'test36 = &mut testArena36 in {
1320
        let mut a = testResolver(testStorage36);
1321
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 4] = [1; 3];");
1322
        let err = try expectError(&result);
1323
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1324
            else throw testing::TestError::Failed;
1325
    }
1326
}
1327
1328
@test unsafe fn testResolveArrayIndex() throws (testing::TestError) {
1329
    let mut testArena37 = testArena();
1330
    let testStorage37: 'test37 = &mut testArena37 in {
1331
        let mut a = testResolver(testStorage37);
1332
        let program = "let xs: [i32; 3] = [1, 2, 3]; xs[1];";
1333
        let result = try resolveProgramStr(&mut a, program);
1334
        try expectNoErrors(&result);
1335
1336
        let stmt = try getBlockStmt(result.root, 1);
1337
        try expectExprStmtType(&a, stmt, super::Type::I32);
1338
    }
1339
}
1340
1341
@test unsafe fn testResolveSliceIndex() throws (testing::TestError) {
1342
    let mut testArena38 = testArena();
1343
    let testStorage38: 'test38 = &mut testArena38 in {
1344
        let mut a = testResolver(testStorage38);
1345
        let program = "static xs: [i32; 4] = [1, 2, 3, 4]; let slice = &xs[1..]; slice[1];";
1346
        let result = try resolveProgramStr(&mut a, program);
1347
        try expectNoErrors(&result);
1348
1349
        let sliceStmt = try getBlockStmt(result.root, 1);
1350
        let case ast::NodeValue::Let(sliceDecl) = sliceStmt.value
1351
            else throw testing::TestError::Failed;
1352
        let sliceTy = try typeOf(&a, sliceDecl.value);
1353
        let elemTy = try expectSliceType(sliceTy, false);
1354
        try testing::expect(elemTy == super::Type::I32);
1355
1356
        let indexStmt = try getBlockStmt(result.root, 2);
1357
        try expectExprStmtType(&a, indexStmt, super::Type::I32);
1358
    }
1359
}
1360
1361
@test unsafe fn testResolveSliceFields() throws (testing::TestError) {
1362
    let mut testArena39 = testArena();
1363
    let testStorage39: 'test39 = &mut testArena39 in {
1364
        let mut a = testResolver(testStorage39);
1365
        let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[1..]; slice.len; unsafe { slice.ptr; }";
1366
        let result = try resolveProgramStr(&mut a, program);
1367
        try expectNoErrors(&result);
1368
1369
        let lenStmt = try getBlockStmt(result.root, 2);
1370
        let case ast::NodeValue::ExprStmt(lenExpr) = lenStmt.value
1371
            else throw testing::TestError::Failed;
1372
        let lenTy = try typeOf(&a, lenExpr);
1373
        try testing::expect(lenTy == super::Type::U32);
1374
1375
        let ptrStmt = try getBlockStmt(result.root, 3);
1376
        let case ast::NodeValue::Block(ptrBlock) = ptrStmt.value
1377
            else throw testing::TestError::Failed;
1378
        let case ast::NodeValue::ExprStmt(ptrExpr) = ptrBlock.statements[0].value
1379
            else throw testing::TestError::Failed;
1380
        let ptrTy = try typeOf(&a, ptrExpr);
1381
        let targetTy = try expectPointerType(ptrTy, false);
1382
        try testing::expect(targetTy == super::Type::I32);
1383
    }
1384
}
1385
1386
@test unsafe fn testResolveSliceLiteralImmutable() throws (testing::TestError) {
1387
    let mut testArena40 = testArena();
1388
    let testStorage40: 'test40 = &mut testArena40 in {
1389
        let mut a = testResolver(testStorage40);
1390
        let program = "let slice: *[i32] = &[1, 2, 3];";
1391
        let result = try resolveProgramStr(&mut a, program);
1392
        try expectNoErrors(&result);
1393
    }
1394
}
1395
1396
/// Empty array literal infers element type from slice annotation.
1397
@test unsafe fn testResolveSliceLiteralEmpty() throws (testing::TestError) {
1398
    let mut testArena41 = testArena();
1399
    let testStorage41: 'test41 = &mut testArena41 in {
1400
        let mut a = testResolver(testStorage41);
1401
        let program = "let slice: *[i32] = &[];";
1402
        let result = try resolveProgramStr(&mut a, program);
1403
        try expectNoErrors(&result);
1404
    }
1405
}
1406
1407
/// Nested array literal should infer inner element type from slice annotation.
1408
@test unsafe fn testResolveSliceLiteralNestedArray() throws (testing::TestError) {
1409
    let mut testArena42 = testArena();
1410
    let testStorage42: 'test42 = &mut testArena42 in {
1411
        let mut a = testResolver(testStorage42);
1412
        let program = "let slice: *[[i32; 2]] = &[[1, 2], [3, 4]];";
1413
        let result = try resolveProgramStr(&mut a, program);
1414
        try expectNoErrors(&result);
1415
    }
1416
}
1417
1418
@test unsafe fn testResolveSliceFromArray() throws (testing::TestError) {
1419
    {
1420
        let mut testArena43 = testArena();
1421
        let testStorage43: 'test43 = &mut testArena43 in {
1422
            let mut a = testResolver(testStorage43);
1423
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[..];";
1424
            let result = try resolveProgramStr(&mut a, program);
1425
            try expectNoErrors(&result);
1426
        }
1427
    } {
1428
        let mut testArena44 = testArena();
1429
        let testStorage44: 'test44 = &mut testArena44 in {
1430
            let mut a = testResolver(testStorage44);
1431
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[0..3];";
1432
            let result = try resolveProgramStr(&mut a, program);
1433
            try expectNoErrors(&result);
1434
        }
1435
    } {
1436
        let mut testArena45 = testArena();
1437
        let testStorage45: 'test45 = &mut testArena45 in {
1438
            let mut a = testResolver(testStorage45);
1439
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[..3];";
1440
            let result = try resolveProgramStr(&mut a, program);
1441
            try expectNoErrors(&result);
1442
        }
1443
    } {
1444
        let mut testArena46 = testArena();
1445
        let testStorage46: 'test46 = &mut testArena46 in {
1446
            let mut a = testResolver(testStorage46);
1447
            let program = "static xs: [u8; 2] = [1, 2]; let slice = &xs[1..1];";
1448
            let result = try resolveProgramStr(&mut a, program);
1449
            try expectNoErrors(&result);
1450
        }
1451
    }
1452
}
1453
1454
@test unsafe fn testResolveSliceLiteralMutableRequiresMut() throws (testing::TestError) {
1455
    let mut testArena47 = testArena();
1456
    let testStorage47: 'test47 = &mut testArena47 in {
1457
        let mut a = testResolver(testStorage47);
1458
        let program = "let slice: *mut [i32] = &[1, 2, 3];";
1459
        let result = try resolveProgramStr(&mut a, program);
1460
        let err = try expectError(&result);
1461
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1462
            else throw testing::TestError::Failed;
1463
    }
1464
}
1465
1466
@test unsafe fn testResolveSliceLiteralMutable() throws (testing::TestError) {
1467
    let mut testArena48 = testArena();
1468
    let testStorage48: 'test48 = &mut testArena48 in {
1469
        let mut a = testResolver(testStorage48);
1470
        let program = "let slice: *mut [i32] = &mut [1, 2, 3];";
1471
        let result = try resolveProgramStr(&mut a, program);
1472
        try expectNoErrors(&result);
1473
    }
1474
}
1475
1476
@test unsafe fn testResolvePointerMutableAssignmentRequiresMut() throws (testing::TestError) {
1477
    let mut testArena49 = testArena();
1478
    let testStorage49: 'test49 = &mut testArena49 in {
1479
        let mut a = testResolver(testStorage49);
1480
        let program = "let x: i32 = 0; let ptr: *mut i32 = &x;";
1481
        let result = try resolveProgramStr(&mut a, program);
1482
        let err = try expectError(&result);
1483
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1484
            else throw testing::TestError::Failed;
1485
    }
1486
}
1487
1488
@test unsafe fn testResolvePointerMutableToImmutableAssignment() throws (testing::TestError) {
1489
    let mut testArena50 = testArena();
1490
    let testStorage50: 'test50 = &mut testArena50 in {
1491
        let mut a = testResolver(testStorage50);
1492
        let program = "static x: i32 = 0; let mptr: *mut i32 = &mut x; let ptr: *i32 = mptr;";
1493
        let result = try resolveProgramStr(&mut a, program);
1494
        try expectNoErrors(&result);
1495
    }
1496
}
1497
1498
@test unsafe fn testResolveAddressOfRequiresMutableBinding() throws (testing::TestError) {
1499
    {
1500
        let mut testArena51 = testArena();
1501
        let testStorage51: 'test51 = &mut testArena51 in {
1502
            let mut a = testResolver(testStorage51);
1503
            let program = "let x: i32 = 0; let ptr = &mut x;";
1504
            let result = try resolveProgramStr(&mut a, program);
1505
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1506
        }
1507
    } {
1508
        let mut testArena52 = testArena();
1509
        let testStorage52: 'test52 = &mut testArena52 in {
1510
            let mut a = testResolver(testStorage52);
1511
            let program = "let mut x: i32 = 0; &mut x;";
1512
            let result = try resolveProgramStr(&mut a, program);
1513
            try expectNoErrors(&result);
1514
        }
1515
    }
1516
}
1517
1518
@test unsafe fn testResolveAddressOfSliceRequiresMutableBinding() throws (testing::TestError) {
1519
    {
1520
        let mut testArena53 = testArena();
1521
        let testStorage53: 'test53 = &mut testArena53 in {
1522
            let mut a = testResolver(testStorage53);
1523
            let program = "let xs: [i32; 3] = [1, 2, 3]; let slice = &mut xs[..];";
1524
            let result = try resolveProgramStr(&mut a, program);
1525
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1526
        }
1527
    } {
1528
        let mut testArena54 = testArena();
1529
        let testStorage54: 'test54 = &mut testArena54 in {
1530
            let mut a = testResolver(testStorage54);
1531
            let program = "let mut xs: [i32; 3] = [1, 2, 3]; &mut xs[..];";
1532
            let result = try resolveProgramStr(&mut a, program);
1533
            try expectNoErrors(&result);
1534
        }
1535
    }
1536
}
1537
1538
@test unsafe fn testResolveSliceCannotAssignToArray() throws (testing::TestError) {
1539
    let mut testArena55 = testArena();
1540
    let testStorage55: 'test55 = &mut testArena55 in {
1541
        let mut a = testResolver(testStorage55);
1542
        let program = "let xs: *[u8] = &[1, 2]; let ys: [u8; 2] = xs;";
1543
        let result = try resolveProgramStr(&mut a, program);
1544
        let err = try expectError(&result);
1545
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1546
            else throw testing::TestError::Failed;
1547
    }
1548
}
1549
1550
@test unsafe fn testResolveSliceSyntaxRequiresAddressOf() throws (testing::TestError) {
1551
    let mut testArena56 = testArena();
1552
    let testStorage56: 'test56 = &mut testArena56 in {
1553
        let mut a = testResolver(testStorage56);
1554
        let program = "let xs: [u8; 2] = [1, 2]; xs[..];";
1555
        let result = try resolveProgramStr(&mut a, program);
1556
        try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
1557
    }
1558
}
1559
1560
@test unsafe fn testResolveSliceResliceRequiresAddressOf() throws (testing::TestError) {
1561
    let mut testArena57 = testArena();
1562
    let testStorage57: 'test57 = &mut testArena57 in {
1563
        let mut a = testResolver(testStorage57);
1564
        let program = "fn f(s: *[u8]) -> *[u8] { return s[..]; }";
1565
        let result = try resolveProgramStr(&mut a, program);
1566
        try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
1567
    }
1568
}
1569
1570
@test unsafe fn testResolveSliceRangeOutOfBounds() throws (testing::TestError) {
1571
    {
1572
        let mut testArena58 = testArena();
1573
        let testStorage58: 'test58 = &mut testArena58 in {
1574
            let mut a = testResolver(testStorage58);
1575
            let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[..3];";
1576
            let result = try resolveProgramStr(&mut a, program);
1577
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1578
        }
1579
    } {
1580
        let mut testArena59 = testArena();
1581
        let testStorage59: 'test59 = &mut testArena59 in {
1582
            let mut a = testResolver(testStorage59);
1583
            let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[3..];";
1584
            let result = try resolveProgramStr(&mut a, program);
1585
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1586
        }
1587
    } {
1588
        let mut testArena60 = testArena();
1589
        let testStorage60: 'test60 = &mut testArena60 in {
1590
            let mut a = testResolver(testStorage60);
1591
            let program = "let xs: [u8; 4] = [1, 2, 3, 4]; let slice = &xs[3..2];";
1592
            let result = try resolveProgramStr(&mut a, program);
1593
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1594
        }
1595
    }
1596
}
1597
1598
@test unsafe fn testResolveArrayLenConstValue() throws (testing::TestError) {
1599
    let mut testArena61 = testArena();
1600
    let testStorage61: 'test61 = &mut testArena61 in {
1601
        let mut a = testResolver(testStorage61);
1602
        let program = "let xs: [i32; 3] = [1, 2, 3]; constant LEN: u32 = xs.len;";
1603
        let result = try resolveBlockStr(&mut a, program);
1604
        try expectNoErrors(&result);
1605
1606
        let constStmt = try getBlockStmt(result.root, 1);
1607
        let case ast::NodeValue::ConstDecl(decl) = constStmt.value
1608
            else throw testing::TestError::Failed;
1609
        let valueConst = super::constValueEntry(&a, decl.value)
1610
            else throw testing::TestError::Failed;
1611
        let case super::ConstValue::Int(lenVal) = valueConst
1612
            else throw testing::TestError::Failed;
1613
        try testing::expect(lenVal.magnitude == 3);
1614
        try testing::expect(not lenVal.negative);
1615
    }
1616
}
1617
1618
@test unsafe fn testResolveIndexNonIndexable() throws (testing::TestError) {
1619
    let mut testArena62 = testArena();
1620
    let testStorage62: 'test62 = &mut testArena62 in {
1621
        let mut a = testResolver(testStorage62);
1622
        let program = "let flag: bool = true; flag[0];";
1623
        let result = try resolveProgramStr(&mut a, program);
1624
        try expectErrorKind(&result, super::ErrorKind::ExpectedIndexable);
1625
    }
1626
}
1627
1628
@test unsafe fn testResolveSliceFieldUnknown() throws (testing::TestError) {
1629
    let mut testArena63 = testArena();
1630
    let testStorage63: 'test63 = &mut testArena63 in {
1631
        let mut a = testResolver(testStorage63);
1632
        let program = "let xs: [i32; 2] = [1, 2]; (&xs[0..]).unknown;";
1633
        let result = try resolveProgramStr(&mut a, program);
1634
        try expectErrorKind(&result, super::ErrorKind::SliceFieldUnknown("unknown"));
1635
    }
1636
}
1637
1638
@test unsafe fn testResolveArrayFieldUnknown() throws (testing::TestError) {
1639
    let mut testArena64 = testArena();
1640
    let testStorage64: 'test64 = &mut testArena64 in {
1641
        let mut a = testResolver(testStorage64);
1642
        let program = "let xs: [i32; 2] = [1, 2]; xs.field;";
1643
        let result = try resolveProgramStr(&mut a, program);
1644
        try expectErrorKind(&result, super::ErrorKind::ArrayFieldUnknown("field"));
1645
    }
1646
}
1647
1648
@test unsafe fn testResolveIfConditionRequiresBool() throws (testing::TestError) {
1649
    {
1650
        let mut testArena65 = testArena();
1651
        let testStorage65: 'test65 = &mut testArena65 in {
1652
            let mut a = testResolver(testStorage65);
1653
            let result = try resolveProgramStr(&mut a, "if 42 {}");
1654
            let err = try expectError(&result);
1655
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1656
        }
1657
    } {
1658
        let mut testArena66 = testArena();
1659
        let testStorage66: 'test66 = &mut testArena66 in {
1660
            let mut a = testResolver(testStorage66);
1661
            let result = try resolveProgramStr(&mut a, "if true {}");
1662
            try expectNoErrors(&result);
1663
        }
1664
    }
1665
}
1666
1667
@test unsafe fn testResolveIfLetScopeBinding() throws (testing::TestError) {
1668
    let mut testArena67 = testArena();
1669
    let testStorage67: 'test67 = &mut testArena67 in {
1670
        let mut a = testResolver(testStorage67);
1671
        let result = try resolveProgramStr(&mut a, "let opt: ?i32 = 42; if let x = opt { x }");
1672
        try expectNoErrors(&result);
1673
1674
        // Get the if-let statement and verify `x` has type `i32`.
1675
        let ifLetStmt = try parser::tests::getBlockLastStmt(result.root);
1676
        let case ast::NodeValue::IfLet(ifLet) = ifLetStmt.value
1677
            else throw testing::TestError::Failed;
1678
1679
        let thenStmt = try parser::tests::getBlockLastStmt(ifLet.thenBranch);
1680
        let case ast::NodeValue::ExprStmt(xExpr) = thenStmt.value
1681
            else throw testing::TestError::Failed;
1682
1683
        try expectType(&a, xExpr, super::Type::I32);
1684
1685
        let scope = super::scopeFor(&a, ifLetStmt)
1686
            else throw testing::TestError::Failed;
1687
        let xSym = super::findSymbolInScope(scope, "x")
1688
            else throw testing::TestError::Failed;
1689
        let case super::SymbolData::Value { type: valType, .. } = xSym.data
1690
            else throw testing::TestError::Failed;
1691
1692
        try testing::expect(valType == super::Type::I32);
1693
    }
1694
}
1695
1696
@test unsafe fn testResolveIfLetScopeBindingError() throws (testing::TestError) {
1697
    let mut testArena68 = testArena();
1698
    let testStorage68: 'test68 = &mut testArena68 in {
1699
        let mut a = testResolver(testStorage68);
1700
        let result = try resolveProgramStr(&mut a, "let opt: ?i32 = 42; if let x = opt { x } else { x }");
1701
        let err = try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1702
1703
        // Verify the error comes from the else branch (offset 48).
1704
        let errNode = err.node
1705
            else throw testing::TestError::Failed;
1706
        try testing::expect(errNode.span.offset == 48);
1707
    }
1708
}
1709
1710
/// Tests that `if let` with a condition expression binds the variable in scope.
1711
@test unsafe fn testResolveIfLetConditionBindsVariable() throws (testing::TestError) {
1712
    let mut testArena69 = testArena();
1713
    let testStorage69: 'test69 = &mut testArena69 in {
1714
        let mut a = testResolver(testStorage69);
1715
        let program = "let opt: ?i32 = 42; if let x = opt; x == 1 { x }";
1716
        let result = try resolveProgramStr(&mut a, program);
1717
        try expectNoErrors(&result);
1718
    }
1719
}
1720
1721
@test unsafe fn testResolveWhileConditionRequiresBool() throws (testing::TestError) {
1722
    {
1723
        let mut testArena70 = testArena();
1724
        let testStorage70: 'test70 = &mut testArena70 in {
1725
            let mut a = testResolver(testStorage70);
1726
            let result = try resolveProgramStr(&mut a, "while 1 {}");
1727
            let err = try expectError(&result);
1728
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1729
        }
1730
    } {
1731
        let mut testArena71 = testArena();
1732
        let testStorage71: 'test71 = &mut testArena71 in {
1733
            let mut a = testResolver(testStorage71);
1734
            let result = try resolveProgramStr(&mut a, "while true {}");
1735
            try expectNoErrors(&result);
1736
        }
1737
    }
1738
}
1739
1740
@test unsafe fn testResolveWhileLetBindingScope() throws (testing::TestError) {
1741
    {
1742
        let mut testArena72 = testArena();
1743
        let testStorage72: 'test72 = &mut testArena72 in {
1744
            let mut a = testResolver(testStorage72);
1745
            let program = "let mut opt: ?i32 = 42; while let x = opt; x > 0 { x; opt; }";
1746
            let result = try resolveProgramStr(&mut a, program);
1747
            try expectNoErrors(&result);
1748
1749
            let whileStmt = try parser::tests::getBlockLastStmt(result.root);
1750
            let case ast::NodeValue::WhileLet(loopNode) = whileStmt.value
1751
                else throw testing::TestError::Failed;
1752
1753
            let bodyStmt = try parser::tests::getBlockFirstStmt(loopNode.body);
1754
            try expectExprStmtType(&a, bodyStmt, super::Type::I32);
1755
1756
            let scope = super::scopeFor(&a, whileStmt)
1757
                else throw testing::TestError::Failed;
1758
            let xSym = super::findSymbolInScope(scope, "x")
1759
                else throw testing::TestError::Failed;
1760
            let case super::SymbolData::Value { type: valType, .. } = xSym.data
1761
                else throw testing::TestError::Failed;
1762
            try testing::expect(valType == super::Type::I32);
1763
        }
1764
    } {
1765
        let mut testArena73 = testArena();
1766
        let testStorage73: 'test73 = &mut testArena73 in {
1767
            let mut a = testResolver(testStorage73);
1768
            let program = "let opt: ?i32 = nil; while let x = opt; true { break } else { x }";
1769
            let result = try resolveProgramStr(&mut a, program);
1770
            try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1771
        }
1772
    }
1773
}
1774
1775
@test unsafe fn testResolveForArrayBindsElementType() throws (testing::TestError) {
1776
    let mut testArena74 = testArena();
1777
    let testStorage74: 'test74 = &mut testArena74 in {
1778
        let mut a = testResolver(testStorage74);
1779
        let program = "let xs: [i32; 2] = [1, 2]; for x in xs { x; }";
1780
        let result = try resolveProgramStr(&mut a, program);
1781
        try expectNoErrors(&result);
1782
1783
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1784
        let case ast::NodeValue::For(loopNode) = forStmt.value
1785
            else throw testing::TestError::Failed;
1786
1787
        let scope = super::scopeFor(&a, forStmt)
1788
            else throw testing::TestError::Failed;
1789
        let sym = super::findSymbolInScope(scope, "x")
1790
            else throw testing::TestError::Failed;
1791
        let case super::SymbolData::Value { type: valType, .. } = sym.data
1792
            else throw testing::TestError::Failed;
1793
        try testing::expect(valType == super::Type::I32);
1794
1795
        let bindingTy = super::typeFor(&a, loopNode.binding)
1796
            else throw testing::TestError::Failed;
1797
        try testing::expect(bindingTy == super::Type::I32);
1798
    }
1799
}
1800
1801
@test unsafe fn testResolveForIndexedLoopBindsIndex() throws (testing::TestError) {
1802
    let mut testArena75 = testArena();
1803
    let testStorage75: 'test75 = &mut testArena75 in {
1804
        let mut a = testResolver(testStorage75);
1805
        let program = "let xs: [bool; 3] = [true; 3]; for value, idx in xs { value; idx; }";
1806
        let result = try resolveProgramStr(&mut a, program);
1807
        try expectNoErrors(&result);
1808
1809
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1810
        let case ast::NodeValue::For(loopNode) = forStmt.value
1811
            else throw testing::TestError::Failed;
1812
1813
        let scope = super::scopeFor(&a, forStmt)
1814
            else throw testing::TestError::Failed;
1815
        let valueSym = super::findSymbolInScope(scope, "value")
1816
            else throw testing::TestError::Failed;
1817
        let case super::SymbolData::Value { type: valueValType, .. } = valueSym.data
1818
            else throw testing::TestError::Failed;
1819
        try testing::expect(valueValType == super::Type::Bool);
1820
        let indexSym = super::findSymbolInScope(scope, "idx")
1821
            else throw testing::TestError::Failed;
1822
        let case super::SymbolData::Value { type: indexValType, .. } = indexSym.data
1823
            else throw testing::TestError::Failed;
1824
        try testing::expect(indexValType == super::Type::U32);
1825
1826
        let indexNode = loopNode.index
1827
            else throw testing::TestError::Failed;
1828
        let indexTy = super::typeFor(&a, indexNode)
1829
            else throw testing::TestError::Failed;
1830
        try testing::expect(indexTy == super::Type::U32);
1831
    }
1832
}
1833
1834
@test unsafe fn testResolveForSliceIterable() throws (testing::TestError) {
1835
    let mut testArena76 = testArena();
1836
    let testStorage76: 'test76 = &mut testArena76 in {
1837
        let mut a = testResolver(testStorage76);
1838
        let program = "let xs: [i32; 3] = [1, 2, 3]; for x in &xs[..] { x; }";
1839
        let result = try resolveProgramStr(&mut a, program);
1840
        try expectNoErrors(&result);
1841
1842
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1843
        let case ast::NodeValue::For(loopNode) = forStmt.value
1844
            else throw testing::TestError::Failed;
1845
1846
        let bindingTy = super::typeFor(&a, loopNode.binding)
1847
            else throw testing::TestError::Failed;
1848
        try testing::expect(bindingTy == super::Type::I32);
1849
    }
1850
}
1851
1852
@test unsafe fn testResolveForRequiresIterable() throws (testing::TestError) {
1853
    let mut testArena77 = testArena();
1854
    let testStorage77: 'test77 = &mut testArena77 in {
1855
        let mut a = testResolver(testStorage77);
1856
        let result = try resolveProgramStr(&mut a, "for x in true { x; }");
1857
        try expectErrorKind(&result, super::ErrorKind::ExpectedIterable);
1858
    }
1859
}
1860
1861
@test unsafe fn testResolveForRangeBoundsMustNumeric() throws (testing::TestError) {
1862
    let mut testArena78 = testArena();
1863
    let testStorage78: 'test78 = &mut testArena78 in {
1864
        let mut a = testResolver(testStorage78);
1865
        let result = try resolveBlockStr(&mut a, "for i in 0..true { i; }");
1866
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
1867
    }
1868
}
1869
1870
@test unsafe fn testResolveMatchPatternTypeMismatch() throws (testing::TestError) {
1871
    let mut testArena79 = testArena();
1872
    let testStorage79: 'test79 = &mut testArena79 in {
1873
        let mut a = testResolver(testStorage79);
1874
        let program = "let val: i32 = 0; match val { case true => {} }";
1875
        let result = try resolveProgramStr(&mut a, program);
1876
        let err = try expectError(&result);
1877
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
1878
    }
1879
}
1880
1881
@test unsafe fn testResolveMatchUnionVariantTypeMismatch() throws (testing::TestError) {
1882
    let mut testArena80 = testArena();
1883
    let testStorage80: 'test80 = &mut testArena80 in {
1884
        let mut a = testResolver(testStorage80);
1885
        let program = "union First { A }  union Second { B } fn run(val: First) { match val { case Second::B => {} } }";
1886
        let result = try resolveProgramStr(&mut a, program);
1887
        let err = try expectError(&result);
1888
1889
        let firstTy = try getTypeInScopeOf(&a, result.root, "First");
1890
        let secondTy = try getTypeInScopeOf(&a, result.root, "Second");
1891
        try expectTypeMismatch(err, super::Type::Nominal(firstTy), super::Type::Nominal(secondTy));
1892
    }
1893
}
1894
1895
@test unsafe fn testResolveMatchUnionPayloadMissing() throws (testing::TestError) {
1896
    let mut testArena81 = testArena();
1897
    let testStorage81: 'test81 = &mut testArena81 in {
1898
        let mut a = testResolver(testStorage81);
1899
        let program = "union Opt { Some(i32) } fn run(val: Opt) { match val { case Opt::Some => {} } }";
1900
        let result = try resolveProgramStr(&mut a, program);
1901
        try expectErrorKind(&result, super::ErrorKind::UnionVariantPayloadMissing("Some"));
1902
    }
1903
}
1904
1905
@test unsafe fn testResolveMatchUnionVoidVariantExplicitDiscriminant() throws (testing::TestError) {
1906
    let mut testArena82 = testArena();
1907
    let testStorage82: 'test82 = &mut testArena82 in {
1908
        let mut a = testResolver(testStorage82);
1909
        let program = "union Opt { Some = 5 } fn run(val: Opt) { match val { case Opt::Some => {} } }";
1910
        let result = try resolveProgramStr(&mut a, program);
1911
        try expectNoErrors(&result);
1912
    }
1913
}
1914
1915
@test unsafe fn testResolveMatchUnionPayloadUnexpected() throws (testing::TestError) {
1916
    let mut testArena83 = testArena();
1917
    let testStorage83: 'test83 = &mut testArena83 in {
1918
        let mut a = testResolver(testStorage83);
1919
        let program = "union Opt { None } fn run(val: Opt) { match val { case Opt::None(x) => {} } }";
1920
        let result = try resolveProgramStr(&mut a, program);
1921
        try expectErrorKind(&result, super::ErrorKind::UnionVariantPayloadUnexpected("None"));
1922
    }
1923
}
1924
1925
@test unsafe fn testResolveMatchUnionUnknownVariant() throws (testing::TestError) {
1926
    let mut testArena84 = testArena();
1927
    let testStorage84: 'test84 = &mut testArena84 in {
1928
        let mut a = testResolver(testStorage84);
1929
        let program = "union Opt { Some, None } fn run(value: Opt) { match value { case Opt::Unknown => {} } }";
1930
        let result = try resolveProgramStr(&mut a, program);
1931
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
1932
    }
1933
}
1934
1935
@test unsafe fn testResolveMatchUnionNonExhaustive() throws (testing::TestError) {
1936
    {
1937
        let mut testArena85 = testArena();
1938
        let testStorage85: 'test85 = &mut testArena85 in {
1939
            let mut a = testResolver(testStorage85);
1940
            let program = "union Opt { Some, None } fn run(value: Opt) { match value { case Opt::Some => {} } }";
1941
            let result = try resolveProgramStr(&mut a, program);
1942
            try expectErrorKind(&result, super::ErrorKind::UnionMatchNonExhaustive("None"));
1943
        }
1944
    } {
1945
        let mut testArena86 = testArena();
1946
        let testStorage86: 'test86 = &mut testArena86 in {
1947
            let mut a = testResolver(testStorage86);
1948
            let program = "union Opt { Some, None } fn run(value: Opt) { match value { else => {} } }";
1949
            let result = try resolveProgramStr(&mut a, program);
1950
            try expectNoErrors(&result);
1951
        }
1952
    }
1953
}
1954
1955
@test unsafe fn testResolveMatchUnionNonExhaustiveExplicitDiscriminants() throws (testing::TestError) {
1956
    let mut testArena87 = testArena();
1957
    let testStorage87: 'test87 = &mut testArena87 in {
1958
        let mut a = testResolver(testStorage87);
1959
        let program = "union U { A = 3, B = 9 } fn run(value: U) { match value { case U::A => {}, case U::B => {} } }";
1960
        let result = try resolveProgramStr(&mut a, program);
1961
        try expectNoErrors(&result);
1962
    }
1963
}
1964
1965
@test unsafe fn testResolveMatchUnionBindingScope() throws (testing::TestError) {
1966
    let mut testArena88 = testArena();
1967
    let testStorage88: 'test88 = &mut testArena88 in {
1968
        let mut a = testResolver(testStorage88);
1969
        let program = "union Opt { Some(i32), None } fn f(value: Opt) { match value { case Opt::Some(x) if x > 0 => { x; } else => {} } }";
1970
        let result = try resolveProgramStr(&mut a, program);
1971
        try expectNoErrors(&result);
1972
1973
        let fnBlock = try getFnBody(&a, result.root, "f");
1974
        try testing::expect(fnBlock.statements.len > 0);
1975
1976
        let matchNode = fnBlock.statements[0];
1977
        let case ast::NodeValue::Match(sw) = matchNode.value
1978
            else throw testing::TestError::Failed;
1979
        let caseNode = sw.prongs[0];
1980
1981
        let scope = super::scopeFor(&a, caseNode)
1982
            else throw testing::TestError::Failed;
1983
        let payloadSym = super::findSymbolInScope(scope, "x")
1984
            else throw testing::TestError::Failed;
1985
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
1986
            else throw testing::TestError::Failed;
1987
        try testing::expect(payloadValType == super::Type::I32);
1988
    }
1989
}
1990
1991
@test unsafe fn testResolveMatchUnionPatternNonUnionType() throws (testing::TestError) {
1992
    let mut testArena89 = testArena();
1993
    let testStorage89: 'test89 = &mut testArena89 in {
1994
        let mut a = testResolver(testStorage89);
1995
        let program = "union Opt { Some, None } fn f(value: Opt) { match value { case true => {} } }";
1996
        let result = try resolveProgramStr(&mut a, program);
1997
        let err = try expectError(&result);
1998
        let optionTy = try getTypeInScopeOf(&a, result.root, "Opt");
1999
        try expectTypeMismatch(err, super::Type::Nominal(optionTy), super::Type::Bool);
2000
    }
2001
}
2002
2003
@test unsafe fn testResolveMatchGuardForms() throws (testing::TestError) {
2004
    let mut testArena90 = testArena();
2005
    let testStorage90: 'test90 = &mut testArena90 in {
2006
        let mut a = testResolver(testStorage90);
2007
        let program = "fn first(value: i32) { match value { case _ if true => {}, else => {} } }";
2008
        let result = try resolveProgramStr(&mut a, program);
2009
        try expectNoErrors(&result);
2010
    }
2011
}
2012
2013
/// Expected lowering metadata for a resolved match.
2014
record MatchMetadataCase: Copy {
2015
    /// Complete source program with a function named f.
2016
    source: *[u8],
2017
    /// Bit set when lowering can omit a prong's pattern test.
2018
    catchAllMask: u32,
2019
    /// Whether scalar cases can use switch lowering.
2020
    isConst: bool,
2021
}
2022
2023
/// Guards and subject types determine unconditional-prong metadata.
2024
@test unsafe fn testMatchCatchAllMetadata() throws (testing::TestError) {
2025
    let cases = [
2026
        MatchMetadataCase { source: "fn f(x: u32) { match x { case 1 => {}, else => {} } }", catchAllMask: 2, isConst: true },
2027
        MatchMetadataCase { source: "fn f(x: u32) { match x { n if n > 0 => {}, case _ => {} } }", catchAllMask: 2, isConst: false },
2028
        MatchMetadataCase { source: "fn f(x: u32) { match x { case _ if x > 0 => {}, n => {} } }", catchAllMask: 2, isConst: false },
2029
        MatchMetadataCase { source: "fn f(x: u32) { match x { n => {} } }", catchAllMask: 1, isConst: false },
2030
        MatchMetadataCase { source: "fn f(x: [[u32; 2]; 2]) { match x { case [[1, a], [b, c]] => {}, case [[a, b], [c, d]] => {} } }", catchAllMask: 2, isConst: false },
2031
        MatchMetadataCase { source: "union U: Copy { A, B } fn f(x: U) { match x { case U::A => {}, else => {} } }", catchAllMask: 2, isConst: false },
2032
        MatchMetadataCase { source: "fn f(x: ?u32) { match x { n => {}, case nil => {} } }", catchAllMask: 2, isConst: false },
2033
        MatchMetadataCase { source: "fn f(x: ?u32) { match x { case _ if false => {}, else => {} } }", catchAllMask: 2, isConst: false },
2034
        MatchMetadataCase { source: "fn f(x: ?u32) { match x { case _ => {} } }", catchAllMask: 1, isConst: false },
2035
        MatchMetadataCase { source: "fn f(x: bool) { match x { case true => {}, case false => {} } }", catchAllMask: 2, isConst: true },
2036
    ];
2037
    for item in cases {
2038
        let mut arena = testArena();
2039
        let storage: 'test = &mut arena in {
2040
            let mut res = testResolver(storage);
2041
            let result = try resolveProgramStr(&mut res, item.source);
2042
            try expectNoErrors(&result);
2043
            let body = try getFnBody(&res, result.root, "f");
2044
            let node = body.statements[0];
2045
            let case ast::NodeValue::Match(sw) = node.value else throw testing::TestError::Failed;
2046
            for prong, i in sw.prongs {
2047
                assert super::isProngCatchAll(&res, prong) == ((item.catchAllMask & (1 << i)) <> 0);
2048
            }
2049
            assert super::isMatchConst(&res, node) == item.isConst;
2050
        }
2051
    }
2052
}
2053
2054
/// Duplicate unconditional arms are rejected for each match subject category.
2055
@test unsafe fn testMatchDuplicateCatchAll() throws (testing::TestError) {
2056
    for source in [
2057
        "fn f(x: u32) { match x { case _ => {}, else => {} } }",
2058
        "fn f(x: u32) { match x { n => {}, case _ => {} } }",
2059
        "fn f(x: [[u32; 2]; 2]) { match x { case [[a, b], [c, d]] => {}, else => {} } }",
2060
        "union U: Copy { A, B } fn f(x: U) { match x { n => {}, else => {} } }",
2061
        "fn f(x: ?u32) { match x { case _ => {}, else => {} } }",
2062
    ] {
2063
        let mut arena = testArena();
2064
        let storage: 'test = &mut arena in {
2065
            let mut res = testResolver(storage);
2066
            let result = try resolveProgramStr(&mut res, source);
2067
            try expectErrorKind(&result, super::ErrorKind::DuplicateCatchAll);
2068
        }
2069
    }
2070
}
2071
2072
/// Test that a binding prong binds the subject to the identifier.
2073
@test unsafe fn testResolveMatchBindingProng() throws (testing::TestError) {
2074
    let mut testArena91 = testArena();
2075
    let testStorage91: 'test91 = &mut testArena91 in {
2076
        let mut a = testResolver(testStorage91);
2077
        let program = "fn f(value: i32) -> i32 { match value { x => return x } }";
2078
        let result = try resolveProgramStr(&mut a, program);
2079
        try expectNoErrors(&result);
2080
    }
2081
}
2082
2083
/// Test that a binding prong with guard can use the bound variable.
2084
@test unsafe fn testResolveMatchBindingProngGuard() throws (testing::TestError) {
2085
    let mut testArena92 = testArena();
2086
    let testStorage92: 'test92 = &mut testArena92 in {
2087
        let mut a = testResolver(testStorage92);
2088
        let program = "fn f(value: i32) -> i32 { match value { x if x > 0 => return x, _ => return 0 } }";
2089
        let result = try resolveProgramStr(&mut a, program);
2090
        try expectNoErrors(&result);
2091
    }
2092
}
2093
2094
/// Test that a binding prong covers all union variants for exhaustiveness.
2095
@test unsafe fn testResolveMatchBindingProngExhaustive() throws (testing::TestError) {
2096
    let mut testArena93 = testArena();
2097
    let testStorage93: 'test93 = &mut testArena93 in {
2098
        let mut a = testResolver(testStorage93);
2099
        let program = "union U { A, B, C } fn f(u: U) -> i32 { match u { x => return 0 } }";
2100
        let result = try resolveProgramStr(&mut a, program);
2101
        try expectNoErrors(&result);
2102
    }
2103
}
2104
2105
/// Test that `case x =>` fails if `x` is not in scope, since bare identifiers
2106
/// in case patterns are values to compare against, not bindings.
2107
@test unsafe fn testResolveMatchCaseUndefinedIdent() throws (testing::TestError) {
2108
    let mut testArena94 = testArena();
2109
    let testStorage94: 'test94 = &mut testArena94 in {
2110
        let mut a = testResolver(testStorage94);
2111
        let program = "fn f(n: i32) -> i32 { match n { case x => return 0 } }";
2112
        let result = try resolveProgramStr(&mut a, program);
2113
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
2114
    }
2115
}
2116
2117
/// Test matching on optionals: exhaustiveness and type unwrapping.
2118
@test unsafe fn testResolveMatchOptional() throws (testing::TestError) {
2119
    {
2120
        // Exhaustive: binding + nil case.
2121
        let mut testArena95 = testArena();
2122
        let testStorage95: 'test95 = &mut testArena95 in {
2123
            let mut a = testResolver(testStorage95);
2124
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {} } }";
2125
            let result = try resolveProgramStr(&mut a, program);
2126
            try expectNoErrors(&result);
2127
        }
2128
    } {
2129
        // Missing nil case.
2130
        let mut testArena96 = testArena();
2131
        let testStorage96: 'test96 = &mut testArena96 in {
2132
            let mut a = testResolver(testStorage96);
2133
            let program = "fn f(opt: ?i32) { match opt { v => {} } }";
2134
            let result = try resolveProgramStr(&mut a, program);
2135
            try expectErrorKind(&result, super::ErrorKind::OptionalMatchMissingNil);
2136
        }
2137
    } {
2138
        // Missing value case.
2139
        let mut testArena97 = testArena();
2140
        let testStorage97: 'test97 = &mut testArena97 in {
2141
            let mut a = testResolver(testStorage97);
2142
            let program = "fn f(opt: ?i32) { match opt { case nil => {} } }";
2143
            let result = try resolveProgramStr(&mut a, program);
2144
            try expectErrorKind(&result, super::ErrorKind::OptionalMatchMissingValue);
2145
        }
2146
    } {
2147
        // Else covers both cases.
2148
        let mut testArena98 = testArena();
2149
        let testStorage98: 'test98 = &mut testArena98 in {
2150
            let mut a = testResolver(testStorage98);
2151
            let program = "fn f(opt: ?i32) { match opt { else => {} } }";
2152
            let result = try resolveProgramStr(&mut a, program);
2153
            try expectNoErrors(&result);
2154
        }
2155
    } {
2156
        // Binding unwraps the inner type.
2157
        let mut testArena99 = testArena();
2158
        let testStorage99: 'test99 = &mut testArena99 in {
2159
            let mut a = testResolver(testStorage99);
2160
            let program = "fn f(opt: ?i32) -> i32 { match opt { v => return v + 1, case nil => return 0 } }";
2161
            let result = try resolveProgramStr(&mut a, program);
2162
            try expectNoErrors(&result);
2163
        }
2164
    }
2165
}
2166
2167
/// Test that match on non-union types requires exhaustiveness.
2168
@test unsafe fn testResolveMatchGenericExhaustive() throws (testing::TestError) {
2169
    {
2170
        // Match on i32 without catch-all should error.
2171
        let mut testArena100 = testArena();
2172
        let testStorage100: 'test100 = &mut testArena100 in {
2173
            let mut a = testResolver(testStorage100);
2174
            let program = "fn f(x: i32) { match x { case 1 => {} } }";
2175
            let result = try resolveProgramStr(&mut a, program);
2176
            try expectErrorKind(&result, super::ErrorKind::MatchNonExhaustive);
2177
        }
2178
    } {
2179
        // Match on i32 with else is fine.
2180
        let mut testArena101 = testArena();
2181
        let testStorage101: 'test101 = &mut testArena101 in {
2182
            let mut a = testResolver(testStorage101);
2183
            let program = "fn f(x: i32) { match x { case 1 => {}, else => {} } }";
2184
            let result = try resolveProgramStr(&mut a, program);
2185
            try expectNoErrors(&result);
2186
        }
2187
    } {
2188
        // Match on i32 with binding catch-all is fine.
2189
        let mut testArena102 = testArena();
2190
        let testStorage102: 'test102 = &mut testArena102 in {
2191
            let mut a = testResolver(testStorage102);
2192
            let program = "fn f(x: i32) { match x { y => {} } }";
2193
            let result = try resolveProgramStr(&mut a, program);
2194
            try expectNoErrors(&result);
2195
        }
2196
    } {
2197
        // Match on i32 with wildcard catch-all is fine.
2198
        let mut testArena103 = testArena();
2199
        let testStorage103: 'test103 = &mut testArena103 in {
2200
            let mut a = testResolver(testStorage103);
2201
            let program = "fn f(x: i32) { match x { case _ => {} } }";
2202
            let result = try resolveProgramStr(&mut a, program);
2203
            try expectNoErrors(&result);
2204
        }
2205
    }
2206
}
2207
2208
/// Test that match on bool requires both true and false cases.
2209
@test unsafe fn testResolveMatchBoolExhaustive() throws (testing::TestError) {
2210
    {
2211
        // Match on bool with both cases is fine.
2212
        let mut testArena104 = testArena();
2213
        let testStorage104: 'test104 = &mut testArena104 in {
2214
            let mut a = testResolver(testStorage104);
2215
            let program = "fn f(x: bool) { match x { case true => {}, case false => {} } }";
2216
            let result = try resolveProgramStr(&mut a, program);
2217
            try expectNoErrors(&result);
2218
        }
2219
    } {
2220
        // Match on bool missing true should error.
2221
        let mut testArena105 = testArena();
2222
        let testStorage105: 'test105 = &mut testArena105 in {
2223
            let mut a = testResolver(testStorage105);
2224
            let program = "fn f(x: bool) { match x { case false => {} } }";
2225
            let result = try resolveProgramStr(&mut a, program);
2226
            try expectErrorKind(&result, super::ErrorKind::BoolMatchMissing(true));
2227
        }
2228
    } {
2229
        // Match on bool missing false should error.
2230
        let mut testArena106 = testArena();
2231
        let testStorage106: 'test106 = &mut testArena106 in {
2232
            let mut a = testResolver(testStorage106);
2233
            let program = "fn f(x: bool) { match x { case true => {} } }";
2234
            let result = try resolveProgramStr(&mut a, program);
2235
            try expectErrorKind(&result, super::ErrorKind::BoolMatchMissing(false));
2236
        }
2237
    } {
2238
        // Match on bool with else is fine.
2239
        let mut testArena107 = testArena();
2240
        let testStorage107: 'test107 = &mut testArena107 in {
2241
            let mut a = testResolver(testStorage107);
2242
            let program = "fn f(x: bool) { match x { else => {} } }";
2243
            let result = try resolveProgramStr(&mut a, program);
2244
            try expectNoErrors(&result);
2245
        }
2246
    } {
2247
        // Match on bool with binding catch-all is fine.
2248
        let mut testArena108 = testArena();
2249
        let testStorage108: 'test108 = &mut testArena108 in {
2250
            let mut a = testResolver(testStorage108);
2251
            let program = "fn f(x: bool) { match x { b => {} } }";
2252
            let result = try resolveProgramStr(&mut a, program);
2253
            try expectNoErrors(&result);
2254
        }
2255
    }
2256
}
2257
2258
@test unsafe fn testResolveFnTypeVoidNoParams() throws (testing::TestError) {
2259
    let mut testArena113 = testArena();
2260
    let testStorage113: 'test113 = &mut testArena113 in {
2261
        let mut a = testResolver(testStorage113);
2262
        let result = try resolveProgramStr(&mut a, "fn f() {} f();");
2263
        try expectNoErrors(&result);
2264
2265
        let blockNode = result.root;
2266
        let case ast::NodeValue::Block(block) = blockNode.value
2267
            else throw testing::TestError::Failed;
2268
        let fnNode = try getBlockStmt(blockNode, 0);
2269
        let callStmt = try getBlockStmt(blockNode, 1);
2270
2271
        { // Verify the function symbol captures an empty parameter list and void return.
2272
            let sym = super::symbolFor(&a, fnNode)
2273
                else throw testing::TestError::Failed;
2274
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2275
                else throw testing::TestError::Failed;
2276
            try testing::expect(fnTy.paramTypes.len == 0);
2277
            try testing::expect(*fnTy.returnType == super::Type::Void);
2278
        }
2279
        { // Checking that the type of the call matches the function return type.
2280
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
2281
2282
            let fnSym = super::symbolFor(&a, fnNode)
2283
                else throw testing::TestError::Failed;
2284
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2285
                else throw testing::TestError::Failed;
2286
            try expectType(&a, callExpr, *fnTy.returnType);
2287
        }
2288
    }
2289
}
2290
2291
@test unsafe fn testResolveFnTypeReturnsValue() throws (testing::TestError) {
2292
    let mut testArena114 = testArena();
2293
    let testStorage114: 'test114 = &mut testArena114 in {
2294
        let mut a = testResolver(testStorage114);
2295
        let program = "fn f() -> i32 { return 1; } f();";
2296
        let result = try resolveProgramStr(&mut a, program);
2297
        try expectNoErrors(&result);
2298
2299
        let blockNode = result.root;
2300
        let case ast::NodeValue::Block(block) = blockNode.value
2301
            else throw testing::TestError::Failed;
2302
        let fnNode = try getBlockStmt(blockNode, 0);
2303
        let callStmt = try getBlockStmt(blockNode, 1);
2304
2305
        { // Function returns i32 with no parameters.
2306
            let sym = super::symbolFor(&a, fnNode)
2307
                else throw testing::TestError::Failed;
2308
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2309
                else throw testing::TestError::Failed;
2310
            try testing::expect(fnTy.paramTypes.len == 0);
2311
            try testing::expect(*fnTy.returnType == super::Type::I32);
2312
        }
2313
        { // Call expression should inherit the function's return type.
2314
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::I32);
2315
2316
            let fnSym = super::symbolFor(&a, fnNode)
2317
                else throw testing::TestError::Failed;
2318
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2319
                else throw testing::TestError::Failed;
2320
            try expectType(&a, callExpr, *fnTy.returnType);
2321
        }
2322
    }
2323
}
2324
2325
@test unsafe fn testResolveFnTypeSingleParam() throws (testing::TestError) {
2326
    let mut testArena115 = testArena();
2327
    let testStorage115: 'test115 = &mut testArena115 in {
2328
        let mut a = testResolver(testStorage115);
2329
        let program = "fn f(x: i8) {} let x: i8 = 1; f(x);";
2330
        let result = try resolveProgramStr(&mut a, program);
2331
        try expectNoErrors(&result);
2332
2333
        let blockNode = result.root;
2334
        let case ast::NodeValue::Block(block) = blockNode.value
2335
            else throw testing::TestError::Failed;
2336
        let fnNode = try getBlockStmt(blockNode, 0);
2337
        let callStmt = try getBlockStmt(blockNode, 2);
2338
2339
        { // Single parameter propagates nominal type onto the symbol and parameter node.
2340
            let sym = super::symbolFor(&a, fnNode)
2341
                else throw testing::TestError::Failed;
2342
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2343
                else throw testing::TestError::Failed;
2344
            try testing::expect(fnTy.paramTypes.len == 1);
2345
            try testing::expect(*fnTy.paramTypes[0] == super::Type::I8);
2346
            try testing::expect(*fnTy.returnType == super::Type::Void);
2347
2348
            let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
2349
                else throw testing::TestError::Failed;
2350
            try testing::expect(fnDecl.sig.params.len == 1);
2351
2352
            let paramNode = fnDecl.sig.params[0];
2353
            try expectType(&a, paramNode, super::Type::I8);
2354
        }
2355
        { // Call should resolve to void, matching the function's return type.
2356
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
2357
            let fnSym = super::symbolFor(&a, fnNode)
2358
                else throw testing::TestError::Failed;
2359
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2360
                else throw testing::TestError::Failed;
2361
            try expectType(&a, callExpr, *fnTy.returnType);
2362
        }
2363
    }
2364
}
2365
2366
@test unsafe fn testResolveFnTypeMultipleParams() throws (testing::TestError) {
2367
    let mut testArena116 = testArena();
2368
    let testStorage116: 'test116 = &mut testArena116 in {
2369
        let mut a = testResolver(testStorage116);
2370
        let program = "fn f(x: i8, y: i32) {} let x: i8 = 1; let y: i32 = 2; f(x, y);";
2371
        let result = try resolveProgramStr(&mut a, program);
2372
        try expectNoErrors(&result);
2373
2374
        let blockNode = result.root;
2375
        let case ast::NodeValue::Block(block) = blockNode.value
2376
            else throw testing::TestError::Failed;
2377
        let fnNode = try getBlockStmt(blockNode, 0);
2378
        let callStmt = try getBlockStmt(blockNode, 3);
2379
2380
        { // Ensure multi-parameter signatures record both argument types.
2381
            let sym = super::symbolFor(&a, fnNode)
2382
                else throw testing::TestError::Failed;
2383
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2384
                else throw testing::TestError::Failed;
2385
            try testing::expect(fnTy.paramTypes.len == 2);
2386
            try testing::expect(*fnTy.paramTypes[0] == super::Type::I8);
2387
            try testing::expect(*fnTy.paramTypes[1] == super::Type::I32);
2388
            try testing::expect(*fnTy.returnType == super::Type::Void);
2389
2390
            let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
2391
                else throw testing::TestError::Failed;
2392
            try testing::expect(fnDecl.sig.params.len == 2);
2393
2394
            let firstParam = fnDecl.sig.params[0];
2395
            let secondParam = fnDecl.sig.params[1];
2396
            try expectType(&a, firstParam, super::Type::I8);
2397
            try expectType(&a, secondParam, super::Type::I32);
2398
        }
2399
        { // Call expression should again mirror the function return type.
2400
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
2401
            let fnSym = super::symbolFor(&a, fnNode)
2402
                else throw testing::TestError::Failed;
2403
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2404
                else throw testing::TestError::Failed;
2405
            try expectType(&a, callExpr, *fnTy.returnType);
2406
        }
2407
    }
2408
}
2409
2410
@test unsafe fn testResolveFnRecursiveCall() throws (testing::TestError) {
2411
    let mut testArena117 = testArena();
2412
    let testStorage117: 'test117 = &mut testArena117 in {
2413
        let mut a = testResolver(testStorage117);
2414
        let program = "fn flip(b: bool) -> bool { if b { return false; } return flip(false); }";
2415
        let result = try resolveProgramStr(&mut a, program);
2416
        try expectNoErrors(&result);
2417
2418
        let blockNode = result.root;
2419
        let case ast::NodeValue::Block(block) = blockNode.value
2420
            else throw testing::TestError::Failed;
2421
        let fnNode = try getBlockStmt(blockNode, 0);
2422
2423
        { // Function symbol should be visible for recursive calls within its own body.
2424
            let sym = super::symbolFor(&a, fnNode)
2425
                else throw testing::TestError::Failed;
2426
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2427
                else throw testing::TestError::Failed;
2428
            try testing::expect(fnTy.paramTypes.len == 1);
2429
            try testing::expect(*fnTy.paramTypes[0] == super::Type::Bool);
2430
            try testing::expect(*fnTy.returnType == super::Type::Bool);
2431
        }
2432
    }
2433
}
2434
2435
@test unsafe fn testResolveFnCallMissingArgument() throws (testing::TestError) {
2436
    let mut testArena118 = testArena();
2437
    let testStorage118: 'test118 = &mut testArena118 in {
2438
        let mut a = testResolver(testStorage118);
2439
        let program = "fn f(x: i8) {} f();";
2440
        let result = try resolveProgramStr(&mut a, program);
2441
        // Expect an error when a required parameter is omitted.
2442
        try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
2443
            expected: 1,
2444
            actual: 0,
2445
        }));
2446
    }
2447
}
2448
2449
@test unsafe fn testResolveFnCallExtraArgument() throws (testing::TestError) {
2450
    let mut testArena119 = testArena();
2451
    let testStorage119: 'test119 = &mut testArena119 in {
2452
        let mut a = testResolver(testStorage119);
2453
        let program = "fn f() {} f(1);";
2454
        let result = try resolveProgramStr(&mut a, program);
2455
        // Passing more arguments than declared should fail.
2456
        try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
2457
            expected: 0,
2458
            actual: 1,
2459
        }));
2460
    }
2461
}
2462
2463
/// Invalid calls in function bodies retain their resolution diagnostics.
2464
@test unsafe fn testInvalidBodyCalls() throws (testing::TestError) {
2465
    for program in &[
2466
        "fn f(x: u32) {} fn g() { f(1, 2); }",
2467
        "fn f(x: u32) {} fn g() { if true { f(1, 2); } }",
2468
        "fn f(x: u32) {} unsafe fn g() { f(1, 2); }",
2469
    ] {
2470
        let mut arena = testArena();
2471
        let storage: 'test = &mut arena in {
2472
            let mut res = testResolver(storage);
2473
            let result = try resolveProgramStr(&mut res, program);
2474
            try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
2475
                expected: 1, actual: 2,
2476
            }));
2477
        }
2478
    }
2479
}
2480
2481
/// Unsafe calls with excess arguments report the unsafe-call diagnostic.
2482
@test unsafe fn testInvalidUnsafeBodyCall() throws (testing::TestError) {
2483
    let mut arena = testArena();
2484
    let storage: 'test = &mut arena in {
2485
        let mut res = testResolver(storage);
2486
        let result = try resolveProgramStr(&mut res,
2487
            "unsafe fn f(x: u32) {} fn g() { f(1, 2); }");
2488
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
2489
    }
2490
}
2491
2492
@test unsafe fn testResolveFnCallArgumentTypeMismatch() throws (testing::TestError) {
2493
    let mut testArena120 = testArena();
2494
    let testStorage120: 'test120 = &mut testArena120 in {
2495
        let mut a = testResolver(testStorage120);
2496
        let program = "fn f(x: i8) {} f(true);";
2497
        let result = try resolveProgramStr(&mut a, program);
2498
        let err = try expectError(&result);
2499
        // The argument type (bool) should not match the parameter type (i8).
2500
        try expectTypeMismatch(err, super::Type::I8, super::Type::Bool);
2501
    }
2502
}
2503
2504
@test unsafe fn testResolveFnReturnTypeMismatch() throws (testing::TestError) {
2505
    let mut testArena121 = testArena();
2506
    let testStorage121: 'test121 = &mut testArena121 in {
2507
        let mut a = testResolver(testStorage121);
2508
        let program = "fn f() -> i32 { return true; }";
2509
        let result = try resolveProgramStr(&mut a, program);
2510
        let err = try expectError(&result);
2511
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
2512
    }
2513
}
2514
2515
@test unsafe fn testResolveFnReturnVoid() throws (testing::TestError) {
2516
    {
2517
        let mut testArena122 = testArena();
2518
        let testStorage122: 'test122 = &mut testArena122 in {
2519
            let mut a = testResolver(testStorage122);
2520
            let result = try resolveProgramStr(&mut a, "fn f() { return; }");
2521
            try expectNoErrors(&result);
2522
        }
2523
    } {
2524
        let mut testArena123 = testArena();
2525
        let testStorage123: 'test123 = &mut testArena123 in {
2526
            let mut a = testResolver(testStorage123);
2527
            let result = try resolveProgramStr(&mut a, "fn g() -> i32 { return; }");
2528
            let err = try expectError(&result);
2529
            try expectTypeMismatch(err, super::Type::I32, super::Type::Void);
2530
        }
2531
    }
2532
}
2533
2534
@test unsafe fn testResolveFnMissingReturn() throws (testing::TestError) {
2535
    {
2536
        let mut testArena124 = testArena();
2537
        let testStorage124: 'test124 = &mut testArena124 in {
2538
            let mut a = testResolver(testStorage124);
2539
            let result = try resolveProgramStr(&mut a, "fn f() -> i32 {}");
2540
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2541
        }
2542
    } {
2543
        let mut testArena125 = testArena();
2544
        let testStorage125: 'test125 = &mut testArena125 in {
2545
            let mut a = testResolver(testStorage125);
2546
            let program = "fn g(flag: bool) -> i32 { if flag { return 1; } 2; }";
2547
            let result = try resolveProgramStr(&mut a, program);
2548
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2549
        }
2550
    }
2551
}
2552
2553
/// Never-returning functions require divergence on every path.
2554
@test unsafe fn testResolveNeverReturn() throws (testing::TestError) {
2555
    for program in &[
2556
        "fn stop() -> ! { panic; } fn f() -> i32 { stop(); }",
2557
        "fn stop() -> ! { panic; } fn f() -> ! { return stop(); }",
2558
        "fn f(callback: fn() -> !) -> ! { callback(); }",
2559
        "fn stop() -> ! { panic; } fn f() -> ! { let _ = stop(); }",
2560
        "fn stop() -> ! { panic; } fn f() -> i32 { let value: i32 = stop(); }",
2561
        "union Token: Once { Held(u32) } fn stop() -> ! { panic; } fn f(token: Token) -> ! { stop(); }",
2562
        "union Token: Once { Held(u32) } fn stop() -> ! { panic; } fn f(token: Token) -> ! { return stop(); }",
2563
        "union Token: Once { Held(u32) } fn stop() -> ! throws (i32) { throw 1; } fn f(token: Token) -> ! { try! stop(); }",
2564
        "fn f() -> ! { while true {} }",
2565
        "fn f(flag: bool) -> ! { if flag { panic; } else { while true {} } }",
2566
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! throws (i32) { try f(); }",
2567
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> i32 { try f() catch { return 2; }; }",
2568
    ] {
2569
        let mut testArena126 = testArena();
2570
        let testStorage126: 'test126 = &mut testArena126 in {
2571
            let mut a = testResolver(testStorage126);
2572
            let result = try resolveProgramStr(&mut a, program);
2573
            try expectNoErrors(&result);
2574
        }
2575
    }
2576
}
2577
2578
/// A never-returning signature rejects any normal completion path.
2579
@test unsafe fn testResolveNeverFallthrough() throws (testing::TestError) {
2580
    for program in &[
2581
        "fn f() -> ! {}",
2582
        "fn f(flag: bool) -> ! { if flag { panic; } }",
2583
        "fn f() -> ! { while true { break; } }",
2584
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! { try f() catch {}; }",
2585
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! { try f() catch e as i32 {}; }",
2586
    ] {
2587
        let mut testArena127 = testArena();
2588
        let testStorage127: 'test127 = &mut testArena127 in {
2589
            let mut a = testResolver(testStorage127);
2590
            let result = try resolveProgramStr(&mut a, program);
2591
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2592
        }
2593
    }
2594
}
2595
2596
/// No value, including undefined, can construct a never return value.
2597
@test unsafe fn testResolveNeverValue() throws (testing::TestError) {
2598
    for program in &[
2599
        "fn f() -> ! { return; }",
2600
        "fn f() -> ! { return 1; }",
2601
        "unsafe fn f() -> ! { return undefined; }",
2602
        "fn ordinary() {} fn f() { let callback: fn() -> ! = ordinary; }",
2603
    ] {
2604
        let mut testArena128 = testArena();
2605
        let testStorage128: 'test128 = &mut testArena128 in {
2606
            let mut a = testResolver(testStorage128);
2607
            let result = try resolveProgramStr(&mut a, program);
2608
            let error = try expectError(&result);
2609
        }
2610
    }
2611
}
2612
2613
/// Caught errors preserve the caller's exact-use ownership obligations.
2614
@test unsafe fn testResolveNeverCaughtOwnership() throws (testing::TestError) {
2615
    for program in &[
2616
        "union Token: Once { Held(u32) } fn fail() -> ! throws (i32) { throw 1; } fn f(token: Token) { try fail() catch {}; }",
2617
        "union Token: Once { Held(u32) } fn fail() -> ! throws (i32) { throw 1; } fn f(token: Token) { let absent = try? fail(); }",
2618
    ] {
2619
        let mut testArena129 = testArena();
2620
        let testStorage129: 'test129 = &mut testArena129 in {
2621
            let mut a = testResolver(testStorage129);
2622
            let result = try resolveProgramStr(&mut a, program);
2623
            let error = try expectError(&result);
2624
            let case super::ErrorKind::LinearNotConsumed(_) = error.kind
2625
                else throw testing::TestError::Failed;
2626
        }
2627
    }
2628
}
2629
2630
@test unsafe fn testResolveFnAllPathsReturn() throws (testing::TestError) {
2631
    let mut testArena130 = testArena();
2632
    let testStorage130: 'test130 = &mut testArena130 in {
2633
        let mut a = testResolver(testStorage130);
2634
        let program = "fn h(flag: bool) -> i32 { if flag { return 1; } else { return 2; } }";
2635
        let result = try resolveProgramStr(&mut a, program);
2636
        try expectNoErrors(&result);
2637
    }
2638
}
2639
2640
/// Test that match statements with returns in all branches don't require a
2641
/// return at the end of the function.
2642
@test unsafe fn testResolveFnMatchAllPathsReturn() throws (testing::TestError) {
2643
    {
2644
        // Union match with all variants returning.
2645
        let mut testArena131 = testArena();
2646
        let testStorage131: 'test131 = &mut testArena131 in {
2647
            let mut a = testResolver(testStorage131);
2648
            let program = "union E { A, B } fn f(e: E) -> i32 { match e { case E::A => return 1, case E::B => return 2 } }";
2649
            let result = try resolveProgramStr(&mut a, program);
2650
            try expectNoErrors(&result);
2651
        }
2652
    } {
2653
        // Match with default case where all branches return.
2654
        let mut testArena132 = testArena();
2655
        let testStorage132: 'test132 = &mut testArena132 in {
2656
            let mut a = testResolver(testStorage132);
2657
            let program = "fn f(x: i32) -> i32 { match x { case 1 => return 1, else => return 0, } }";
2658
            let result = try resolveProgramStr(&mut a, program);
2659
            try expectNoErrors(&result);
2660
        }
2661
    } {
2662
        // Match where not all branches return should error.
2663
        let mut testArena133 = testArena();
2664
        let testStorage133: 'test133 = &mut testArena133 in {
2665
            let mut a = testResolver(testStorage133);
2666
            let program = "union E { A, B } fn f(e: E) -> i32 { match e { case E::A => return 1, case E::B => {} } }";
2667
            let result = try resolveProgramStr(&mut a, program);
2668
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2669
        }
2670
    }
2671
}
2672
2673
@test unsafe fn testResolveAssign() throws (testing::TestError) {
2674
    {
2675
        let mut testArena134 = testArena();
2676
        let testStorage134: 'test134 = &mut testArena134 in {
2677
            let mut a = testResolver(testStorage134);
2678
            let result = try resolveProgramStr(&mut a, "let mut x: i32 = 0; set x = 1;");
2679
            try expectNoErrors(&result);
2680
        }
2681
    } {
2682
        let mut testArena135 = testArena();
2683
        let testStorage135: 'test135 = &mut testArena135 in {
2684
            let mut a = testResolver(testStorage135);
2685
            let result = try resolveProgramStr(&mut a, "let x: i32 = 0; set x = 1;");
2686
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2687
        }
2688
    } {
2689
        let mut testArena136 = testArena();
2690
        let testStorage136: 'test136 = &mut testArena136 in {
2691
            let mut a = testResolver(testStorage136);
2692
            let result = try resolveProgramStr(&mut a, "let mut x: bool = false; set x = 1;");
2693
            let err = try expectError(&result);
2694
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
2695
        }
2696
    } {
2697
        let mut testArena137 = testArena();
2698
        let testStorage137: 'test137 = &mut testArena137 in {
2699
            let mut a = testResolver(testStorage137);
2700
            let result = try resolveProgramStr(&mut a, "set x = 1;");
2701
            try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
2702
        }
2703
    } {
2704
        let mut testArena138 = testArena();
2705
        let testStorage138: 'test138 = &mut testArena138 in {
2706
            let mut a = testResolver(testStorage138);
2707
            let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = 1;");
2708
            try expectNoErrors(&result);
2709
        }
2710
    } {
2711
        let mut testArena139 = testArena();
2712
        let testStorage139: 'test139 = &mut testArena139 in {
2713
            let mut a = testResolver(testStorage139);
2714
            let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = nil;");
2715
            try expectNoErrors(&result);
2716
        }
2717
    }
2718
}
2719
2720
@test unsafe fn testResolveAssignSubscript() throws (testing::TestError) {
2721
    {
2722
        let mut testArena140 = testArena();
2723
        let testStorage140: 'test140 = &mut testArena140 in {
2724
            let mut a = testResolver(testStorage140);
2725
            let program = "let mut xs: [u8; 2] = [0, 1]; set xs[0] = 9;";
2726
            let result = try resolveProgramStr(&mut a, program);
2727
            try expectNoErrors(&result);
2728
        }
2729
    }
2730
    {
2731
        let mut testArena141 = testArena();
2732
        let testStorage141: 'test141 = &mut testArena141 in {
2733
            let mut a = testResolver(testStorage141);
2734
            let program = "static xs: [u8; 2] = [0, 1]; let slice: *mut [u8] = &mut xs[..]; set slice[0] = 1;";
2735
            let result = try resolveProgramStr(&mut a, program);
2736
            try expectNoErrors(&result);
2737
        }
2738
    }
2739
    {
2740
        let mut testArena142 = testArena();
2741
        let testStorage142: 'test142 = &mut testArena142 in {
2742
            let mut a = testResolver(testStorage142);
2743
            let program = "static xs: [u8; 2] = [0, 1]; let mut slice: *[u8] = &xs[..]; set slice[0] = 1;";
2744
            let result = try resolveProgramStr(&mut a, program);
2745
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2746
        }
2747
    }
2748
    {
2749
        let mut testArena143 = testArena();
2750
        let testStorage143: 'test143 = &mut testArena143 in {
2751
            let mut a = testResolver(testStorage143);
2752
            let program = "let xs: [u8; 2] = [0, 1]; set xs[0] = 9;";
2753
            let result = try resolveProgramStr(&mut a, program);
2754
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2755
        }
2756
    }
2757
    {
2758
        let mut testArena144 = testArena();
2759
        let testStorage144: 'test144 = &mut testArena144 in {
2760
            let mut a = testResolver(testStorage144);
2761
            let program = "static xs: [u8; 2] = [0, 1]; let slice: *[u8] = &xs[..]; set slice[0] = 1;";
2762
            let result = try resolveProgramStr(&mut a, program);
2763
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2764
        }
2765
    }
2766
}
2767
2768
@test unsafe fn testResolveAssignIntegerLits() throws (testing::TestError) {
2769
    try expectAnalyzeOk("let x: i8 = 127;");
2770
    try expectAnalyzeOk("let x: i8 = 0x7F;");
2771
    try expectAnalyzeOk("let x: i8 = -128;");
2772
    try expectAnalyzeOk("let x: u8 = 255;");
2773
    try expectAnalyzeOk("let x: u8 = 0b11111111;");
2774
    try expectAnalyzeOk("let x: i16 = 0x7FFF;");
2775
    try expectAnalyzeOk("let x: i16 = -32768;");
2776
    try expectAnalyzeOk("let x: u16 = 0xFFFF;");
2777
    try expectAnalyzeOk("let x: i32 = 2147483647;");
2778
    try expectAnalyzeOk("let x: i32 = -2147483648;");
2779
    try expectAnalyzeOk("let x: u32 = 0xFFFFFFFF;");
2780
    try expectAnalyzeOk("let x: i64 = 9223372036854775807;");
2781
    try expectAnalyzeOk("let x: i64 = -9223372036854775808;");
2782
2783
    try expectAnalyzeOk("constant LIMIT: u8 = 0xFF;");
2784
2785
    try expectIntMismatch("let x: i8 = 128;", super::Type::I8);
2786
    try expectIntMismatch("let x: i8 = -129;", super::Type::I8);
2787
    try expectIntMismatch("let x: i8 = 0x80;", super::Type::I8);
2788
    try expectIntMismatch("let x: i8 = 0b10000000;", super::Type::I8);
2789
    try expectIntMismatch("let x: u8 = 256;", super::Type::U8);
2790
    try expectIntMismatch("let x: u8 = -1;", super::Type::U8);
2791
    try expectIntMismatch("let x: u8 = 0b100000000;", super::Type::U8);
2792
    try expectIntMismatch("let x: i16 = 32768;", super::Type::I16);
2793
    try expectIntMismatch("let x: i16 = -32769;", super::Type::I16);
2794
    try expectIntMismatch("let x: u16 = 65536;", super::Type::U16);
2795
    try expectIntMismatch("let x: u16 = -1;", super::Type::U16);
2796
    try expectIntMismatch("let x: i32 = 2147483648;", super::Type::I32);
2797
    try expectIntMismatch("let x: i32 = -2147483649;", super::Type::I32);
2798
    try expectIntMismatch("let x: i32 = 0xFFFFFFFF;", super::Type::I32);
2799
    try expectIntMismatch("let x: u32 = -1;", super::Type::U32);
2800
    try expectIntMismatch("let x: u32 = 0x100000000;", super::Type::U32);
2801
    try expectIntMismatch("let x: i64 = 9223372036854775808;", super::Type::I64);
2802
    try expectIntMismatch("let x: i64 = -9223372036854775809;", super::Type::I64);
2803
    try expectIntMismatch("constant LIMIT: u8 = 512;", super::Type::U8);
2804
    try expectIntMismatch("constant LIMIT: u8 = -5;", super::Type::U8);
2805
}
2806
2807
@test unsafe fn testNilCoercions() throws (testing::TestError) {
2808
    {
2809
        let mut testArena145 = testArena();
2810
        let testStorage145: 'test145 = &mut testArena145 in {
2811
            let mut a = testResolver(testStorage145);
2812
            let result = try resolveBlockStr(&mut a, "let opt: ?i32 = nil;");
2813
            try expectNoErrors(&result);
2814
        }
2815
    } {
2816
        let mut testArena146 = testArena();
2817
        let testStorage146: 'test146 = &mut testArena146 in {
2818
            let mut a = testResolver(testStorage146);
2819
            let program = "fn g(opt: ?i32) {} fn f() { g(nil); }";
2820
            let result = try resolveProgramStr(&mut a, program);
2821
            try expectNoErrors(&result);
2822
        }
2823
    } {
2824
        let mut testArena147 = testArena();
2825
        let testStorage147: 'test147 = &mut testArena147 in {
2826
            let mut a = testResolver(testStorage147);
2827
            let program = "fn make(flag: bool) -> ?i32 { if flag { return 1; } return nil; }";
2828
            let result = try resolveProgramStr(&mut a, program);
2829
            try expectNoErrors(&result);
2830
        }
2831
    }
2832
}
2833
2834
@test unsafe fn testOptionalComparedWithNil() throws (testing::TestError) {
2835
    let mut testArena148 = testArena();
2836
    let testStorage148: 'test148 = &mut testArena148 in {
2837
        let mut a = testResolver(testStorage148);
2838
        let program = "let opt: ?i32 = nil; opt == nil; nil == opt; opt == 1; 1 == opt; opt == opt; nil == nil;";
2839
        let result = try resolveBlockStr(&mut a, program);
2840
        try expectNoErrors(&result);
2841
2842
        for i in 1..7 {
2843
            let stmt = try getBlockStmt(result.root, i);
2844
            try expectExprStmtType(&a, stmt, super::Type::Bool);
2845
        }
2846
    }
2847
}
2848
2849
@test unsafe fn testResolveRecordLiteralAllFieldsSet() throws (testing::TestError) {
2850
    let mut testArena149 = testArena();
2851
    let testStorage149: 'test149 = &mut testArena149 in {
2852
        let mut a = testResolver(testStorage149);
2853
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1, y: 2 };";
2854
        let result = try resolveProgramStr(&mut a, program);
2855
        try expectNoErrors(&result);
2856
    }
2857
}
2858
2859
@test unsafe fn testResolveRecordLiteralMissingField() throws (testing::TestError) {
2860
    let mut testArena150 = testArena();
2861
    let testStorage150: 'test150 = &mut testArena150 in {
2862
        let mut a = testResolver(testStorage150);
2863
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1 };";
2864
        let result = try resolveProgramStr(&mut a, program);
2865
        try expectErrorKind(&result, super::ErrorKind::RecordFieldMissing("y"));
2866
    }
2867
}
2868
2869
@test unsafe fn testResolveRecordLiteralFieldTypeMismatch() throws (testing::TestError) {
2870
    let mut testArena151 = testArena();
2871
    let testStorage151: 'test151 = &mut testArena151 in {
2872
        let mut a = testResolver(testStorage151);
2873
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: true, y: 2 };";
2874
        let result = try resolveProgramStr(&mut a, program);
2875
        let err = try expectError(&result);
2876
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
2877
2878
        let errNode = err.node
2879
            else throw testing::TestError::Failed;
2880
        let case ast::NodeValue::Bool(_) = errNode.value
2881
            else throw testing::TestError::Failed;
2882
    }
2883
}
2884
2885
@test unsafe fn testResolveRecordLiteralExtraField() throws (testing::TestError) {
2886
    let mut testArena152 = testArena();
2887
    let testStorage152: 'test152 = &mut testArena152 in {
2888
        let mut a = testResolver(testStorage152);
2889
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1, z: 3, y: 2 };";
2890
        let result = try resolveProgramStr(&mut a, program);
2891
        let err = try expectError(&result);
2892
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
2893
            else throw testing::TestError::Failed;
2894
    }
2895
}
2896
2897
/// Test that anonymous record literals with labels can be passed to functions expecting named records.
2898
@test unsafe fn testResolveAnonRecordLabeledToNamedRecord() throws (testing::TestError) {
2899
    let mut testArena153 = testArena();
2900
    let testStorage153: 'test153 = &mut testArena153 in {
2901
        let mut a = testResolver(testStorage153);
2902
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) -> i32 { return p.x; } foo({ x: 1, y: 2 });";
2903
        let result = try resolveProgramStr(&mut a, program);
2904
        try expectNoErrors(&result);
2905
    }
2906
}
2907
2908
/// Test that anonymous record with wrong field name causes out of order error.
2909
@test unsafe fn testResolveAnonRecordWrongFieldName() throws (testing::TestError) {
2910
    let mut testArena154 = testArena();
2911
    let testStorage154: 'test154 = &mut testArena154 in {
2912
        let mut a = testResolver(testStorage154);
2913
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1, z: 2 });";
2914
        let result = try resolveProgramStr(&mut a, program);
2915
        let err = try expectError(&result);
2916
        let case super::ErrorKind::RecordFieldOutOfOrder { field: _, prev: _ } = err.kind
2917
            else throw testing::TestError::Failed;
2918
    }
2919
}
2920
2921
/// Test that anonymous record with wrong field type causes type mismatch.
2922
@test unsafe fn testResolveAnonRecordWrongFieldType() throws (testing::TestError) {
2923
    let mut testArena155 = testArena();
2924
    let testStorage155: 'test155 = &mut testArena155 in {
2925
        let mut a = testResolver(testStorage155);
2926
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: true, y: 2 });";
2927
        let result = try resolveProgramStr(&mut a, program);
2928
        let err = try expectError(&result);
2929
        let case super::ErrorKind::TypeMismatch(_) = err.kind
2930
            else throw testing::TestError::Failed;
2931
    }
2932
}
2933
2934
/// Test that anonymous record with missing field causes a missing field error.
2935
@test unsafe fn testResolveAnonRecordMissingField() throws (testing::TestError) {
2936
    let mut testArena156 = testArena();
2937
    let testStorage156: 'test156 = &mut testArena156 in {
2938
        let mut a = testResolver(testStorage156);
2939
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1 });";
2940
        let result = try resolveProgramStr(&mut a, program);
2941
        try expectErrorKind(&result, super::ErrorKind::RecordFieldMissing("y"));
2942
    }
2943
}
2944
2945
/// Test that anonymous record with extra field causes a count mismatch error.
2946
@test unsafe fn testResolveAnonRecordExtraField() throws (testing::TestError) {
2947
    let mut testArena157 = testArena();
2948
    let testStorage157: 'test157 = &mut testArena157 in {
2949
        let mut a = testResolver(testStorage157);
2950
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1, y: 2, z: 3 });";
2951
        let result = try resolveProgramStr(&mut a, program);
2952
        let err = try expectError(&result);
2953
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
2954
            else throw testing::TestError::Failed;
2955
    }
2956
}
2957
2958
/// Test that anonymous record fields can be coerced (e.g., i32 to optional).
2959
@test unsafe fn testResolveAnonRecordFieldCoercion() throws (testing::TestError) {
2960
    let mut testArena158 = testArena();
2961
    let testStorage158: 'test158 = &mut testArena158 in {
2962
        let mut a = testResolver(testStorage158);
2963
        let program = "record Opt { x: ?i32 } fn foo(p: Opt) {} foo({ x: 42 });";
2964
        let result = try resolveProgramStr(&mut a, program);
2965
        try expectNoErrors(&result);
2966
    }
2967
}
2968
2969
/// Test that arrays of anonymous records with labeled fields are allowed.
2970
@test unsafe fn testResolveAnonRecordArray() throws (testing::TestError) {
2971
    let mut testArena159 = testArena();
2972
    let testStorage159: 'test159 = &mut testArena159 in {
2973
        let mut a = testResolver(testStorage159);
2974
        let program = "record Pt { x: i32, y: i32 } constant ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4 }];";
2975
        let result = try resolveProgramStr(&mut a, program);
2976
        try expectNoErrors(&result);
2977
    }
2978
}
2979
2980
/// Test that arrays of anonymous records with extra fields cause count mismatch.
2981
@test unsafe fn testResolveAnonRecordArrayMismatch() throws (testing::TestError) {
2982
    let mut testArena160 = testArena();
2983
    let testStorage160: 'test160 = &mut testArena160 in {
2984
        let mut a = testResolver(testStorage160);
2985
        let program = "record Pt { x: i32, y: i32 } constant ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4, z: 5 }];";
2986
        let result = try resolveProgramStr(&mut a, program);
2987
        let err = try expectError(&result);
2988
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
2989
            else throw testing::TestError::Failed;
2990
    }
2991
}
2992
2993
/// Test that unlabeled record declarations are analyzed correctly.
2994
@test unsafe fn testResolveUnlabeledRecordDecl() throws (testing::TestError) {
2995
    let mut testArena161 = testArena();
2996
    let testStorage161: 'test161 = &mut testArena161 in {
2997
        let mut a = testResolver(testStorage161);
2998
        let program = "record R(i32, bool);";
2999
        let result = try resolveProgramStr(&mut a, program);
3000
        try expectNoErrors(&result);
3001
3002
        // Verify the type symbol was created with labeled=false.
3003
        let nominalTy = try getTypeInScopeOf(&a, result.root, "R");
3004
        let case super::NominalType::Record(recordType) = *nominalTy
3005
            else throw testing::TestError::Failed;
3006
        try testing::expect(not recordType.labeled);
3007
        try testing::expect(recordType.fields.len == 2);
3008
        try testing::expect(recordType.fields[0].name == nil);
3009
        try testing::expect(recordType.fields[1].name == nil);
3010
    }
3011
}
3012
3013
@test unsafe fn testResolveLabeledRecordDecl() throws (testing::TestError) {
3014
    let mut testArena162 = testArena();
3015
    let testStorage162: 'test162 = &mut testArena162 in {
3016
        let mut a = testResolver(testStorage162);
3017
        let program = "record R { x: i32, y: i32 }";
3018
        let result = try resolveProgramStr(&mut a, program);
3019
        try expectNoErrors(&result);
3020
3021
        let nominalTy = try getTypeInScopeOf(&a, result.root, "R");
3022
        let case super::NominalType::Record(recordType) = *nominalTy
3023
            else throw testing::TestError::Failed;
3024
        try testing::expect(recordType.labeled);
3025
        try testing::expect(recordType.fields.len == 2);
3026
        try testing::expect(recordType.fields[0].name <> nil);
3027
        try testing::expect(recordType.fields[1].name <> nil);
3028
    }
3029
}
3030
3031
@test unsafe fn testResolveRecordFieldAccessValid() throws (testing::TestError) {
3032
    let mut testArena163 = testArena();
3033
    let testStorage163: 'test163 = &mut testArena163 in {
3034
        let mut a = testResolver(testStorage163);
3035
        let program = "record Pt { x: i32, y: u8 } let p = Pt { x: 1, y: 2 }; p.y;";
3036
        let result = try resolveProgramStr(&mut a, program);
3037
        try expectNoErrors(&result);
3038
3039
        let fieldStmt = try getBlockStmt(result.root, 2);
3040
        try expectExprStmtType(&a, fieldStmt, super::Type::U8);
3041
    }
3042
}
3043
3044
@test unsafe fn testResolveRecordFieldAccessUnknownField() throws (testing::TestError) {
3045
    let mut testArena164 = testArena();
3046
    let testStorage164: 'test164 = &mut testArena164 in {
3047
        let mut a = testResolver(testStorage164);
3048
        let program = "record Pt { x: i32 } let p = Pt { x: 1 }; p.y;";
3049
        let result = try resolveProgramStr(&mut a, program);
3050
        try expectErrorKind(&result, super::ErrorKind::RecordFieldUnknown("y"));
3051
    }
3052
}
3053
3054
@test unsafe fn testResolveRecordFieldAccessOnFunctionReturn() throws (testing::TestError) {
3055
    let mut testArena165 = testArena();
3056
    let testStorage165: 'test165 = &mut testArena165 in {
3057
        let mut a = testResolver(testStorage165);
3058
        let program = "record Pt { x: i32, y: i32 } fn make() -> Pt { return Pt { x: 5, y: 10 }; } make().x;";
3059
        let result = try resolveProgramStr(&mut a, program);
3060
        try expectNoErrors(&result);
3061
3062
        let stmt = try getBlockStmt(result.root, 2);
3063
        try expectExprStmtType(&a, stmt, super::Type::I32);
3064
    }
3065
}
3066
3067
@test unsafe fn testResolveRecordFieldAccessChained() throws (testing::TestError) {
3068
    let mut testArena166 = testArena();
3069
    let testStorage166: 'test166 = &mut testArena166 in {
3070
        let mut a = testResolver(testStorage166);
3071
        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;";
3072
        let result = try resolveProgramStr(&mut a, program);
3073
        try expectNoErrors(&result);
3074
3075
        let stmt = try getBlockStmt(result.root, 4);
3076
        try expectExprStmtType(&a, stmt, super::Type::I32);
3077
    }
3078
}
3079
3080
@test unsafe fn testResolveRecordFieldAccessOnInteger() throws (testing::TestError) {
3081
    let mut testArena167 = testArena();
3082
    let testStorage167: 'test167 = &mut testArena167 in {
3083
        let mut a = testResolver(testStorage167);
3084
        let program = "let x: i32 = 42; x.field;";
3085
        let result = try resolveBlockStr(&mut a, program);
3086
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
3087
    }
3088
}
3089
3090
@test unsafe fn testResolveRecordFieldAccessOnArray() throws (testing::TestError) {
3091
    let mut testArena168 = testArena();
3092
    let testStorage168: 'test168 = &mut testArena168 in {
3093
        let mut a = testResolver(testStorage168);
3094
        let program = "let arr: [i32; 3] = [1, 2, 3]; arr.field;";
3095
        let result = try resolveProgramStr(&mut a, program);
3096
        try expectErrorKind(&result, super::ErrorKind::ArrayFieldUnknown("field"));
3097
    }
3098
}
3099
3100
@test unsafe fn testResolveRecordFieldAccessOnBool() throws (testing::TestError) {
3101
    let mut testArena169 = testArena();
3102
    let testStorage169: 'test169 = &mut testArena169 in {
3103
        let mut a = testResolver(testStorage169);
3104
        let program = "let b: bool = true; b.field;";
3105
        let result = try resolveProgramStr(&mut a, program);
3106
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
3107
    }
3108
}
3109
3110
@test unsafe fn testResolveRecordFieldAccessOnOptional() throws (testing::TestError) {
3111
    let mut testArena170 = testArena();
3112
    let testStorage170: 'test170 = &mut testArena170 in {
3113
        let mut a = testResolver(testStorage170);
3114
        let program = "record Pt { x: i32 } let opt: ?Pt = Pt { x: 5 }; opt.x;";
3115
        let result = try resolveProgramStr(&mut a, program);
3116
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
3117
    }
3118
}
3119
3120
/// Records may reference themselves through pointers without causing resolution errors.
3121
@test unsafe fn testResolveRecordSelfReferentialPointer() throws (testing::TestError) {
3122
    let mut testArena171 = testArena();
3123
    let testStorage171: 'test171 = &mut testArena171 in {
3124
        let mut a = testResolver(testStorage171);
3125
        let program = "record A { next: *A }";
3126
        let result = try resolveProgramStr(&mut a, program);
3127
        try expectNoErrors(&result);
3128
    }
3129
}
3130
3131
/// Mutually recursive records should resolve without infinite loops.
3132
@test unsafe fn testResolveRecordMutuallyRecursive() throws (testing::TestError) {
3133
    let mut testArena172 = testArena();
3134
    let testStorage172: 'test172 = &mut testArena172 in {
3135
        let mut a = testResolver(testStorage172);
3136
        let program = "record A { b: *B } record B { a: *A }";
3137
        let result = try resolveProgramStr(&mut a, program);
3138
        try expectNoErrors(&result);
3139
    }
3140
}
3141
3142
/// Unions may reference themselves through pointers without causing resolution errors.
3143
@test unsafe fn testResolveUnionSelfReferentialPointerAllowed() throws (testing::TestError) {
3144
    let mut testArena173 = testArena();
3145
    let testStorage173: 'test173 = &mut testArena173 in {
3146
        let mut a = testResolver(testStorage173);
3147
        let program = "union List { Cons(*List), Nil }";
3148
        let result = try resolveProgramStr(&mut a, program);
3149
        try expectNoErrors(&result);
3150
    }
3151
}
3152
3153
/// Mutually recursive unions should resolve without infinite loops.
3154
@test unsafe fn testResolveUnionMutuallyRecursive() throws (testing::TestError) {
3155
    let mut testArena174 = testArena();
3156
    let testStorage174: 'test174 = &mut testArena174 in {
3157
        let mut a = testResolver(testStorage174);
3158
        let program = "union A { HasB(*B), None } union B { HasA(*A), None }";
3159
        let result = try resolveProgramStr(&mut a, program);
3160
        try expectNoErrors(&result);
3161
    }
3162
}
3163
3164
/// Unions with record payloads containing slice references to self should resolve.
3165
/// This matches the pattern in sexpr.rad: `List { tail: *[Expr] }`.
3166
@test unsafe fn testResolveUnionRecordPayloadWithSliceSelfRef() throws (testing::TestError) {
3167
    let mut testArena175 = testArena();
3168
    let testStorage175: 'test175 = &mut testArena175 in {
3169
        let mut a = testResolver(testStorage175);
3170
        let program = "union Expr { Null, List { head: *[u8], tail: *[Expr] } }";
3171
        let result = try resolveProgramStr(&mut a, program);
3172
        try expectNoErrors(&result);
3173
    }
3174
}
3175
3176
@test unsafe fn testUndefinedCoercions() throws (testing::TestError) {
3177
    {
3178
        let mut testArena176 = testArena();
3179
        let testStorage176: 'test176 = &mut testArena176 in {
3180
            let mut a = testResolver(testStorage176);
3181
            let result = try resolveBlockStr(&mut a, "unsafe { let count: i32 = undefined; }");
3182
            try expectNoErrors(&result);
3183
        }
3184
    } {
3185
        let mut testArena177 = testArena();
3186
        let testStorage177: 'test177 = &mut testArena177 in {
3187
            let mut a = testResolver(testStorage177);
3188
            let program = "unsafe { let mut value: i32 = 0; set value = undefined; }";
3189
            let result = try resolveProgramStr(&mut a, program);
3190
            try expectNoErrors(&result);
3191
        }
3192
    } {
3193
        let mut testArena178 = testArena();
3194
        let testStorage178: 'test178 = &mut testArena178 in {
3195
            let mut a = testResolver(testStorage178);
3196
            let program = "fn f(x: i32) {} unsafe fn g() { f(undefined); }";
3197
            let result = try resolveProgramStr(&mut a, program);
3198
            try expectNoErrors(&result);
3199
        }
3200
    } {
3201
        let mut testArena179 = testArena();
3202
        let testStorage179: 'test179 = &mut testArena179 in {
3203
            let mut a = testResolver(testStorage179);
3204
            let program = "unsafe fn fetch() -> i32 { return undefined; }";
3205
            let result = try resolveProgramStr(&mut a, program);
3206
            try expectNoErrors(&result);
3207
        }
3208
    }
3209
}
3210
3211
@test unsafe fn testResolveBlockVoid() throws (testing::TestError) {
3212
    let mut testArena180 = testArena();
3213
    let testStorage180: 'test180 = &mut testArena180 in {
3214
        let mut a = testResolver(testStorage180);
3215
        let result = try resolveProgramStr(&mut a, "{ 42; }");
3216
        try expectNoErrors(&result);
3217
3218
        let block = try getBlockStmt(result.root, 0);
3219
        try expectType(&a, block, super::Type::Void);
3220
    }
3221
}
3222
3223
@test unsafe fn testResolveBlockNever() throws (testing::TestError) {
3224
    let mut testArena181 = testArena();
3225
    let testStorage181: 'test181 = &mut testArena181 in {
3226
        let mut a = testResolver(testStorage181);
3227
        let result = try resolveProgramStr(&mut a, "{ panic; }");
3228
        try expectNoErrors(&result);
3229
3230
        let block = try getBlockStmt(result.root, 0);
3231
        try expectType(&a, block, super::Type::Never);
3232
    }
3233
}
3234
3235
@test unsafe fn testResolveIfAllBranchesNever() throws (testing::TestError) {
3236
    let mut testArena182 = testArena();
3237
    let testStorage182: 'test182 = &mut testArena182 in {
3238
        let mut a = testResolver(testStorage182);
3239
        let program = "if true { panic; } else { panic; }";
3240
        let result = try resolveProgramStr(&mut a, program);
3241
        try expectNoErrors(&result);
3242
3243
        let stmt = try getBlockStmt(result.root, 0);
3244
        try expectType(&a, stmt, super::Type::Never);
3245
    }
3246
}
3247
3248
@test unsafe fn testResolveIfMixedBranchesNotNever() throws (testing::TestError) {
3249
    let mut testArena183 = testArena();
3250
    let testStorage183: 'test183 = &mut testArena183 in {
3251
        let mut a = testResolver(testStorage183);
3252
        let program = "if true { panic; } else {}";
3253
        let result = try resolveProgramStr(&mut a, program);
3254
        try expectNoErrors(&result);
3255
3256
        let stmt = try getBlockStmt(result.root, 0);
3257
        try expectType(&a, stmt, super::Type::Void);
3258
    }
3259
}
3260
3261
@test unsafe fn testResolveLetElse() throws (testing::TestError) {
3262
    let mut testArena184 = testArena();
3263
    let testStorage184: 'test184 = &mut testArena184 in {
3264
        let mut a = testResolver(testStorage184);
3265
        let program = "let opt: ?i32 = 42; let value = opt else panic; value;";
3266
        let result = try resolveProgramStr(&mut a, program);
3267
        try expectNoErrors(&result);
3268
3269
        let blockNode = result.root;
3270
        let case ast::NodeValue::Block(block) = blockNode.value
3271
            else throw testing::TestError::Failed;
3272
        let letElseNode = try getBlockStmt(blockNode, 1);
3273
        let valueStmt = try getBlockStmt(blockNode, 2);
3274
3275
        { // Ensure the bound identifier receives the inner optional type.
3276
            let valueExpr = try expectExprStmtType(&a, valueStmt, super::Type::I32);
3277
3278
            let sym = super::symbolFor(&a, valueExpr)
3279
                else throw testing::TestError::Failed;
3280
            let case super::SymbolData::Value { type: valType, .. } = sym.data
3281
                else throw testing::TestError::Failed;
3282
            try testing::expect(valType == super::Type::I32);
3283
        }
3284
        // The let-else statement itself should be typed as void.
3285
        try expectType(&a, letElseNode, super::Type::Void);
3286
    }
3287
}
3288
3289
@test unsafe fn testResolveLetElseDefaultValue() throws (testing::TestError) {
3290
    let mut testArena185 = testArena();
3291
    let testStorage185: 'test185 = &mut testArena185 in {
3292
        let mut a = testResolver(testStorage185);
3293
        let program = "let opt: ?i32 = nil; let value = opt else 42; value;";
3294
        let result = try resolveProgramStr(&mut a, program);
3295
        try expectNoErrors(&result);
3296
    }
3297
}
3298
3299
@test unsafe fn testResolveLetElseRequiresDivergentElse() throws (testing::TestError) {
3300
    let mut testArena186 = testArena();
3301
    let testStorage186: 'test186 = &mut testArena186 in {
3302
        let mut a = testResolver(testStorage186);
3303
        let program = "let opt: ?i32 = nil; let value = opt else {}; value;";
3304
        let result = try resolveProgramStr(&mut a, program);
3305
        let err = try expectError(&result);
3306
        try expectTypeMismatch(err, super::Type::I32, super::Type::Void);
3307
    }
3308
}
3309
3310
@test unsafe fn testResolveLetElseRequiresOptional() throws (testing::TestError) {
3311
    let mut testArena187 = testArena();
3312
    let testStorage187: 'test187 = &mut testArena187 in {
3313
        let mut a = testResolver(testStorage187);
3314
        let program = "let x: i32 = 42; let value = x else panic;";
3315
        let result = try resolveProgramStr(&mut a, program);
3316
        try expectErrorKind(&result, super::ErrorKind::ExpectedOptional);
3317
    }
3318
}
3319
3320
/// Test that `if let mut` produces a mutable binding.
3321
@test unsafe fn testResolveIfLetMut() throws (testing::TestError) {
3322
    let mut testArena188 = testArena();
3323
    let testStorage188: 'test188 = &mut testArena188 in {
3324
        let mut a = testResolver(testStorage188);
3325
        let program = "let opt: ?i32 = 42; if let mut v = opt { set v = v + 1; }";
3326
        let result = try resolveProgramStr(&mut a, program);
3327
        try expectNoErrors(&result);
3328
    }
3329
}
3330
3331
/// Test that `if let` (without mut) rejects assignment.
3332
@test unsafe fn testResolveIfLetImmutable() throws (testing::TestError) {
3333
    let mut testArena189 = testArena();
3334
    let testStorage189: 'test189 = &mut testArena189 in {
3335
        let mut a = testResolver(testStorage189);
3336
        let program = "let opt: ?i32 = 42; if let v = opt { set v = 1; }";
3337
        let result = try resolveProgramStr(&mut a, program);
3338
        let err = try expectError(&result);
3339
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3340
    }
3341
}
3342
3343
/// Test that `let mut ... else` produces a mutable binding.
3344
@test unsafe fn testResolveLetMutElse() throws (testing::TestError) {
3345
    let mut testArena190 = testArena();
3346
    let testStorage190: 'test190 = &mut testArena190 in {
3347
        let mut a = testResolver(testStorage190);
3348
        let program = "let opt: ?i32 = 42; let mut v = opt else panic; set v = v + 1;";
3349
        let result = try resolveProgramStr(&mut a, program);
3350
        try expectNoErrors(&result);
3351
    }
3352
}
3353
3354
/// Test that `let ... else` (without mut) rejects assignment.
3355
@test unsafe fn testResolveLetElseImmutable() throws (testing::TestError) {
3356
    let mut testArena191 = testArena();
3357
    let testStorage191: 'test191 = &mut testArena191 in {
3358
        let mut a = testResolver(testStorage191);
3359
        let program = "let opt: ?i32 = 42; let v = opt else panic; set v = 1;";
3360
        let result = try resolveProgramStr(&mut a, program);
3361
        let err = try expectError(&result);
3362
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3363
    }
3364
}
3365
3366
@test unsafe fn testResolveLetCaseElse() throws (testing::TestError) {
3367
    {
3368
        let mut testArena192 = testArena();
3369
        let testStorage192: 'test192 = &mut testArena192 in {
3370
            let mut a = testResolver(testStorage192);
3371
            let program = "let case _ = 1 else panic;";
3372
            let result = try resolveProgramStr(&mut a, program);
3373
            try expectNoErrors(&result);
3374
        }
3375
    } {
3376
        let mut testArena193 = testArena();
3377
        let testStorage193: 'test193 = &mut testArena193 in {
3378
            let mut a = testResolver(testStorage193);
3379
            let program = "let case _ = true else false;";
3380
            let result = try resolveProgramStr(&mut a, program);
3381
            try expectNoErrors(&result);
3382
        }
3383
    }
3384
}
3385
3386
@test unsafe fn testResolveLetCaseElseRequiresDivergentElse() throws (testing::TestError) {
3387
    let mut testArena194 = testArena();
3388
    let testStorage194: 'test194 = &mut testArena194 in {
3389
        let mut a = testResolver(testStorage194);
3390
        let program = "let case _ = 1 else {};";
3391
        let result = try resolveProgramStr(&mut a, program);
3392
        let err = try expectError(&result);
3393
        try expectTypeMismatch(err, super::Type::Int, super::Type::Void);
3394
    }
3395
}
3396
3397
@test unsafe fn testResolveTryValidPropagation() throws (testing::TestError) {
3398
    let mut testArena195 = testArena();
3399
    let testStorage195: 'test195 = &mut testArena195 in {
3400
        let mut a = testResolver(testStorage195);
3401
        let program = "fn fallible() throws (i32) {} fn caller() throws (i32) { try fallible() }";
3402
        let result = try resolveProgramStr(&mut a, program);
3403
        try expectNoErrors(&result);
3404
    }
3405
}
3406
3407
@test unsafe fn testResolveTryRequiresThrowsClause() throws (testing::TestError) {
3408
    let mut testArena196 = testArena();
3409
    let testStorage196: 'test196 = &mut testArena196 in {
3410
        let mut a = testResolver(testStorage196);
3411
        let program = "fn fallible() throws (i32) {} fn caller() { try fallible() }";
3412
        let result = try resolveProgramStr(&mut a, program);
3413
        try expectErrorKind(&result, super::ErrorKind::TryRequiresThrows);
3414
    }
3415
}
3416
3417
@test unsafe fn testResolveTryIncompatibleError() throws (testing::TestError) {
3418
    let mut testArena197 = testArena();
3419
    let testStorage197: 'test197 = &mut testArena197 in {
3420
        let mut a = testResolver(testStorage197);
3421
        let program = "fn fallible() throws (i32) {} fn caller() throws (i8) { try fallible() }";
3422
        let result = try resolveProgramStr(&mut a, program);
3423
        try expectErrorKind(&result, super::ErrorKind::TryIncompatibleError);
3424
    }
3425
}
3426
3427
@test unsafe fn testResolveTryNonThrowing() throws (testing::TestError) {
3428
    let mut testArena198 = testArena();
3429
    let testStorage198: 'test198 = &mut testArena198 in {
3430
        let mut a = testResolver(testStorage198);
3431
        let program = "fn safe() {} fn caller() throws (i32) { try safe() }";
3432
        let result = try resolveProgramStr(&mut a, program);
3433
        try expectErrorKind(&result, super::ErrorKind::TryNonThrowing);
3434
    }
3435
}
3436
3437
@test unsafe fn testResolveTryCatchBlockMatchesResult() throws (testing::TestError) {
3438
    let mut testArena199 = testArena();
3439
    let testStorage199: 'test199 = &mut testArena199 in {
3440
        let mut a = testResolver(testStorage199);
3441
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { return 42; }; }";
3442
        let result = try resolveProgramStr(&mut a, program);
3443
        try expectNoErrors(&result);
3444
    }
3445
}
3446
3447
@test unsafe fn testResolveTryCatchBlockDiverges() throws (testing::TestError) {
3448
    let mut testArena200 = testArena();
3449
    let testStorage200: 'test200 = &mut testArena200 in {
3450
        let mut a = testResolver(testStorage200);
3451
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { return 7; }; }";
3452
        let result = try resolveProgramStr(&mut a, program);
3453
        try expectNoErrors(&result);
3454
    }
3455
}
3456
3457
@test unsafe fn testResolveTryCatchBlockMustDiverge() throws (testing::TestError) {
3458
    let mut testArena201 = testArena();
3459
    let testStorage201: 'test201 = &mut testArena201 in {
3460
        let mut a = testResolver(testStorage201);
3461
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { 7; }; }";
3462
        let result = try resolveProgramStr(&mut a, program);
3463
        let err = try expectError(&result);
3464
        try expectTypeMismatch(err, super::Type::U32, super::Type::Void);
3465
    }
3466
}
3467
3468
@test unsafe fn testResolveCallMissingTry() throws (testing::TestError) {
3469
    let mut testArena202 = testArena();
3470
    let testStorage202: 'test202 = &mut testArena202 in {
3471
        let mut a = testResolver(testStorage202);
3472
        let program = "fn fallible() throws (i32) {} fn caller() { fallible() }";
3473
        let result = try resolveProgramStr(&mut a, program);
3474
        try expectErrorKind(&result, super::ErrorKind::MissingTry);
3475
    }
3476
}
3477
3478
/// Test that `try?` converts errors to optionals without requiring caller to throw.
3479
@test unsafe fn testResolveTryOptionalConvertsToOptional() throws (testing::TestError) {
3480
    // `try?` should wrap the return type in optional and not require caller to throw.
3481
    {
3482
        let mut testArena203 = testArena();
3483
        let testStorage203: 'test203 = &mut testArena203 in {
3484
            let mut a = testResolver(testStorage203);
3485
            let program = "record S {} fn fallible() -> *S throws (i32) { panic; } fn caller() -> ?*S { return try? fallible(); }";
3486
            let result = try resolveProgramStr(&mut a, program);
3487
            try expectNoErrors(&result);
3488
        }
3489
    }
3490
    // `try?` works in non-throwing function.
3491
    {
3492
        let mut testArena204 = testArena();
3493
        let testStorage204: 'test204 = &mut testArena204 in {
3494
            let mut a = testResolver(testStorage204);
3495
            let program = "fn fallible() -> i32 throws (i32) { panic; } fn caller() -> ?i32 { return try? fallible(); }";
3496
            let result = try resolveProgramStr(&mut a, program);
3497
            try expectNoErrors(&result);
3498
        }
3499
    }
3500
    // `try?` can be used in if-let patterns.
3501
    {
3502
        let mut testArena205 = testArena();
3503
        let testStorage205: 'test205 = &mut testArena205 in {
3504
            let mut a = testResolver(testStorage205);
3505
            let program = "fn fallible() -> i32 throws (i32) { panic; } fn caller() -> i32 { if let x = try? fallible() { return x; } return 0; }";
3506
            let result = try resolveProgramStr(&mut a, program);
3507
            try expectNoErrors(&result);
3508
        }
3509
    }
3510
}
3511
3512
@test unsafe fn testResolveThrowValid() throws (testing::TestError) {
3513
    let mut testArena206 = testArena();
3514
    let testStorage206: 'test206 = &mut testArena206 in {
3515
        let mut a = testResolver(testStorage206);
3516
        let program = "fn fail() throws (i32) { throw 1; }";
3517
        let result = try resolveProgramStr(&mut a, program);
3518
        try expectNoErrors(&result);
3519
    }
3520
}
3521
3522
@test unsafe fn testResolveThrowRequiresThrowsClause() throws (testing::TestError) {
3523
    let mut testArena207 = testArena();
3524
    let testStorage207: 'test207 = &mut testArena207 in {
3525
        let mut a = testResolver(testStorage207);
3526
        let program = "fn fail() { throw 1; }";
3527
        let result = try resolveProgramStr(&mut a, program);
3528
        try expectErrorKind(&result, super::ErrorKind::ThrowRequiresThrows);
3529
    }
3530
}
3531
3532
@test unsafe fn testResolveThrowIncompatibleError() throws (testing::TestError) {
3533
    let mut testArena208 = testArena();
3534
    let testStorage208: 'test208 = &mut testArena208 in {
3535
        let mut a = testResolver(testStorage208);
3536
        let program = "fn fail() throws (i32) { throw true; }";
3537
        let result = try resolveProgramStr(&mut a, program);
3538
        try expectErrorKind(&result, super::ErrorKind::ThrowIncompatibleError);
3539
    }
3540
}
3541
3542
// Binary operation tests //////////////////////////////////////////////////////
3543
3544
@test unsafe fn testResolveBinaryOpArithmetic() throws (testing::TestError) {
3545
    {
3546
        let mut testArena209 = testArena();
3547
        let testStorage209: 'test209 = &mut testArena209 in {
3548
            let mut a = testResolver(testStorage209);
3549
            let result = try resolveExprStr(&mut a, "4 + 4");
3550
            try expectNoErrors(&result);
3551
            try expectType(&a, result.root, super::Type::Int);
3552
        }
3553
    } {
3554
        let mut testArena210 = testArena();
3555
        let testStorage210: 'test210 = &mut testArena210 in {
3556
            let mut a = testResolver(testStorage210);
3557
            let result = try resolveExprStr(&mut a, "10 - 3");
3558
            try expectNoErrors(&result);
3559
            try expectType(&a, result.root, super::Type::Int);
3560
        }
3561
    } {
3562
        let mut testArena211 = testArena();
3563
        let testStorage211: 'test211 = &mut testArena211 in {
3564
            let mut a = testResolver(testStorage211);
3565
            let result = try resolveExprStr(&mut a, "5 * 6");
3566
            try expectNoErrors(&result);
3567
            try expectType(&a, result.root, super::Type::Int);
3568
        }
3569
    } {
3570
        let mut testArena212 = testArena();
3571
        let testStorage212: 'test212 = &mut testArena212 in {
3572
            let mut a = testResolver(testStorage212);
3573
            let result = try resolveExprStr(&mut a, "20 / 4");
3574
            try expectNoErrors(&result);
3575
            try expectType(&a, result.root, super::Type::Int);
3576
        }
3577
    } {
3578
        let mut testArena213 = testArena();
3579
        let testStorage213: 'test213 = &mut testArena213 in {
3580
            let mut a = testResolver(testStorage213);
3581
            let result = try resolveExprStr(&mut a, "17 % 5");
3582
            try expectNoErrors(&result);
3583
            try expectType(&a, result.root, super::Type::Int);
3584
        }
3585
    } {
3586
        let mut testArena214 = testArena();
3587
        let testStorage214: 'test214 = &mut testArena214 in {
3588
            let mut a = testResolver(testStorage214);
3589
            let result = try resolveBlockStr(&mut a, "let x: i32 = 4; let y: i32 = 5; x + y;");
3590
            try expectNoErrors(&result);
3591
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3592
            try expectExprStmtType(&a, stmt, super::Type::I32);
3593
        }
3594
    } {
3595
        let mut testArena215 = testArena();
3596
        let testStorage215: 'test215 = &mut testArena215 in {
3597
            let mut a = testResolver(testStorage215);
3598
            let result = try resolveExprStr(&mut a, "1 + (2 * 3) - 4");
3599
            try expectNoErrors(&result);
3600
            try expectType(&a, result.root, super::Type::Int);
3601
        }
3602
    } {
3603
        let mut testArena216 = testArena();
3604
        let testStorage216: 'test216 = &mut testArena216 in {
3605
            let mut a = testResolver(testStorage216);
3606
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n * 2;");
3607
            try expectNoErrors(&result);
3608
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3609
            try expectExprStmtType(&a, stmt, super::Type::I32);
3610
        }
3611
    } {
3612
        let mut testArena217 = testArena();
3613
        let testStorage217: 'test217 = &mut testArena217 in {
3614
            let mut a = testResolver(testStorage217);
3615
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; 2 * n;");
3616
            try expectNoErrors(&result);
3617
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3618
            try expectExprStmtType(&a, stmt, super::Type::I32);
3619
        }
3620
    } {
3621
        let mut testArena218 = testArena();
3622
        let testStorage218: 'test218 = &mut testArena218 in {
3623
            let mut a = testResolver(testStorage218);
3624
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n - 1;");
3625
            try expectNoErrors(&result);
3626
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3627
            try expectExprStmtType(&a, stmt, super::Type::I32);
3628
        }
3629
    }
3630
}
3631
3632
@test unsafe fn testResolveBinaryOpComparison() throws (testing::TestError) {
3633
    {
3634
        let mut testArena219 = testArena();
3635
        let testStorage219: 'test219 = &mut testArena219 in {
3636
            let mut a = testResolver(testStorage219);
3637
            let result = try resolveExprStr(&mut a, "5 == 5");
3638
            try expectNoErrors(&result);
3639
            try expectType(&a, result.root, super::Type::Bool);
3640
        }
3641
    } {
3642
        let mut testArena220 = testArena();
3643
        let testStorage220: 'test220 = &mut testArena220 in {
3644
            let mut a = testResolver(testStorage220);
3645
            let result = try resolveExprStr(&mut a, "5 <> 10");
3646
            try expectNoErrors(&result);
3647
            try expectType(&a, result.root, super::Type::Bool);
3648
        }
3649
    } {
3650
        let mut testArena221 = testArena();
3651
        let testStorage221: 'test221 = &mut testArena221 in {
3652
            let mut a = testResolver(testStorage221);
3653
            let result = try resolveExprStr(&mut a, "5 < 10");
3654
            try expectNoErrors(&result);
3655
            try expectType(&a, result.root, super::Type::Bool);
3656
        }
3657
    } {
3658
        let mut testArena222 = testArena();
3659
        let testStorage222: 'test222 = &mut testArena222 in {
3660
            let mut a = testResolver(testStorage222);
3661
            let result = try resolveExprStr(&mut a, "10 > 5");
3662
            try expectNoErrors(&result);
3663
            try expectType(&a, result.root, super::Type::Bool);
3664
        }
3665
    } {
3666
        let mut testArena223 = testArena();
3667
        let testStorage223: 'test223 = &mut testArena223 in {
3668
            let mut a = testResolver(testStorage223);
3669
            let result = try resolveExprStr(&mut a, "5 <= 5");
3670
            try expectNoErrors(&result);
3671
            try expectType(&a, result.root, super::Type::Bool);
3672
        }
3673
    } {
3674
        let mut testArena224 = testArena();
3675
        let testStorage224: 'test224 = &mut testArena224 in {
3676
            let mut a = testResolver(testStorage224);
3677
            let result = try resolveExprStr(&mut a, "10 >= 5");
3678
            try expectNoErrors(&result);
3679
            try expectType(&a, result.root, super::Type::Bool);
3680
        }
3681
    } {
3682
        let mut testArena225 = testArena();
3683
        let testStorage225: 'test225 = &mut testArena225 in {
3684
            let mut a = testResolver(testStorage225);
3685
            let result = try resolveExprStr(&mut a, "true == false");
3686
            try expectNoErrors(&result);
3687
            try expectType(&a, result.root, super::Type::Bool);
3688
        }
3689
    } {
3690
        let mut testArena226 = testArena();
3691
        let testStorage226: 'test226 = &mut testArena226 in {
3692
            let mut a = testResolver(testStorage226);
3693
            let result = try resolveExprStr(&mut a, "5 + 3 > 10 - 4");
3694
            try expectNoErrors(&result);
3695
            try expectType(&a, result.root, super::Type::Bool);
3696
        }
3697
    } {
3698
        let mut testArena227 = testArena();
3699
        let testStorage227: 'test227 = &mut testArena227 in {
3700
            let mut a = testResolver(testStorage227);
3701
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n == 1;");
3702
            try expectNoErrors(&result);
3703
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3704
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3705
        }
3706
    } {
3707
        let mut testArena228 = testArena();
3708
        let testStorage228: 'test228 = &mut testArena228 in {
3709
            let mut a = testResolver(testStorage228);
3710
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; 1 == n;");
3711
            try expectNoErrors(&result);
3712
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3713
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3714
        }
3715
    }
3716
}
3717
3718
@test unsafe fn testResolveBinaryOpLogical() throws (testing::TestError) {
3719
    {
3720
        let mut testArena229 = testArena();
3721
        let testStorage229: 'test229 = &mut testArena229 in {
3722
            let mut a = testResolver(testStorage229);
3723
            let result = try resolveBlockStr(&mut a, "let x: bool = true; let y: bool = false; x and y;");
3724
            try expectNoErrors(&result);
3725
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3726
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3727
        }
3728
    } {
3729
        let mut testArena230 = testArena();
3730
        let testStorage230: 'test230 = &mut testArena230 in {
3731
            let mut a = testResolver(testStorage230);
3732
            let result = try resolveBlockStr(&mut a, "let x: bool = true; let y: bool = false; x or y;");
3733
            try expectNoErrors(&result);
3734
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3735
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3736
        }
3737
    } {
3738
        let mut testArena231 = testArena();
3739
        let testStorage231: 'test231 = &mut testArena231 in {
3740
            let mut a = testResolver(testStorage231);
3741
            let result = try resolveExprStr(&mut a, "true and false");
3742
            try expectNoErrors(&result);
3743
            try expectType(&a, result.root, super::Type::Bool);
3744
        }
3745
    }
3746
}
3747
3748
@test unsafe fn testResolveBinaryOpArithmeticTypeMismatch() throws (testing::TestError) {
3749
    {
3750
        let mut testArena232 = testArena();
3751
        let testStorage232: 'test232 = &mut testArena232 in {
3752
            let mut a = testResolver(testStorage232);
3753
            let result = try resolveProgramStr(&mut a, "4 + true");
3754
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3755
        }
3756
    } {
3757
        let mut testArena233 = testArena();
3758
        let testStorage233: 'test233 = &mut testArena233 in {
3759
            let mut a = testResolver(testStorage233);
3760
            let result = try resolveBlockStr(&mut a, "let x: i32 = 4; let y: bool = false; x + y;");
3761
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3762
        }
3763
    } {
3764
        let mut testArena234 = testArena();
3765
        let testStorage234: 'test234 = &mut testArena234 in {
3766
            let mut a = testResolver(testStorage234);
3767
            let result = try resolveProgramStr(&mut a, "10 - false");
3768
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3769
        }
3770
    } {
3771
        let mut testArena235 = testArena();
3772
        let testStorage235: 'test235 = &mut testArena235 in {
3773
            let mut a = testResolver(testStorage235);
3774
            let result = try resolveProgramStr(&mut a, "5 * true");
3775
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3776
        }
3777
    } {
3778
        let mut testArena236 = testArena();
3779
        let testStorage236: 'test236 = &mut testArena236 in {
3780
            let mut a = testResolver(testStorage236);
3781
            let result = try resolveProgramStr(&mut a, "20 / false");
3782
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3783
        }
3784
    } {
3785
        let mut testArena237 = testArena();
3786
        let testStorage237: 'test237 = &mut testArena237 in {
3787
            let mut a = testResolver(testStorage237);
3788
            let result = try resolveProgramStr(&mut a, "17 % true");
3789
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3790
        }
3791
    } {
3792
        let mut testArena238 = testArena();
3793
        let testStorage238: 'test238 = &mut testArena238 in {
3794
            let mut a = testResolver(testStorage238);
3795
            let result = try resolveProgramStr(&mut a, "1 + (true * 3)");
3796
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3797
        }
3798
    }
3799
}
3800
3801
@test unsafe fn testResolveBinaryOpLogicalTypeMismatch() throws (testing::TestError) {
3802
    {
3803
        let mut testArena239 = testArena();
3804
        let testStorage239: 'test239 = &mut testArena239 in {
3805
            let mut a = testResolver(testStorage239);
3806
            let result = try resolveProgramStr(&mut a, "42 and true");
3807
            let err = try expectError(&result);
3808
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3809
        }
3810
    } {
3811
        let mut testArena240 = testArena();
3812
        let testStorage240: 'test240 = &mut testArena240 in {
3813
            let mut a = testResolver(testStorage240);
3814
            let result = try resolveProgramStr(&mut a, "true or 5");
3815
            let err = try expectError(&result);
3816
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3817
        }
3818
    } {
3819
        let mut testArena241 = testArena();
3820
        let testStorage241: 'test241 = &mut testArena241 in {
3821
            let mut a = testResolver(testStorage241);
3822
            let result = try resolveProgramStr(&mut a, "1 and 2");
3823
            let err = try expectError(&result);
3824
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3825
        }
3826
    }
3827
}
3828
3829
@test unsafe fn testResolveBinaryOpComparisonTypeMismatch() throws (testing::TestError) {
3830
    let mut testArena242 = testArena();
3831
    let testStorage242: 'test242 = &mut testArena242 in {
3832
        let mut a = testResolver(testStorage242);
3833
        let result = try resolveProgramStr(&mut a, "true < false");
3834
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3835
    }
3836
}
3837
3838
// Unary operation tests ///////////////////////////////////////////////////////
3839
3840
@test unsafe fn testResolveUnaryOpNot() throws (testing::TestError) {
3841
    {
3842
        let mut testArena243 = testArena();
3843
        let testStorage243: 'test243 = &mut testArena243 in {
3844
            let mut a = testResolver(testStorage243);
3845
            let result = try resolveExprStr(&mut a, "not true");
3846
            try expectNoErrors(&result);
3847
            try expectType(&a, result.root, super::Type::Bool);
3848
        }
3849
    } {
3850
        let mut testArena244 = testArena();
3851
        let testStorage244: 'test244 = &mut testArena244 in {
3852
            let mut a = testResolver(testStorage244);
3853
            let result = try resolveBlockStr(&mut a, "let x: bool = true; not x;");
3854
            try expectNoErrors(&result);
3855
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3856
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3857
        }
3858
    } {
3859
        let mut testArena245 = testArena();
3860
        let testStorage245: 'test245 = &mut testArena245 in {
3861
            let mut a = testResolver(testStorage245);
3862
            let result = try resolveExprStr(&mut a, "not (true and false)");
3863
            try expectNoErrors(&result);
3864
            try expectType(&a, result.root, super::Type::Bool);
3865
        }
3866
    } {
3867
        let mut testArena246 = testArena();
3868
        let testStorage246: 'test246 = &mut testArena246 in {
3869
            let mut a = testResolver(testStorage246);
3870
            let result = try resolveProgramStr(&mut a, "not 42");
3871
            let err = try expectError(&result);
3872
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3873
        }
3874
    } {
3875
        let mut testArena247 = testArena();
3876
        let testStorage247: 'test247 = &mut testArena247 in {
3877
            let mut a = testResolver(testStorage247);
3878
            let result = try resolveBlockStr(&mut a, "let x: i32 = 5; not x;");
3879
            let err = try expectError(&result);
3880
            try expectTypeMismatch(err, super::Type::Bool, super::Type::I32);
3881
        }
3882
    }
3883
}
3884
3885
@test unsafe fn testResolveUnaryOpNeg() throws (testing::TestError) {
3886
    {
3887
        let mut testArena248 = testArena();
3888
        let testStorage248: 'test248 = &mut testArena248 in {
3889
            let mut a = testResolver(testStorage248);
3890
            let result = try resolveExprStr(&mut a, "-42");
3891
            try expectNoErrors(&result);
3892
            try expectType(&a, result.root, super::Type::Int);
3893
        }
3894
    } {
3895
        let mut testArena249 = testArena();
3896
        let testStorage249: 'test249 = &mut testArena249 in {
3897
            let mut a = testResolver(testStorage249);
3898
            let result = try resolveBlockStr(&mut a, "let x: i32 = 10; -x;");
3899
            try expectNoErrors(&result);
3900
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3901
            try expectExprStmtType(&a, stmt, super::Type::I32);
3902
        }
3903
    } {
3904
        let mut testArena250 = testArena();
3905
        let testStorage250: 'test250 = &mut testArena250 in {
3906
            let mut a = testResolver(testStorage250);
3907
            let result = try resolveExprStr(&mut a, "-(5 + 3)");
3908
            try expectNoErrors(&result);
3909
            try expectType(&a, result.root, super::Type::Int);
3910
        }
3911
    } {
3912
        let mut testArena251 = testArena();
3913
        let testStorage251: 'test251 = &mut testArena251 in {
3914
            let mut a = testResolver(testStorage251);
3915
            let result = try resolveBlockStr(&mut a, "let x: i8 = 5; -x;");
3916
            try expectNoErrors(&result);
3917
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3918
            try expectExprStmtType(&a, stmt, super::Type::I8);
3919
        }
3920
    } {
3921
        let mut testArena252 = testArena();
3922
        let testStorage252: 'test252 = &mut testArena252 in {
3923
            let mut a = testResolver(testStorage252);
3924
            let result = try resolveProgramStr(&mut a, "-true");
3925
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3926
        }
3927
    } {
3928
        let mut testArena253 = testArena();
3929
        let testStorage253: 'test253 = &mut testArena253 in {
3930
            let mut a = testResolver(testStorage253);
3931
            let result = try resolveBlockStr(&mut a, "let x: bool = false; -x;");
3932
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3933
        }
3934
    }
3935
}
3936
3937
@test unsafe fn testResolveUnaryOpBitNot() throws (testing::TestError) {
3938
    {
3939
        let mut testArena254 = testArena();
3940
        let testStorage254: 'test254 = &mut testArena254 in {
3941
            let mut a = testResolver(testStorage254);
3942
            let result = try resolveExprStr(&mut a, "~42");
3943
            try expectNoErrors(&result);
3944
            try expectType(&a, result.root, super::Type::Int);
3945
        }
3946
    } {
3947
        let mut testArena255 = testArena();
3948
        let testStorage255: 'test255 = &mut testArena255 in {
3949
            let mut a = testResolver(testStorage255);
3950
            let result = try resolveBlockStr(&mut a, "let x: u32 = 255; ~x;");
3951
            try expectNoErrors(&result);
3952
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3953
            try expectExprStmtType(&a, stmt, super::Type::U32);
3954
        }
3955
    } {
3956
        let mut testArena256 = testArena();
3957
        let testStorage256: 'test256 = &mut testArena256 in {
3958
            let mut a = testResolver(testStorage256);
3959
            let result = try resolveExprStr(&mut a, "~(0xFF)");
3960
            try expectNoErrors(&result);
3961
            try expectType(&a, result.root, super::Type::Int);
3962
        }
3963
    } {
3964
        let mut testArena257 = testArena();
3965
        let testStorage257: 'test257 = &mut testArena257 in {
3966
            let mut a = testResolver(testStorage257);
3967
            let result = try resolveBlockStr(&mut a, "let x: i8 = 5; ~x;");
3968
            try expectNoErrors(&result);
3969
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3970
            try expectExprStmtType(&a, stmt, super::Type::I8);
3971
        }
3972
    } {
3973
        let mut testArena258 = testArena();
3974
        let testStorage258: 'test258 = &mut testArena258 in {
3975
            let mut a = testResolver(testStorage258);
3976
            let result = try resolveProgramStr(&mut a, "~true");
3977
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3978
        }
3979
    } {
3980
        let mut testArena259 = testArena();
3981
        let testStorage259: 'test259 = &mut testArena259 in {
3982
            let mut a = testResolver(testStorage259);
3983
            let result = try resolveBlockStr(&mut a, "let x: bool = false; ~x;");
3984
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3985
        }
3986
    }
3987
}
3988
3989
@test unsafe fn testResolveUnaryOpNested() throws (testing::TestError) {
3990
    {
3991
        let mut testArena260 = testArena();
3992
        let testStorage260: 'test260 = &mut testArena260 in {
3993
            let mut a = testResolver(testStorage260);
3994
            let result = try resolveExprStr(&mut a, "not not true");
3995
            try expectNoErrors(&result);
3996
            try expectType(&a, result.root, super::Type::Bool);
3997
        }
3998
    } {
3999
        let mut testArena261 = testArena();
4000
        let testStorage261: 'test261 = &mut testArena261 in {
4001
            let mut a = testResolver(testStorage261);
4002
            let result = try resolveExprStr(&mut a, "--42");
4003
            try expectNoErrors(&result);
4004
            try expectType(&a, result.root, super::Type::Int);
4005
        }
4006
    } {
4007
        let mut testArena262 = testArena();
4008
        let testStorage262: 'test262 = &mut testArena262 in {
4009
            let mut a = testResolver(testStorage262);
4010
            let result = try resolveExprStr(&mut a, "~~0xFF");
4011
            try expectNoErrors(&result);
4012
            try expectType(&a, result.root, super::Type::Int);
4013
        }
4014
    } {
4015
        let mut testArena263 = testArena();
4016
        let testStorage263: 'test263 = &mut testArena263 in {
4017
            let mut a = testResolver(testStorage263);
4018
            let result = try resolveExprStr(&mut a, "-(~42)");
4019
            try expectNoErrors(&result);
4020
            try expectType(&a, result.root, super::Type::Int);
4021
        }
4022
    }
4023
}
4024
4025
// test fn testNormalPointerArithmetic() throws (testing::TestError) {
4026
//     mut a = testResolver();
4027
//     let result = try resolveProgramStr(&mut a, "fn test() { let ptr: *i32 = undefined; let x = ptr + 1; }");
4028
//     try expectNoErrors(&result);
4029
// }
4030
4031
// Dereference tests //////////////////////////////////////////////////////////
4032
4033
@test unsafe fn testResolveDeref() throws (testing::TestError) {
4034
    {
4035
        let mut testArena264 = testArena();
4036
        let testStorage264: 'test264 = &mut testArena264 in {
4037
            let mut a = testResolver(testStorage264);
4038
            let result = try resolveBlockStr(&mut a, "static x: i32 = 42; let ptr: *i32 = &x; *ptr;");
4039
            try expectNoErrors(&result);
4040
            let stmt = try parser::tests::getBlockLastStmt(result.root);
4041
            try expectExprStmtType(&a, stmt, super::Type::I32);
4042
        }
4043
    } {
4044
        let mut testArena265 = testArena();
4045
        let testStorage265: 'test265 = &mut testArena265 in {
4046
            let mut a = testResolver(testStorage265);
4047
            let result = try resolveExprStr(&mut a, "*42");
4048
            try expectErrorKind(&result, super::ErrorKind::ExpectedPointer);
4049
        }
4050
    } {
4051
        let mut testArena266 = testArena();
4052
        let testStorage266: 'test266 = &mut testArena266 in {
4053
            let mut a = testResolver(testStorage266);
4054
            let result = try resolveBlockStr(&mut a, "let x: i32 = 5; *x;");
4055
            try expectErrorKind(&result, super::ErrorKind::ExpectedPointer);
4056
        }
4057
    }
4058
}
4059
4060
@test unsafe fn testResolveAssignDeref() throws (testing::TestError) {
4061
    {
4062
        let mut testArena267 = testArena();
4063
        let testStorage267: 'test267 = &mut testArena267 in {
4064
            let mut a = testResolver(testStorage267);
4065
            let program = "static x: i32 = 0; let ptr: *mut i32 = &mut x; set *ptr = 42;";
4066
            let result = try resolveProgramStr(&mut a, program);
4067
            try expectNoErrors(&result);
4068
        }
4069
    } {
4070
        let mut testArena268 = testArena();
4071
        let testStorage268: 'test268 = &mut testArena268 in {
4072
            let mut a = testResolver(testStorage268);
4073
            let program = "static x: i32 = 0; let ptr: *i32 = &x; set *ptr = 42;";
4074
            let result = try resolveProgramStr(&mut a, program);
4075
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4076
        }
4077
    } {
4078
        let mut testArena269 = testArena();
4079
        let testStorage269: 'test269 = &mut testArena269 in {
4080
            let mut a = testResolver(testStorage269);
4081
            let program = "static x: i32 = 0; let mut ptr: *i32 = &x; set *ptr = 42;";
4082
            let result = try resolveProgramStr(&mut a, program);
4083
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4084
        }
4085
    } {
4086
        let mut testArena270 = testArena();
4087
        let testStorage270: 'test270 = &mut testArena270 in {
4088
            let mut a = testResolver(testStorage270);
4089
            let program = "static x: u8 = 0; let mut ptr: *mut u8 = &mut x; set *ptr = 255;";
4090
            let result = try resolveProgramStr(&mut a, program);
4091
            try expectNoErrors(&result);
4092
        }
4093
    }
4094
}
4095
4096
// Type inference tests ///////////////////////////////////////////////////////
4097
4098
@test unsafe fn testResolveBasicTypeInference() throws (testing::TestError) {
4099
    {
4100
        // Boolean literals are unambiguous.
4101
        let mut testArena271 = testArena();
4102
        let testStorage271: 'test271 = &mut testArena271 in {
4103
            let mut a = testResolver(testStorage271);
4104
            let result = try resolveProgramStr(&mut a, "let x = true; x;");
4105
            try expectNoErrors(&result);
4106
4107
            let xStmt = try parser::tests::getBlockLastStmt(result.root);
4108
            try expectExprStmtType(&a, xStmt, super::Type::Bool);
4109
        }
4110
    } {
4111
        // Integer literals are ambiguous.
4112
        let mut testArena272 = testArena();
4113
        let testStorage272: 'test272 = &mut testArena272 in {
4114
            let mut a = testResolver(testStorage272);
4115
            let result = try resolveProgramStr(&mut a, "let x = 34;");
4116
            try expectErrorKind(&result, super::ErrorKind::CannotInferType);
4117
        }
4118
    }
4119
}
4120
4121
// Union tests /////////////////////////////////////////////////////////////////
4122
4123
@test unsafe fn testResolveUnionVariantWithoutPayload() throws (testing::TestError) {
4124
    let mut testArena273 = testArena();
4125
    let testStorage273: 'test273 = &mut testArena273 in {
4126
        let mut a = testResolver(testStorage273);
4127
        let program = "union Status { Ok, Error } Status::Ok;";
4128
        let result = try resolveProgramStr(&mut a, program);
4129
4130
        let ty = try getTypeInScopeOf(&a, result.root, "Status");
4131
        let case super::NominalType::Union(unionType) = *ty
4132
            else throw testing::TestError::Failed;
4133
        try testing::expect(unionType.variants.len == 2);
4134
        try testing::expect(mem::eq(unionType.variants[0].name, "Ok"));
4135
        try testing::expect(mem::eq(unionType.variants[1].name, "Error"));
4136
        if getUnionVariantPayload(ty, "Ok") <> super::Type::Void {
4137
            throw testing::TestError::Failed;
4138
        }
4139
        let stmt = try getBlockStmt(result.root, 1);
4140
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4141
        try expectNoErrors(&result);
4142
    }
4143
}
4144
4145
@test unsafe fn testResolveUnionVariantWithPayload() throws (testing::TestError) {
4146
    let mut testArena274 = testArena();
4147
    let testStorage274: 'test274 = &mut testArena274 in {
4148
        let mut a = testResolver(testStorage274);
4149
        let program = "union R { Ok(i32), Err(bool) } R::Ok(42);";
4150
        let result = try resolveProgramStr(&mut a, program);
4151
        try expectNoErrors(&result);
4152
4153
        let ty = try getTypeInScopeOf(&a, result.root, "R");
4154
4155
        let okPayload = getUnionVariantPayload(ty, "Ok");
4156
        try testing::expect(okPayload == super::Type::I32);
4157
4158
        let errPayload = getUnionVariantPayload(ty, "Err");
4159
        try testing::expect(errPayload == super::Type::Bool);
4160
4161
        let stmt = try getBlockStmt(result.root, 1);
4162
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4163
4164
        // TODO: Test payload type.
4165
    }
4166
}
4167
4168
@test unsafe fn testResolveUnionVariantWithoutPayloadExplicitDiscriminant() throws (testing::TestError) {
4169
    let mut testArena275 = testArena();
4170
    let testStorage275: 'test275 = &mut testArena275 in {
4171
        let mut a = testResolver(testStorage275);
4172
        let program = "union R { Ok = 7, Err = 11 } R::Ok;";
4173
        let result = try resolveProgramStr(&mut a, program);
4174
        try expectNoErrors(&result);
4175
4176
        let ty = try getTypeInScopeOf(&a, result.root, "R");
4177
        let stmt = try getBlockStmt(result.root, 1);
4178
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4179
    }
4180
}
4181
4182
@test unsafe fn testResolveUnionVariantPayloadTypeMismatch() throws (testing::TestError) {
4183
    let mut testArena276 = testArena();
4184
    let testStorage276: 'test276 = &mut testArena276 in {
4185
        let mut a = testResolver(testStorage276);
4186
        let program = "union R { Ok(i32), Error(bool) } R::Ok(true);";
4187
        let result = try resolveProgramStr(&mut a, program);
4188
        let err = try expectError(&result);
4189
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
4190
4191
        let ty = try getTypeInScopeOf(&a, result.root, "R");
4192
        let payload = getUnionVariantPayload(ty, "Ok");
4193
        try testing::expect(payload == super::Type::I32);
4194
4195
        let errNode = err.node
4196
            else throw testing::TestError::Failed;
4197
        let case ast::NodeValue::Bool(_) = errNode.value
4198
            else throw testing::TestError::Failed;
4199
    }
4200
}
4201
4202
@test unsafe fn testResolveUnionVariantUnexpectedPayload() throws (testing::TestError) {
4203
    let mut testArena277 = testArena();
4204
    let testStorage277: 'test277 = &mut testArena277 in {
4205
        let mut a = testResolver(testStorage277);
4206
        let program = "union Status { Ok, Error } Status::Ok(42);";
4207
        let result = try resolveProgramStr(&mut a, program);
4208
        let err = try expectError(&result);
4209
4210
        let case super::ErrorKind::UnionVariantPayloadUnexpected(_) = err.kind
4211
            else throw testing::TestError::Failed;
4212
        let node = err.node
4213
            else throw testing::TestError::Failed;
4214
        let case ast::NodeValue::Call(_) = node.value
4215
            else throw testing::TestError::Failed;
4216
    }
4217
}
4218
4219
@test unsafe fn testResolveUnionVariantUnknown() throws (testing::TestError) {
4220
    let mut testArena278 = testArena();
4221
    let testStorage278: 'test278 = &mut testArena278 in {
4222
        let mut a = testResolver(testStorage278);
4223
        let program = "union Status { Ok, Error } Status::Unknown;";
4224
        let result = try resolveProgramStr(&mut a, program);
4225
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
4226
    }
4227
}
4228
4229
@test unsafe fn testResolveScopeAccessUndefinedType() throws (testing::TestError) {
4230
    let mut testArena279 = testArena();
4231
    let testStorage279: 'test279 = &mut testArena279 in {
4232
        let mut a = testResolver(testStorage279);
4233
        let result = try resolveProgramStr(&mut a, "Unknown::X;");
4234
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
4235
    }
4236
}
4237
4238
@test unsafe fn testResolveUnionVariantVoidPayload() throws (testing::TestError) {
4239
    let mut testArena280 = testArena();
4240
    let testStorage280: 'test280 = &mut testArena280 in {
4241
        let mut a = testResolver(testStorage280);
4242
        let program = "union R { Success(i32), Pending } R::Pending;";
4243
        let result = try resolveProgramStr(&mut a, program);
4244
        try expectNoErrors(&result);
4245
4246
        let ty = try getTypeInScopeOf(&a, result.root, "R");
4247
        let payload = getUnionVariantPayload(ty, "Pending");
4248
        try testing::expect(payload == super::Type::Void);
4249
4250
        let stmt = try getBlockStmt(result.root, 1);
4251
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4252
    }
4253
}
4254
4255
@test unsafe fn testResolveUnionVariantRecordPayload() throws (testing::TestError) {
4256
    let mut testArena281 = testArena();
4257
    let testStorage281: 'test281 = &mut testArena281 in {
4258
        let mut a = testResolver(testStorage281);
4259
        let program = "record P { x: i32, y: i32 } union S { Point(P), Num(u32) } S::Point(P { x: 10, y: 20 });";
4260
        let result = try resolveProgramStr(&mut a, program);
4261
        try expectNoErrors(&result);
4262
4263
        let ty = try getTypeInScopeOf(&a, result.root, "S");
4264
        let stmt = try getBlockStmt(result.root, 2);
4265
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
4266
    }
4267
}
4268
4269
@test unsafe fn testResolveBuiltinSizeOf() throws (testing::TestError) {
4270
    try resolveAndExpectConstExpr("@sizeOf(u8)", 1);
4271
    try resolveAndExpectConstExpr("@sizeOf(u16)", 2);
4272
    try resolveAndExpectConstExpr("@sizeOf(u32)", 4);
4273
    try resolveAndExpectConstExpr("@sizeOf(i32)", 4);
4274
    try resolveAndExpectConstExpr("@sizeOf(bool)", 1);
4275
    try resolveAndExpectConstExpr("@sizeOf(*u32)", 8);
4276
    try resolveAndExpectConstExpr("@sizeOf([u8; 10])", 10);
4277
    try resolveAndExpectConstExpr("@sizeOf(*[u32])", 16);
4278
    try resolveAndExpectConstExpr("@sizeOf(?u8)", 2);
4279
    try resolveAndExpectConstExpr("@sizeOf(?u16)", 4);
4280
    try resolveAndExpectConstExpr("@sizeOf(?u32)", 8);
4281
    try resolveAndExpectConstExpr("@sizeOf(*opaque)", 8);
4282
    try resolveAndExpectConstStmt("record T { x: u8 } @sizeOf(T);", 1);
4283
    try resolveAndExpectConstStmt("record T { x: i32 } @sizeOf(T);", 4);
4284
    try resolveAndExpectConstStmt("record T { x: i32, y: i8 } @sizeOf(T);", 8);
4285
    try resolveAndExpectConstStmt("record T { x: i8, y: i32 } @sizeOf(T);", 8);
4286
    try resolveAndExpectConstStmt("record T { x: i8, y: i32 } @sizeOf(T);", 8);
4287
    try resolveAndExpectConstStmt("record T { x: u32, y: u8, z: u8 }; @sizeOf(T);", 8);
4288
    try resolveAndExpectConstStmt("record T { x: u8, y: u32, z: u8 }; @sizeOf(T);", 12);
4289
    try resolveAndExpectConstStmt("union T { A, B, C }; @sizeOf(T);", 1);
4290
    try resolveAndExpectConstStmt("union T { A, B(u32), C }; @sizeOf(T);", 8);
4291
    try resolveAndExpectConstStmt("union T { A, B(u16), C }; @sizeOf(T);", 4);
4292
    try resolveAndExpectConstStmt("union T { A(u32), B(u16), C(u16) }; @sizeOf(T);", 8);
4293
    try resolveAndExpectConstStmt("union T { A(u32), B(u16), C([u8; 16]) }; @sizeOf(T);", 20);
4294
}
4295
4296
@test unsafe fn testResolveBuiltinAlignOf() throws (testing::TestError) {
4297
    try resolveAndExpectConstExpr("@alignOf(u8)", 1);
4298
    try resolveAndExpectConstExpr("@alignOf(u16)", 2);
4299
    try resolveAndExpectConstExpr("@alignOf(u32)", 4);
4300
    try resolveAndExpectConstExpr("@alignOf(i32)", 4);
4301
    try resolveAndExpectConstExpr("@alignOf(bool)", 1);
4302
    try resolveAndExpectConstExpr("@alignOf(*u8)", 8);
4303
    try resolveAndExpectConstExpr("@alignOf(*u16)", 8);
4304
    try resolveAndExpectConstExpr("@alignOf(*u32)", 8);
4305
    try resolveAndExpectConstExpr("@alignOf(*opaque)", 8);
4306
    try resolveAndExpectConstExpr("@alignOf([u8; 8])", 1);
4307
    try resolveAndExpectConstExpr("@alignOf([u16; 8])", 2);
4308
    try resolveAndExpectConstExpr("@alignOf([u32; 8])", 4);
4309
    try resolveAndExpectConstExpr("@alignOf(*[u32])", 8);
4310
    try resolveAndExpectConstExpr("@alignOf(?u8)", 1);
4311
    try resolveAndExpectConstExpr("@alignOf(?u16)", 2);
4312
    try resolveAndExpectConstExpr("@alignOf(?u32)", 4);
4313
    try resolveAndExpectConstStmt("record T { x: u8, y: u16 }; @alignOf(T);", 2);
4314
    try resolveAndExpectConstStmt("record T { x: u8, y: u32, z: u8 }; @alignOf(T);", 4);
4315
    try resolveAndExpectConstStmt("record T { x: u32, y: u8, z: u8 }; @alignOf(T);", 4);
4316
    try resolveAndExpectConstStmt("union T { A, B, C }; @alignOf(T);", 1);
4317
    try resolveAndExpectConstStmt("union T { A, B(u32), C }; @alignOf(T);", 4);
4318
}
4319
4320
@test unsafe fn testResolveBuiltinSizeOfRecord() throws (testing::TestError) {
4321
    let mut testArena282 = testArena();
4322
    let testStorage282: 'test282 = &mut testArena282 in {
4323
        let mut a = testResolver(testStorage282);
4324
        let program = "record T { x: u8, y: u32 } @sizeOf(T);";
4325
        let result = try resolveProgramStr(&mut a, program);
4326
        try expectNoErrors(&result);
4327
4328
        let stmt = try getBlockStmt(result.root, 1);
4329
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
4330
        try expectConstInt(&a, expr, 8);
4331
    }
4332
}
4333
4334
@test unsafe fn testResolveBuiltinSizeOfUnion() throws (testing::TestError) {
4335
    let mut testArena283 = testArena();
4336
    let testStorage283: 'test283 = &mut testArena283 in {
4337
        let mut a = testResolver(testStorage283);
4338
        let program = "union Result { Ok(u32), Err(u8) } @sizeOf(Result);";
4339
        let result = try resolveProgramStr(&mut a, program);
4340
        try expectNoErrors(&result);
4341
4342
        let stmt = try getBlockStmt(result.root, 1);
4343
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
4344
        try expectConstInt(&a, expr, 8);
4345
    }
4346
}
4347
4348
@test unsafe fn testResolveAlignAnnotation() throws (testing::TestError) {
4349
    {
4350
        let mut testArena284 = testArena();
4351
        let testStorage284: 'test284 = &mut testArena284 in {
4352
            let mut a = testResolver(testStorage284);
4353
            let result = try resolveBlockStr(&mut a, "let x: u8 align(8) = 0;");
4354
            try expectNoErrors(&result);
4355
4356
            let stmt = try getBlockStmt(result.root, 0);
4357
            let sym = super::symbolFor(&a, stmt)
4358
                else throw testing::TestError::Failed;
4359
            let case super::SymbolData::Value { type: valType, .. } = sym.data
4360
                else throw testing::TestError::Failed;
4361
            let layout = super::getLayout(&a, sym.node, valType);
4362
            try testing::expect(layout.alignment == 8);
4363
        }
4364
    } {
4365
        let mut testArena285 = testArena();
4366
        let testStorage285: 'test285 = &mut testArena285 in {
4367
            let mut a = testResolver(testStorage285);
4368
            let result = try resolveProgramStr(&mut a, "let x: u32 align(3) = 0;");
4369
            let err = try expectError(&result);
4370
            let case super::ErrorKind::InvalidAlignmentValue(val) = err.kind
4371
                else throw testing::TestError::Failed;
4372
            try testing::expect(val == 3);
4373
        }
4374
    } {
4375
        let mut testArena286 = testArena();
4376
        let testStorage286: 'test286 = &mut testArena286 in {
4377
            let mut a = testResolver(testStorage286);
4378
            let result = try resolveProgramStr(&mut a, "let x: u32 align(7) = 0;");
4379
            let err = try expectError(&result);
4380
            let case super::ErrorKind::InvalidAlignmentValue(val) = err.kind
4381
                else throw testing::TestError::Failed;
4382
            try testing::expect(val == 7);
4383
        }
4384
    }
4385
}
4386
4387
@test unsafe fn testResolveVoidAssignmentError() throws (testing::TestError) {
4388
    {
4389
        let mut testArena287 = testArena();
4390
        let testStorage287: 'test287 = &mut testArena287 in {
4391
            let mut a = testResolver(testStorage287);
4392
            let program = "fn voidFn() {} let _ = voidFn();";
4393
            let result = try resolveProgramStr(&mut a, program);
4394
            try expectErrorKind(&result, super::ErrorKind::CannotAssignVoid);
4395
        }
4396
    } {
4397
        let mut testArena288 = testArena();
4398
        let testStorage288: 'test288 = &mut testArena288 in {
4399
            let mut a = testResolver(testStorage288);
4400
            let program = "fn voidFn() {} let x = voidFn();";
4401
            let result = try resolveProgramStr(&mut a, program);
4402
            try expectErrorKind(&result, super::ErrorKind::CannotAssignVoid);
4403
        }
4404
    }
4405
}
4406
4407
//
4408
// Module Declaration Tests
4409
//
4410
4411
@test unsafe fn testResolveEmptyMod() throws (testing::TestError) {
4412
    let mut testArena289 = testArena();
4413
    let testStorage289: 'test289 = &mut testArena289 in {
4414
        let mut a = testResolver(testStorage289);
4415
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4416
        let mut graph = &mut MODULE_GRAPH;
4417
4418
        let rootId = try registerModule(graph, nil, "root", "mod child;", &mut arena);
4419
        let childId = try registerModule(graph, rootId, "child", "{}", &mut arena);
4420
        let result = try resolveModuleTree(&mut a, rootId);
4421
        try expectNoErrors(&result);
4422
    }
4423
}
4424
4425
@test unsafe fn testResolveModuleCannotAccessParentScope() throws (testing::TestError) {
4426
    let mut testArena290 = testArena();
4427
    let testStorage290: 'test290 = &mut testArena290 in {
4428
        let mut a = testResolver(testStorage290);
4429
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4430
4431
        // Register root and util modules.
4432
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod util; export fn helper() {}", &mut arena);
4433
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "fn main() { helper(); }", &mut arena);
4434
4435
        // Resolve should fail: the parent module is not in scope.
4436
        let result = try resolveModuleTree(&mut a, rootId);
4437
        let err = try expectError(&result);
4438
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4439
            else throw testing::TestError::Failed;
4440
        try testing::expect(mem::eq(name, "helper"));
4441
    }
4442
}
4443
4444
@test unsafe fn testResolveModuleAccessPrivateSubModule() throws (testing::TestError) {
4445
    let mut testArena291 = testArena();
4446
    let testStorage291: 'test291 = &mut testArena291 in {
4447
        let mut a = testResolver(testStorage291);
4448
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4449
4450
        // Register root and util modules.
4451
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod util; fn main() { util::helper(); }", &mut arena);
4452
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "export fn helper() {}", &mut arena);
4453
4454
        // Resolve should succeed: parent can access child.
4455
        let result = try resolveModuleTree(&mut a, rootId);
4456
        try expectNoErrors(&result);
4457
    }
4458
}
4459
4460
@test unsafe fn testResolveSiblingModulesCannotAccessDirectly() throws (testing::TestError) {
4461
    let mut testArena292 = testArena();
4462
    let testStorage292: 'test292 = &mut testArena292 in {
4463
        let mut a = testResolver(testStorage292);
4464
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4465
4466
        // Register root with two sibling modules.
4467
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod paul; export mod patrick;", &mut arena);
4468
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "paul", "fn main() { patrick::helper(); }", &mut arena);
4469
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "patrick", "export fn helper() -> i32 { return 42; }", &mut arena);
4470
4471
        // Resolve should fail: siblings can't access each other directly.
4472
        let result = try resolveModuleTree(&mut a, rootId);
4473
        let err = try expectError(&result);
4474
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4475
            else throw testing::TestError::Failed;
4476
        try testing::expect(mem::eq(name, "patrick"));
4477
    }
4478
}
4479
4480
@test unsafe fn testResolveSiblingModulesViaRoot() throws (testing::TestError) {
4481
    let mut testArena293 = testArena();
4482
    let testStorage293: 'test293 = &mut testArena293 in {
4483
        let mut a = testResolver(testStorage293);
4484
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4485
4486
        // Register root with two sibling modules.
4487
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod paul; export mod patrick;", &mut arena);
4488
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "paul", "use root::patrick; fn main() -> i32 { return patrick::helper(); }", &mut arena);
4489
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "patrick", "export fn helper() -> i32 { return 42; }", &mut arena);
4490
4491
        // Resolve should succeed: siblings can access each other via root.
4492
        let result = try resolveModuleTree(&mut a, rootId);
4493
        try expectNoErrors(&result);
4494
    }
4495
}
4496
4497
@test unsafe fn testResolveModuleMutualRecursion() throws (testing::TestError) {
4498
    let mut testArena294 = testArena();
4499
    let testStorage294: 'test294 = &mut testArena294 in {
4500
        let mut a = testResolver(testStorage294);
4501
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4502
4503
        // Register root with two sibling modules that call each other.
4504
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod left; export mod right;", &mut arena);
4505
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "left", "use root::right; export fn leftHelper() -> i32 { return right::rightHelper(); }", &mut arena);
4506
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "right", "use root::left; export fn rightHelper() -> i32 { return left::leftHelper(); }", &mut arena);
4507
4508
        // Resolve should succeed: cyclic use is allowed.
4509
        let result = try resolveModuleTree(&mut a, rootId);
4510
        try expectNoErrors(&result);
4511
    }
4512
}
4513
4514
@test unsafe fn testResolveAccessModuleType() throws (testing::TestError) {
4515
    let mut testArena295 = testArena();
4516
    let testStorage295: 'test295 = &mut testArena295 in {
4517
        let mut a = testResolver(testStorage295);
4518
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4519
4520
        // Register root with types module containing a record.
4521
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4522
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Point { x: i32, y: i32 }", &mut arena);
4523
        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);
4524
4525
        // Resolve should succeed: types can be accessed.
4526
        let result = try resolveModuleTree(&mut a, rootId);
4527
        try expectNoErrors(&result);
4528
    }
4529
}
4530
4531
@test unsafe fn testResolveAccessModuleConstant() throws (testing::TestError) {
4532
    let mut testArena296 = testArena();
4533
    let testStorage296: 'test296 = &mut testArena296 in {
4534
        let mut a = testResolver(testStorage296);
4535
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4536
4537
        // Register root with constants module.
4538
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
4539
        let constantsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant MAX_SIZE: i32 = 100;", &mut arena);
4540
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() -> i32 { return consts::MAX_SIZE; }", &mut arena);
4541
4542
        // Resolve should succeed: constants can be accessed.
4543
        let result = try resolveModuleTree(&mut a, rootId);
4544
        try expectNoErrors(&result);
4545
    }
4546
}
4547
4548
@test unsafe fn testResolveRootSymbolMustBeImported() throws (testing::TestError) {
4549
    let mut testArena297 = testArena();
4550
    let testStorage297: 'test297 = &mut testArena297 in {
4551
        let mut a = testResolver(testStorage297);
4552
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4553
4554
        // Register deeply nested modules: `root::app::services::auth`.
4555
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; export fn helper() -> i32 { return 42; }", &mut arena);
4556
        let mainId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "fn run() -> i32 { return root::helper(); }", &mut arena);
4557
4558
        // Resolve should fail: the `root` module must be imported.
4559
        let result = try resolveModuleTree(&mut a, rootId);
4560
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("root"));
4561
    }
4562
}
4563
4564
@test unsafe fn testResolveUseImportsNestedSymbol() throws (testing::TestError) {
4565
    let mut testArena298 = testArena();
4566
    let testStorage298: 'test298 = &mut testArena298 in {
4567
        let mut a = testResolver(testStorage298);
4568
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4569
4570
        // Register deeply nested modules: `root::app::services::auth`.
4571
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod app; mod main;", &mut arena);
4572
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "export mod services;", &mut arena);
4573
        let servicesId = try registerModule(&mut MODULE_GRAPH, appId, "services", "export mod auth;", &mut arena);
4574
        let authId = try registerModule(&mut MODULE_GRAPH, servicesId, "auth", "export fn login() -> i32 { return 1; }", &mut arena);
4575
        let mainId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::app::services::auth; fn run() -> i32 { return auth::login(); }", &mut arena);
4576
        let otherId = try registerModule(&mut MODULE_GRAPH, rootId, "other", "use root; fn run() -> i32 { return root::app::services::auth::login(); }", &mut arena);
4577
4578
        // Resolve should succeed: use imports the module symbol.
4579
        let result = try resolveModuleTree(&mut a, rootId);
4580
        try expectNoErrors(&result);
4581
    }
4582
}
4583
4584
@test unsafe fn testResolveUseNonExistentModule() throws (testing::TestError) {
4585
    let mut testArena299 = testArena();
4586
    let testStorage299: 'test299 = &mut testArena299 in {
4587
        let mut a = testResolver(testStorage299);
4588
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4589
4590
        // Register root with app trying to use a non-existent module.
4591
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod app;", &mut arena);
4592
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::unknown;", &mut arena);
4593
4594
        // Resolve should fail: module doesn't exist.
4595
        let result = try resolveModuleTree(&mut a, rootId);
4596
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("unknown"));
4597
    }
4598
}
4599
4600
@test unsafe fn testResolveUsePrivateFn() throws (testing::TestError) {
4601
    let mut testArena300 = testArena();
4602
    let testStorage300: 'test300 = &mut testArena300 in {
4603
        let mut a = testResolver(testStorage300);
4604
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4605
4606
        // Register root with util module containing a private function.
4607
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod util; mod app;", &mut arena);
4608
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "fn private() -> i32 { return 42; }", &mut arena);
4609
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::util; fn main() -> i32 { return util::private(); }", &mut arena);
4610
4611
        // Resolve should fail: function is not public.
4612
        let result = try resolveModuleTree(&mut a, rootId);
4613
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
4614
    }
4615
}
4616
4617
@test unsafe fn testResolveUsePrivateMod() throws (testing::TestError) {
4618
    let mut testArena301 = testArena();
4619
    let testStorage301: 'test301 = &mut testArena301 in {
4620
        let mut a = testResolver(testStorage301);
4621
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4622
4623
        // Register root with public and private child modules.
4624
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; mod private;", &mut arena);
4625
        let privateId = try registerModule(&mut MODULE_GRAPH, rootId, "private", "{}", &mut arena);
4626
        let publicId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::private;", &mut arena);
4627
4628
        // Resolve should fail: module is not public.
4629
        let result = try resolveModuleTree(&mut a, rootId);
4630
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
4631
    }
4632
}
4633
4634
@test unsafe fn testResolveUsePublicMod() throws (testing::TestError) {
4635
    let mut testArena302 = testArena();
4636
    let testStorage302: 'test302 = &mut testArena302 in {
4637
        let mut a = testResolver(testStorage302);
4638
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4639
4640
        // Register root with public and private child modules.
4641
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; export mod public;", &mut arena);
4642
        let privateId = try registerModule(&mut MODULE_GRAPH, rootId, "public", "{}", &mut arena);
4643
        let publicId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::public;", &mut arena);
4644
4645
        // Resolve should succeed: module is public.
4646
        let result = try resolveModuleTree(&mut a, rootId);
4647
        try expectNoErrors(&result);
4648
    }
4649
}
4650
4651
@test unsafe fn testResolveUseNonPublicType() throws (testing::TestError) {
4652
    let mut testArena303 = testArena();
4653
    let testStorage303: 'test303 = &mut testArena303 in {
4654
        let mut a = testResolver(testStorage303);
4655
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4656
4657
        // Register root with types module containing a private record.
4658
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4659
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "record Priv { x: i32 }", &mut arena);
4660
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> types::Priv { return types::Priv { x: 1 }; }", &mut arena);
4661
4662
        // Resolve should fail: record is not public.
4663
        let result = try resolveModuleTree(&mut a, rootId);
4664
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Priv"));
4665
    }
4666
}
4667
4668
@test unsafe fn testResolveImportPublicType() throws (testing::TestError) {
4669
    let mut testArena304 = testArena();
4670
    let testStorage304: 'test304 = &mut testArena304 in {
4671
        let mut a = testResolver(testStorage304);
4672
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4673
4674
        // Register root with types module containing a public record.
4675
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4676
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Pub { x: i32 }", &mut arena);
4677
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> types::Pub { return types::Pub { x: 1 }; }", &mut arena);
4678
4679
        // Resolve should succeed: record is public.
4680
        let result = try resolveModuleTree(&mut a, rootId);
4681
        try expectNoErrors(&result);
4682
    }
4683
}
4684
4685
@test unsafe fn testResolveUseNonPublicStatic() throws (testing::TestError) {
4686
    let mut testArena305 = testArena();
4687
    let testStorage305: 'test305 = &mut testArena305 in {
4688
        let mut a = testResolver(testStorage305);
4689
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4690
4691
        // Register root with statics module containing a private static.
4692
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
4693
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "static PRIVATE: i32 = 42;", &mut arena);
4694
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() -> i32 { return statics::PRIVATE; }", &mut arena);
4695
4696
        // Resolve should fail: static is not public.
4697
        let result = try resolveModuleTree(&mut a, rootId);
4698
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("PRIVATE"));
4699
    }
4700
}
4701
4702
@test unsafe fn testResolveImportPublicStatic() throws (testing::TestError) {
4703
    let mut testArena306 = testArena();
4704
    let testStorage306: 'test306 = &mut testArena306 in {
4705
        let mut a = testResolver(testStorage306);
4706
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4707
4708
        // Register root with statics module containing a public static.
4709
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
4710
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "export static PUBLIC: i32 = 42;", &mut arena);
4711
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() -> i32 { return statics::PUBLIC; }", &mut arena);
4712
4713
        // Resolve should succeed: static is public.
4714
        let result = try resolveModuleTree(&mut a, rootId);
4715
        try expectNoErrors(&result);
4716
    }
4717
}
4718
4719
@test unsafe fn testResolveAccessSuper() throws (testing::TestError) {
4720
    {
4721
        let mut testArena307 = testArena();
4722
        let testStorage307: 'test307 = &mut testArena307 in {
4723
            let mut a = testResolver(testStorage307);
4724
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4725
4726
            // Test function access.
4727
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; export fn parentFn() -> i32 { return 42; }", &mut arena);
4728
            let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "fn main() -> i32 { return super::parentFn(); }", &mut arena);
4729
            let result = try resolveModuleTree(&mut a, rootId);
4730
            try expectNoErrors(&result);
4731
        }
4732
    } {
4733
        let mut testArena308 = testArena();
4734
        let testStorage308: 'test308 = &mut testArena308 in {
4735
            let mut a = testResolver(testStorage308);
4736
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4737
4738
            // Test type access.
4739
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; export record Point { x: i32, y: i32 }", &mut arena);
4740
            let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "fn make() -> super::Point { return super::Point { x: 1, y: 2 }; }", &mut arena);
4741
            let result = try resolveModuleTree(&mut a, rootId);
4742
            try expectNoErrors(&result);
4743
        }
4744
    }
4745
}
4746
4747
/// Test nested super access to union variants (e.g. `super::E::A`).
4748
@test unsafe fn testResolveSuperUnionVariant() throws (testing::TestError) {
4749
    let mut testArena309 = testArena();
4750
    let testStorage309: 'test309 = &mut testArena309 in {
4751
        let mut a = testResolver(testStorage309);
4752
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4753
4754
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod c; export union E { A, B }", &mut arena);
4755
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "c",
4756
            "fn f(x: super::E) { match x { case super::E::A => {}, case super::E::B => {} } }",
4757
            &mut arena);
4758
        let result = try resolveModuleTree(&mut a, rootId);
4759
        try expectNoErrors(&result);
4760
    }
4761
}
4762
4763
@test unsafe fn testResolveUseSuper() throws (testing::TestError) {
4764
    let mut testArena310 = testArena();
4765
    let testStorage310: 'test310 = &mut testArena310 in {
4766
        let mut a = testResolver(testStorage310);
4767
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4768
4769
        // Register root with a function, and a child module that uses super to access it.
4770
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod joe; export mod kate;", &mut arena);
4771
        let kateId = try registerModule(&mut MODULE_GRAPH, rootId, "kate", "export fn run() {}", &mut arena);
4772
        let joeId = try registerModule(&mut MODULE_GRAPH, rootId, "joe", "use super::kate; fn main() { kate::run(); }", &mut arena);
4773
4774
        // Resolve should succeed - super allows accessing parent module.
4775
        let result = try resolveModuleTree(&mut a, rootId);
4776
        try expectNoErrors(&result);
4777
    }
4778
}
4779
4780
@test unsafe fn testResolveModNotFound() throws (testing::TestError) {
4781
    let mut testArena311 = testArena();
4782
    let testStorage311: 'test311 = &mut testArena311 in {
4783
        let mut a = testResolver(testStorage311);
4784
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4785
4786
        // Register root that declares a module that doesn't exist.
4787
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod unknown;", &mut arena);
4788
4789
        // Resolve should fail: module doesn't exist.
4790
        let result = try resolveModuleTree(&mut a, rootId);
4791
        let err = try expectError(&result);
4792
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4793
            else throw testing::TestError::Failed;
4794
        try testing::expect(mem::eq(name, "unknown"));
4795
    }
4796
}
4797
4798
@test unsafe fn testResolveDuplicateSubModule() throws (testing::TestError) {
4799
    let mut testArena312 = testArena();
4800
    let testStorage312: 'test312 = &mut testArena312 in {
4801
        let mut a = testResolver(testStorage312);
4802
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4803
4804
        // Register root that declares a module twice.
4805
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; mod child;", &mut arena);
4806
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "{}", &mut arena);
4807
4808
        // Resolve should fail: can't declare the same module twice.
4809
        let result = try resolveModuleTree(&mut a, rootId);
4810
        let err = try expectError(&result);
4811
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("child"));
4812
    }
4813
}
4814
4815
@test unsafe fn testResolveUseSubModule() throws (testing::TestError) {
4816
    let mut testArena313 = testArena();
4817
    let testStorage313: 'test313 = &mut testArena313 in {
4818
        let mut a = testResolver(testStorage313);
4819
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4820
4821
        // Register root that declares and imports the same module.
4822
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; use child;", &mut arena);
4823
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "{}", &mut arena);
4824
4825
        // Resolve should fail: Both `mod` and `use` are trying to create the same binding.
4826
        let result = try resolveModuleTree(&mut a, rootId);
4827
        let err = try expectError(&result);
4828
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("child"));
4829
    }
4830
}
4831
4832
@test unsafe fn testResolveDuplicateUse() throws (testing::TestError) {
4833
    let mut testArena314 = testArena();
4834
    let testStorage314: 'test314 = &mut testArena314 in {
4835
        let mut a = testResolver(testStorage314);
4836
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4837
4838
        // Register a module that imports the same module twice.
4839
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child", &mut arena);
4840
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "use root; use root;", &mut arena);
4841
4842
        // Resolve should fail.
4843
        let result = try resolveModuleTree(&mut a, rootId);
4844
        let err = try expectError(&result);
4845
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("root"));
4846
    }
4847
}
4848
4849
/// Test that opaque pointers are allowed in record fields.
4850
@test unsafe fn testOpaquePointerInRecordField() throws (testing::TestError) {
4851
    let mut testArena315 = testArena();
4852
    let testStorage315: 'test315 = &mut testArena315 in {
4853
        let mut a = testResolver(testStorage315);
4854
        let result = try resolveProgramStr(&mut a, "record T { x: *opaque }");
4855
        try expectNoErrors(&result);
4856
    }
4857
}
4858
4859
/// You cannot use `@sizeOf` or `@alignOf` on opaque type.
4860
@test unsafe fn testOpaqueTypeNoSizeOfAlignOf() throws (testing::TestError) {
4861
    let mut testArena316 = testArena();
4862
    let testStorage316: 'test316 = &mut testArena316 in {
4863
        let mut a = testResolver(testStorage316);
4864
4865
        let result1 = try resolveExprStr(&mut a, "@sizeOf(opaque)");
4866
        let err1 = try expectError(&result1);
4867
        try expectErrorKind(&result1, super::ErrorKind::OpaqueTypeNotAllowed);
4868
4869
        let result2 = try resolveExprStr(&mut a, "@alignOf(opaque)");
4870
        let err2 = try expectError(&result2);
4871
        try expectErrorKind(&result2, super::ErrorKind::OpaqueTypeNotAllowed);
4872
    }
4873
}
4874
4875
/// Test that immutable slice/pointer parameters cannot be borrowed mutably.
4876
@test unsafe fn testMutableBorrowFromImmutablePointer() throws (testing::TestError) {
4877
    let mut testArena317 = testArena();
4878
    let testStorage317: 'test317 = &mut testArena317 in {
4879
        let mut a = testResolver(testStorage317);
4880
        let program = "fn f(p: *i32) { let x = &mut *p; }";
4881
        let result = try resolveProgramStr(&mut a, program);
4882
        let err = try expectError(&result);
4883
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4884
    }
4885
}
4886
4887
/// Test that immutable slice parameters cannot be borrowed mutably.
4888
@test unsafe fn testMutableBorrowFromImmutableSlice() throws (testing::TestError) {
4889
    let mut testArena318 = testArena();
4890
    let testStorage318: 'test318 = &mut testArena318 in {
4891
        let mut a = testResolver(testStorage318);
4892
        let program = "fn f(s: *[i32]) { let x: *mut i32 = &mut s[0]; }";
4893
        let result = try resolveProgramStr(&mut a, program);
4894
        let err = try expectError(&result);
4895
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4896
    }
4897
}
4898
4899
/// Test that mutable pointer parameters can be borrowed mutably.
4900
@test unsafe fn testMutableBorrowFromMutablePointer() throws (testing::TestError) {
4901
    let mut testArena319 = testArena();
4902
    let testStorage319: 'test319 = &mut testArena319 in {
4903
        let mut a = testResolver(testStorage319);
4904
        let program = "fn f(p: *mut i32) { let x: *mut i32 = &mut *p; }";
4905
        let result = try resolveProgramStr(&mut a, program);
4906
        try expectNoErrors(&result);
4907
    }
4908
}
4909
4910
/// Test that mutable slice parameters can be borrowed mutably.
4911
@test unsafe fn testMutableBorrowFromMutableSlice() throws (testing::TestError) {
4912
    let mut testArena320 = testArena();
4913
    let testStorage320: 'test320 = &mut testArena320 in {
4914
        let mut a = testResolver(testStorage320);
4915
        let program = "fn f(s: *mut [i32]) { let x: *mut i32 = &mut s[0]; }";
4916
        let result = try resolveProgramStr(&mut a, program);
4917
        try expectNoErrors(&result);
4918
    }
4919
}
4920
4921
/// Test borrowing mutably from a field access on a call returning `*mut`.
4922
@test unsafe fn testMutableBorrowFromCallReturningMutablePointer() throws (testing::TestError) {
4923
    let mut testArena321 = testArena();
4924
    let testStorage321: 'test321 = &mut testArena321 in {
4925
        let mut a = testResolver(testStorage321);
4926
        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; }";
4927
        let result = try resolveProgramStr(&mut a, program);
4928
        try expectNoErrors(&result);
4929
    }
4930
}
4931
4932
/// Test that calls returning immutable pointers cannot be mutably borrowed.
4933
@test unsafe fn testMutableBorrowFromCallReturningImmutablePointer() throws (testing::TestError) {
4934
    let mut testArena322 = testArena();
4935
    let testStorage322: 'test322 = &mut testArena322 in {
4936
        let mut a = testResolver(testStorage322);
4937
        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; }";
4938
        let result = try resolveProgramStr(&mut a, program);
4939
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4940
    }
4941
}
4942
4943
/// Test borrowing mutably from a public static through scope access.
4944
@test unsafe fn testMutableBorrowFromScopeAccessStatic() throws (testing::TestError) {
4945
    let mut testArena323 = testArena();
4946
    let testStorage323: 'test323 = &mut testArena323 in {
4947
        let mut a = testResolver(testStorage323);
4948
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4949
4950
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
4951
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "export static COUNTER: i32 = 0;", &mut arena);
4952
        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);
4953
4954
        let result = try resolveModuleTree(&mut a, rootId);
4955
        try expectNoErrors(&result);
4956
    }
4957
}
4958
4959
/// Test that constants through scope access cannot be mutably borrowed.
4960
@test unsafe fn testMutableBorrowFromScopeAccessConstant() throws (testing::TestError) {
4961
    let mut testArena324 = testArena();
4962
    let testStorage324: 'test324 = &mut testArena324 in {
4963
        let mut a = testResolver(testStorage324);
4964
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4965
4966
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
4967
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant LIMIT: i32 = 7;", &mut arena);
4968
        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);
4969
4970
        let result = try resolveModuleTree(&mut a, rootId);
4971
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4972
    }
4973
}
4974
4975
/// Test that mutable bindings of immutable pointers cannot borrow mutably through the pointer.
4976
@test unsafe fn testMutableBorrowFromMutableBindingOfPointer() throws (testing::TestError) {
4977
    let mut testArena325 = testArena();
4978
    let testStorage325: 'test325 = &mut testArena325 in {
4979
        let mut a = testResolver(testStorage325);
4980
        let program = "fn f() { static x: i32 = 1; let p: *i32 = &x; let y = &mut *p; }";
4981
        let result = try resolveProgramStr(&mut a, program);
4982
        let err = try expectError(&result);
4983
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4984
    }
4985
}
4986
4987
/// Test that mutable pointer to immutable slice cannot be assigned through index.
4988
/// This tests the case where we have `*mut *[T]`; the outer pointer is mutable but
4989
/// the inner slice is immutable, so we shouldn't be able to mutate the elements.
4990
@test unsafe fn testAssignThroughMutablePointerToImmutableSlice() throws (testing::TestError) {
4991
    let mut testArena326 = testArena();
4992
    let testStorage326: 'test326 = &mut testArena326 in {
4993
        let mut a = testResolver(testStorage326);
4994
        let program = "fn f(slice: *[i32]) { let p: *mut *[i32] = &mut slice; set p[0] = 1; }";
4995
        let result = try resolveProgramStr(&mut a, program);
4996
4997
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4998
    }
4999
}
5000
5001
/// Test that mutable slice parameters can be assigned through index.
5002
@test unsafe fn testAssignThroughMutableSliceParam() throws (testing::TestError) {
5003
    {
5004
        // Mutable slice param: direct assignment should work
5005
        let mut testArena327 = testArena();
5006
        let testStorage327: 'test327 = &mut testArena327 in {
5007
            let mut a = testResolver(testStorage327);
5008
            let program = "fn f(slice: *mut [i32]) { set slice[0] = 1; }";
5009
            let result = try resolveProgramStr(&mut a, program);
5010
            try expectNoErrors(&result);
5011
        }
5012
    } {
5013
        // Immutable slice param: direct assignment should fail
5014
        let mut testArena328 = testArena();
5015
        let testStorage328: 'test328 = &mut testArena328 in {
5016
            let mut a = testResolver(testStorage328);
5017
            let program = "fn f(slice: *[i32]) { set slice[0] = 1; }";
5018
            let result = try resolveProgramStr(&mut a, program);
5019
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5020
        }
5021
    }
5022
}
5023
5024
/// Test range end type coercion with assignable types.
5025
@test unsafe fn testRangeEndTypeCoercion() throws (testing::TestError) {
5026
    {
5027
        let mut testArena329 = testArena();
5028
        let testStorage329: 'test329 = &mut testArena329 in {
5029
            let mut a = testResolver(testStorage329);
5030
            let program = "fn f(end: u32) { for i in 0..end {} }";
5031
            let result = try resolveProgramStr(&mut a, program);
5032
            try expectNoErrors(&result);
5033
        }
5034
    } {
5035
        let mut testArena330 = testArena();
5036
        let testStorage330: 'test330 = &mut testArena330 in {
5037
            let mut a = testResolver(testStorage330);
5038
            let program = "fn f(start: u32) { for i in start..9 {} }";
5039
            let result = try resolveProgramStr(&mut a, program);
5040
            try expectNoErrors(&result);
5041
        }
5042
    }
5043
}
5044
5045
/// Mixed-width range bounds require an explicit cast.
5046
@test unsafe fn testRangeEndTypeSubType() throws (testing::TestError) {
5047
    {
5048
        let mut testArena331 = testArena();
5049
        let testStorage331: 'test331 = &mut testArena331 in {
5050
            let mut a = testResolver(testStorage331);
5051
            let program = "fn f(start: i8, end: u32) { for i in start..end {} }";
5052
            let result = try resolveProgramStr(&mut a, program);
5053
            let err = try expectError(&result);
5054
            try expectTypeMismatch(err, super::Type::I8, super::Type::U32);
5055
        }
5056
    } {
5057
        let mut testArena332 = testArena();
5058
        let testStorage332: 'test332 = &mut testArena332 in {
5059
            let mut a = testResolver(testStorage332);
5060
            let program = "fn f(start: i8, end: u32) { for i in (start as u32)..end {} }";
5061
            let result = try resolveProgramStr(&mut a, program);
5062
            try expectNoErrors(&result);
5063
        }
5064
    }
5065
}
5066
5067
/// Test that try-catch expressions in statement context accept mismatched types.
5068
@test unsafe fn testTryCatchInStatementContextTypeMismatchOk() throws (testing::TestError) {
5069
    let mut testArena333 = testArena();
5070
    let testStorage333: 'test333 = &mut testArena333 in {
5071
        let mut a = testResolver(testStorage333);
5072
        let program = "fn f() { try g() catch {}; } fn g() -> bool throws (i32) { panic; }";
5073
        let result = try resolveProgramStr(&mut a, program);
5074
        try expectNoErrors(&result);
5075
    }
5076
}
5077
5078
/// Test that try-catch blocks in value context require divergence or void.
5079
@test unsafe fn testTryCatchInValueContextTypeMismatch() throws (testing::TestError) {
5080
    let mut testArena334 = testArena();
5081
    let testStorage334: 'test334 = &mut testArena334 in {
5082
        let mut a = testResolver(testStorage334);
5083
        let program = "fn f() -> bool { return try g() catch {}; } fn g() -> bool throws (i32) { panic; }";
5084
        let result = try resolveProgramStr(&mut a, program);
5085
        let err = try expectError(&result);
5086
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Void);
5087
    }
5088
}
5089
5090
/// Test that try-catch blocks in value context work when they diverge.
5091
@test unsafe fn testTryCatchInValueContextDiverges() throws (testing::TestError) {
5092
    let mut testArena335 = testArena();
5093
    let testStorage335: 'test335 = &mut testArena335 in {
5094
        let mut a = testResolver(testStorage335);
5095
        let program = "fn f() -> bool { return try g() catch { return false; }; } fn g() -> bool throws (i32) { panic; }";
5096
        let result = try resolveProgramStr(&mut a, program);
5097
        try expectNoErrors(&result);
5098
    }
5099
}
5100
5101
/// Test that `try?` lifts result type to optional.
5102
@test unsafe fn testTryOptionalLiftsToOptional() throws (testing::TestError) {
5103
    let mut testArena336 = testArena();
5104
    let testStorage336: 'test336 = &mut testArena336 in {
5105
        let mut a = testResolver(testStorage336);
5106
        let program = "record S {} fn f() -> ?*S { return try? g(); } fn g() -> *S throws (i32) { panic; }";
5107
        let result = try resolveProgramStr(&mut a, program);
5108
        try expectNoErrors(&result);
5109
    }
5110
}
5111
5112
/// Test that record fields can be assigned if the record binding is mutable.
5113
@test unsafe fn testMutableAssignToMutableRecordBinding() throws (testing::TestError) {
5114
    let mut testArena337 = testArena();
5115
    let testStorage337: 'test337 = &mut testArena337 in {
5116
        let mut a = testResolver(testStorage337);
5117
        let program = "record S { x: i32 } fn f() { let mut s = S { x: 1 }; set s.x = 2; }";
5118
        let result = try resolveProgramStr(&mut a, program);
5119
        try expectNoErrors(&result);
5120
    }
5121
}
5122
5123
/// Test that record fields cannot be assigned if the record binding is immutable.
5124
@test unsafe fn testMutableAssignToImmutableRecordBinding() throws (testing::TestError) {
5125
    let mut testArena338 = testArena();
5126
    let testStorage338: 'test338 = &mut testArena338 in {
5127
        let mut a = testResolver(testStorage338);
5128
        let program = "record S { x: i32 } fn f() { let s = S { x: 1 }; set s.x = 2; }";
5129
        let result = try resolveProgramStr(&mut a, program);
5130
        let err = try expectError(&result);
5131
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5132
    }
5133
}
5134
5135
/// Test that record fields can be assigned through a mutable pointer.
5136
@test unsafe fn testMutableAssignToMutablePointerToRecord() throws (testing::TestError) {
5137
    let mut testArena339 = testArena();
5138
    let testStorage339: 'test339 = &mut testArena339 in {
5139
        let mut a = testResolver(testStorage339);
5140
        let program = "record S { x: i32 } fn f(p: *mut S) { set p.x = 2; }";
5141
        let result = try resolveProgramStr(&mut a, program);
5142
        try expectNoErrors(&result);
5143
    }
5144
}
5145
5146
/// Test that record fields cannot be assigned through an immutable pointer.
5147
@test unsafe fn testMutableAssignToImmutablePointerToRecord() throws (testing::TestError) {
5148
    let mut testArena340 = testArena();
5149
    let testStorage340: 'test340 = &mut testArena340 in {
5150
        let mut a = testResolver(testStorage340);
5151
        let program = "record S { x: i32 } fn f(p: *S) { set p.x = 2; }";
5152
        let result = try resolveProgramStr(&mut a, program);
5153
        let err = try expectError(&result);
5154
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
5155
    }
5156
}
5157
5158
// Opaque pointer tests.
5159
5160
/// You can assign any pointer (*T) to an opaque pointer (*opaque) without a cast.
5161
@test unsafe fn testOpaquePointerAutoCoercion() throws (testing::TestError) {
5162
    let mut testArena341 = testArena();
5163
    let testStorage341: 'test341 = &mut testArena341 in {
5164
        let mut a = testResolver(testStorage341);
5165
        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; }");
5166
        try expectNoErrors(&result);
5167
    }
5168
}
5169
5170
/// You cannot assign an opaque pointer to a non-opaque pointer without a cast.
5171
@test unsafe fn testOpaquePointerNoReverseCoercion() throws (testing::TestError) {
5172
    let mut testArena342 = testArena();
5173
    let testStorage342: 'test342 = &mut testArena342 in {
5174
        let mut a = testResolver(testStorage342);
5175
        let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let ptr: *i32 = o; }");
5176
        let err = try expectError(&result);
5177
        let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
5178
            else throw testing::TestError::Failed;
5179
        let case super::Type::Pointer { target: expectedTarget, .. } = mismatch.expected
5180
            else throw testing::TestError::Failed;
5181
        let case super::Type::Pointer { target: actualTarget, .. } = mismatch.actual
5182
            else throw testing::TestError::Failed;
5183
5184
        try testing::expect(*expectedTarget == super::Type::I32);
5185
        try testing::expect(*actualTarget == super::Type::Opaque);
5186
    }
5187
}
5188
5189
/// You cannot have a value of type `opaque` (function parameter).
5190
@test unsafe fn testOpaqueValue() throws (testing::TestError) {
5191
    {
5192
        let mut testArena343 = testArena();
5193
        let testStorage343: 'test343 = &mut testArena343 in {
5194
            let mut a = testResolver(testStorage343);
5195
            let result = try resolveProgramStr(&mut a, "fn f(x: opaque) {}");
5196
            let err = try expectError(&result);
5197
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
5198
        }
5199
    } {
5200
        let mut testArena344 = testArena();
5201
        let testStorage344: 'test344 = &mut testArena344 in {
5202
            let mut a = testResolver(testStorage344);
5203
            let result = try resolveProgramStr(&mut a, "unsafe fn f() { let x: opaque = undefined; }");
5204
            let err = try expectError(&result);
5205
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
5206
        }
5207
    } {
5208
        let mut testArena345 = testArena();
5209
        let testStorage345: 'test345 = &mut testArena345 in {
5210
            let mut a = testResolver(testStorage345);
5211
            let result = try resolveProgramStr(&mut a, "record R { x: opaque }");
5212
            let err = try expectError(&result);
5213
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
5214
        }
5215
    }
5216
}
5217
5218
/// You cannot dereference an opaque pointer, you have to cast it first.
5219
@test unsafe fn testOpaquePointerNoDereference() throws (testing::TestError) {
5220
    let mut testArena346 = testArena();
5221
    let testStorage346: 'test346 = &mut testArena346 in {
5222
        let mut a = testResolver(testStorage346);
5223
        let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = *o; }");
5224
        let err = try expectError(&result);
5225
        try expectErrorKind(&result, super::ErrorKind::OpaqueTypeDeref);
5226
    }
5227
}
5228
5229
/// Test that you can dereference after casting.
5230
@test unsafe fn testOpaquePointerDereferenceAfterCast() throws (testing::TestError) {
5231
    let mut testArena347 = testArena();
5232
    let testStorage347: 'test347 = &mut testArena347 in {
5233
        let mut a = testResolver(testStorage347);
5234
        let result = try resolveProgramStr(&mut a, "unsafe fn f() { let o: *opaque = undefined; let x = *(o as *i32); }");
5235
        try expectNoErrors(&result);
5236
    }
5237
}
5238
5239
/// You cannot do pointer arithmetic with an opaque pointer.
5240
@test unsafe fn testOpaquePointerNoArithmetic() throws (testing::TestError) {
5241
    {
5242
        let mut testArena348 = testArena();
5243
        let testStorage348: 'test348 = &mut testArena348 in {
5244
            let mut a = testResolver(testStorage348);
5245
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = o + 1; }");
5246
            let err = try expectError(&result);
5247
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
5248
        }
5249
    } {
5250
        let mut testArena349 = testArena();
5251
        let testStorage349: 'test349 = &mut testArena349 in {
5252
            let mut a = testResolver(testStorage349);
5253
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = 1 + o; }");
5254
            let err = try expectError(&result);
5255
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
5256
        }
5257
    } {
5258
        let mut testArena350 = testArena();
5259
        let testStorage350: 'test350 = &mut testArena350 in {
5260
            let mut a = testResolver(testStorage350);
5261
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = o - 1; }");
5262
            let err = try expectError(&result);
5263
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
5264
        }
5265
    } {
5266
        let mut testArena351 = testArena();
5267
        let testStorage351: 'test351 = &mut testArena351 in {
5268
            let mut a = testResolver(testStorage351);
5269
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = 1 - o; }");
5270
            let err = try expectError(&result);
5271
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
5272
        }
5273
    }
5274
}
5275
5276
// Wildcard import/reexport tests.
5277
5278
/// Test transitive re-export.
5279
@test unsafe fn testWildcardReexportTransitive() throws (testing::TestError) {
5280
    let mut testArena352 = testArena();
5281
    let testStorage352: 'test352 = &mut testArena352 in {
5282
        let mut a = testResolver(testStorage352);
5283
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5284
5285
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod a; export mod b;", &mut arena);
5286
        let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b; fn main() -> i32 { return b::helper() + b::MAX; }", &mut arena);
5287
        let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "mod c; export use c::*;", &mut arena);
5288
        let cId = try registerModule(&mut MODULE_GRAPH, bId, "c", "mod d; export use d::*; export fn helper() -> i32 { return 42; }", &mut arena);
5289
        let dId = try registerModule(&mut MODULE_GRAPH, cId, "d", "export constant MAX: i32 = 100;", &mut arena);
5290
5291
        let result = try resolveModuleTree(&mut a, rootId);
5292
        try expectNoErrors(&result);
5293
    }
5294
}
5295
5296
/// Test that wildcard import can access public symbols.
5297
@test unsafe fn testWildcardImportPublicOnly() throws (testing::TestError) {
5298
    let mut testArena353 = testArena();
5299
    let testStorage353: 'test353 = &mut testArena353 in {
5300
        let mut a = testResolver(testStorage353);
5301
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5302
5303
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod b; mod a;", &mut arena);
5304
        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);
5305
        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);
5306
5307
        let result = try resolveModuleTree(&mut a, rootId);
5308
        try expectNoErrors(&result);
5309
    }
5310
}
5311
5312
/// Test that wildcard import cannot access private symbols.
5313
@test unsafe fn testWildcardImportSkipsPrivate() throws (testing::TestError) {
5314
    let mut testArena354 = testArena();
5315
    let testStorage354: 'test354 = &mut testArena354 in {
5316
        let mut a = testResolver(testStorage354);
5317
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5318
5319
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod b; mod a;", &mut arena);
5320
        let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "export fn public() -> i32 { return 1; } fn private() -> i32 { return 2; }", &mut arena);
5321
        let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b::*; fn main() -> i32 { return private(); }", &mut arena);
5322
5323
        let result = try resolveModuleTree(&mut a, rootId);
5324
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
5325
    }
5326
}
5327
5328
/// Test that a constant array can use another constant as its length.
5329
@test unsafe fn testConstArrayWithConstLength() throws (testing::TestError) {
5330
    let mut testArena355 = testArena();
5331
    let testStorage355: 'test355 = &mut testArena355 in {
5332
        let mut a = testResolver(testStorage355);
5333
        let program = "constant LEN: u32 = 3; constant ARR: [i32; LEN] = [1, 2, 3];";
5334
        let result = try resolveProgramStr(&mut a, program);
5335
        try expectNoErrors(&result);
5336
5337
        // Verify the array constant has the correct type with length 3.
5338
        let arrStmt = try getBlockStmt(result.root, 1);
5339
        let sym = super::symbolFor(&a, arrStmt)
5340
            else throw testing::TestError::Failed;
5341
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
5342
            else throw testing::TestError::Failed;
5343
        try testing::expect(arrType.length == 3);
5344
    }
5345
}
5346
5347
/// Test that a record field can use a constant as its array length.
5348
@test unsafe fn testRecordFieldWithConstArrayLength() throws (testing::TestError) {
5349
    let mut testArena356 = testArena();
5350
    let testStorage356: 'test356 = &mut testArena356 in {
5351
        let mut a = testResolver(testStorage356);
5352
        let program = "constant SIZE: u32 = 4; record Buffer { data: [i32; SIZE], }";
5353
        let result = try resolveProgramStr(&mut a, program);
5354
        try expectNoErrors(&result);
5355
    }
5356
}
5357
5358
/// Test that a constant can have a record literal value (lazy record body resolution).
5359
@test unsafe fn testConstWithRecordLiteral() throws (testing::TestError) {
5360
    let mut testArena357 = testArena();
5361
    let testStorage357: 'test357 = &mut testArena357 in {
5362
        let mut a = testResolver(testStorage357);
5363
        let program = "record Point { x: i32, y: i32 } constant ORIGIN: Point = Point { x: 0, y: 0 };";
5364
        let result = try resolveProgramStr(&mut a, program);
5365
        try expectNoErrors(&result);
5366
    }
5367
}
5368
5369
/// Test that a constant can have a union variant value (lazy union body resolution).
5370
@test unsafe fn testConstWithUnionVariant() throws (testing::TestError) {
5371
    let mut testArena358 = testArena();
5372
    let testStorage358: 'test358 = &mut testArena358 in {
5373
        let mut a = testResolver(testStorage358);
5374
        let program = "union Color { Red, Green, Blue } constant DEFAULT: Color = Color::Red;";
5375
        let result = try resolveProgramStr(&mut a, program);
5376
        try expectNoErrors(&result);
5377
    }
5378
}
5379
5380
/// Test that record field types can reference imported types.
5381
///
5382
/// This tests that `use` statements are processed before record body resolution,
5383
/// allowing record fields to use types from imported modules.
5384
@test unsafe fn testRecordFieldUsesImportedType() throws (testing::TestError) {
5385
    let mut testArena359 = testArena();
5386
    let testStorage359: 'test359 = &mut testArena359 in {
5387
        let mut a = testResolver(testStorage359);
5388
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5389
5390
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod scanner;", &mut arena);
5391
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Pool { count: u32 }", &mut arena);
5392
        let scannerId = try registerModule(&mut MODULE_GRAPH, rootId, "scanner", "use root::types; record Scanner { pool: *types::Pool }", &mut arena);
5393
5394
        let result = try resolveModuleTree(&mut a, rootId);
5395
        try expectNoErrors(&result);
5396
    }
5397
}
5398
5399
/// Test that imported constants can be used in array size expressions.
5400
///
5401
/// This tests that constant values are propagated through scope access expressions,
5402
/// enabling compile-time evaluation of array sizes using imported constants.
5403
@test unsafe fn testImportedConstantInArraySize() throws (testing::TestError) {
5404
    let mut testArena360 = testArena();
5405
    let testStorage360: 'test360 = &mut testArena360 in {
5406
        let mut a = testResolver(testStorage360);
5407
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5408
5409
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
5410
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant SIZE: u32 = 8;", &mut arena);
5411
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; static BUFFER: [u8; consts::SIZE] = [0; consts::SIZE];", &mut arena);
5412
5413
        let result = try resolveModuleTree(&mut a, rootId);
5414
        try expectNoErrors(&result);
5415
    }
5416
}
5417
5418
/// Test that `if let case` binds payload variables in the then branch.
5419
///
5420
/// When using `if let case Union::Variant(x) = expr { ... }`, the variable `x` should
5421
/// be bound to the payload value within the then branch scope.
5422
@test unsafe fn testResolveIfCaseBindsPayload() throws (testing::TestError) {
5423
    let mut testArena361 = testArena();
5424
    let testStorage361: 'test361 = &mut testArena361 in {
5425
        let mut a = testResolver(testStorage361);
5426
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { if let case Opt::Some(x) = value { return x; } return 0; }";
5427
        let result = try resolveProgramStr(&mut a, program);
5428
        try expectNoErrors(&result);
5429
    }
5430
}
5431
5432
/// Test that `if let case` payload binding is scoped to the then branch.
5433
///
5434
/// The payload variable should not be accessible outside the then branch.
5435
@test unsafe fn testResolveIfCasePayloadScopeError() throws (testing::TestError) {
5436
    let mut testArena362 = testArena();
5437
    let testStorage362: 'test362 = &mut testArena362 in {
5438
        let mut a = testResolver(testStorage362);
5439
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { if let case Opt::Some(x) = value {} return x; }";
5440
        let result = try resolveProgramStr(&mut a, program);
5441
        let err = try expectError(&result);
5442
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
5443
            else throw testing::TestError::Failed;
5444
        try testing::expect(mem::eq(name, "x"));
5445
    }
5446
}
5447
5448
/// Test that `let case` binds payload variables in the current scope.
5449
///
5450
/// When using `let case Union::Variant(x) = expr else { ... }`, the variable `x`
5451
/// should be bound in the scope after the statement.
5452
@test unsafe fn testResolveLetCaseElseBindsPayload() throws (testing::TestError) {
5453
    let mut testArena363 = testArena();
5454
    let testStorage363: 'test363 = &mut testArena363 in {
5455
        let mut a = testResolver(testStorage363);
5456
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { let case Opt::Some(x) = value else panic; return x; }";
5457
        let result = try resolveProgramStr(&mut a, program);
5458
        try expectNoErrors(&result);
5459
    }
5460
}
5461
5462
/// Test that function pointers with identical signatures are assignable.
5463
///
5464
/// Two function types with the same parameters, return type, and throw list
5465
/// should be considered structurally equal, even if they are separate allocations.
5466
@test unsafe fn testFnPointerAssignability() throws (testing::TestError) {
5467
    let mut testArena364 = testArena();
5468
    let testStorage364: 'test364 = &mut testArena364 in {
5469
        let mut a = testResolver(testStorage364);
5470
        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);";
5471
        let result = try resolveProgramStr(&mut a, program);
5472
        try expectNoErrors(&result);
5473
    }
5474
}
5475
5476
/// Test that function pointers with different parameter types are not assignable.
5477
@test unsafe fn testFnPointerParamMismatch() throws (testing::TestError) {
5478
    let mut testArena365 = testArena();
5479
    let testStorage365: 'test365 = &mut testArena365 in {
5480
        let mut a = testResolver(testStorage365);
5481
        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);";
5482
        let result = try resolveProgramStr(&mut a, program);
5483
        let err = try expectError(&result);
5484
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5485
            else throw testing::TestError::Failed;
5486
    }
5487
}
5488
5489
/// Test that function pointers with different return types are not assignable.
5490
@test unsafe fn testFnPointerReturnMismatch() throws (testing::TestError) {
5491
    let mut testArena366 = testArena();
5492
    let testStorage366: 'test366 = &mut testArena366 in {
5493
        let mut a = testResolver(testStorage366);
5494
        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);";
5495
        let result = try resolveProgramStr(&mut a, program);
5496
        let err = try expectError(&result);
5497
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5498
            else throw testing::TestError::Failed;
5499
    }
5500
}
5501
5502
/// Test that named records use nominal typing, not structural.
5503
///
5504
/// Two different named record types with identical fields should NOT be
5505
/// assignable to each other, because they are distinct nominal types.
5506
@test unsafe fn testNamedRecordNominalTyping() throws (testing::TestError) {
5507
    let mut testArena367 = testArena();
5508
    let testStorage367: 'test367 = &mut testArena367 in {
5509
        let mut a = testResolver(testStorage367);
5510
        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);";
5511
        let result = try resolveProgramStr(&mut a, program);
5512
        let err = try expectError(&result);
5513
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5514
            else throw testing::TestError::Failed;
5515
    }
5516
}
5517
5518
/// Test that union variants with labeled record payloads can be constructed.
5519
@test unsafe fn testUnionVariantAnonRecordPayload() throws (testing::TestError) {
5520
    let mut testArena368 = testArena();
5521
    let testStorage368: 'test368 = &mut testArena368 in {
5522
        let mut a = testResolver(testStorage368);
5523
        let program = "union Event { Click { x: i32, y: i32 }, Key { code: u32 } } let e = Event::Click { x: 10, y: 20 };";
5524
        let result = try resolveProgramStr(&mut a, program);
5525
        try expectNoErrors(&result);
5526
    }
5527
}
5528
5529
/// Test that unlabeled record literals with positional fields work correctly.
5530
///
5531
/// When a record is declared with positional fields (e.g., `record R(i32, bool)`),
5532
/// the literal must use constructor call syntax with positional arguments.
5533
@test unsafe fn testResolveUnlabeledRecordLitValid() throws (testing::TestError) {
5534
    let mut testArena369 = testArena();
5535
    let testStorage369: 'test369 = &mut testArena369 in {
5536
        let mut a = testResolver(testStorage369);
5537
        let program = "record R(i32, bool); let r: R = R(1, true);";
5538
        let result = try resolveProgramStr(&mut a, program);
5539
        try expectNoErrors(&result);
5540
    }
5541
}
5542
5543
/// Test that using brace syntax for an unlabeled record causes an error.
5544
@test unsafe fn testResolveUnlabeledRecordLitStyleMismatch() throws (testing::TestError) {
5545
    let mut testArena370 = testArena();
5546
    let testStorage370: 'test370 = &mut testArena370 in {
5547
        let mut a = testResolver(testStorage370);
5548
        let program = "record R(i32); let r = R { x: 1 };";
5549
        let result = try resolveProgramStr(&mut a, program);
5550
        try expectErrorKind(&result, super::ErrorKind::RecordFieldStyleMismatch);
5551
    }
5552
}
5553
5554
/// Test that providing too many fields for an unlabeled record causes count mismatch.
5555
@test unsafe fn testResolveUnlabeledRecordLitTooManyFields() throws (testing::TestError) {
5556
    let mut testArena371 = testArena();
5557
    let testStorage371: 'test371 = &mut testArena371 in {
5558
        let mut a = testResolver(testStorage371);
5559
        let program = "record R(i32, bool); let r = R(1, true, 3);";
5560
        let result = try resolveProgramStr(&mut a, program);
5561
        let err = try expectError(&result);
5562
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5563
            else throw testing::TestError::Failed;
5564
    }
5565
}
5566
5567
/// Test that match pattern with wrong number of bindings causes count mismatch.
5568
@test unsafe fn testResolveMatchPatternWrongBindingCount() throws (testing::TestError) {
5569
    let mut testArena372 = testArena();
5570
    let testStorage372: 'test372 = &mut testArena372 in {
5571
        let mut a = testResolver(testStorage372);
5572
        let program = "union Event { Click { x: i32, y: i32 } } fn f(e: Event) { match e { case Event::Click(a) => {} } }";
5573
        let result = try resolveProgramStr(&mut a, program);
5574
        let err = try expectError(&result);
5575
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5576
            else throw testing::TestError::Failed;
5577
    }
5578
}
5579
5580
/// Test that shorthand field syntax works in record literals.
5581
/// `Point { x, y }` should be equivalent to `Point { x: x, y: y }`.
5582
@test unsafe fn testResolveRecordLiteralShorthand() throws (testing::TestError) {
5583
    let mut testArena373 = testArena();
5584
    let testStorage373: 'test373 = &mut testArena373 in {
5585
        let mut a = testResolver(testStorage373);
5586
        let program = "record Point { x: i32, y: i32 } fn f() { let x: i32 = 1; let y: i32 = 2; let p = Point { x, y }; }";
5587
        let result = try resolveProgramStr(&mut a, program);
5588
        try expectNoErrors(&result);
5589
    }
5590
}
5591
5592
/// Test shorthand field syntax with mixed explicit and shorthand fields.
5593
@test unsafe fn testResolveRecordLiteralMixedShorthand() throws (testing::TestError) {
5594
    let mut testArena374 = testArena();
5595
    let testStorage374: 'test374 = &mut testArena374 in {
5596
        let mut a = testResolver(testStorage374);
5597
        let program = "record Point { x: i32, y: i32 } fn f() { let x: i32 = 5; let p = Point { x, y: 10 }; }";
5598
        let result = try resolveProgramStr(&mut a, program);
5599
        try expectNoErrors(&result);
5600
    }
5601
}
5602
5603
/// Test record-style union variant patterns with shorthand syntax.
5604
@test unsafe fn testResolveMatchRecordPatternShorthand() throws (testing::TestError) {
5605
    let mut testArena375 = testArena();
5606
    let testStorage375: 'test375 = &mut testArena375 in {
5607
        let mut a = testResolver(testStorage375);
5608
        let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { width, height } => return width + height } }";
5609
        let result = try resolveProgramStr(&mut a, program);
5610
        try expectNoErrors(&result);
5611
    }
5612
}
5613
5614
/// Test record pattern with mixed shorthand and explicit labels.
5615
@test unsafe fn testResolveMatchRecordPatternMixed() throws (testing::TestError) {
5616
    let mut testArena376 = testArena();
5617
    let testStorage376: 'test376 = &mut testArena376 in {
5618
        let mut a = testResolver(testStorage376);
5619
        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 } }";
5620
        let result = try resolveProgramStr(&mut a, program);
5621
        try expectNoErrors(&result);
5622
    }
5623
}
5624
5625
/// Test record pattern with fields in reverse order.
5626
@test unsafe fn testResolveMatchRecordPatternReversed() throws (testing::TestError) {
5627
    let mut testArena377 = testArena();
5628
    let testStorage377: 'test377 = &mut testArena377 in {
5629
        let mut a = testResolver(testStorage377);
5630
        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 } }";
5631
        let result = try resolveProgramStr(&mut a, program);
5632
        try expectNoErrors(&result);
5633
    }
5634
}
5635
5636
/// Test record pattern with shorthand syntax in reverse order.
5637
/// Pattern `{ height, width }` binds all fields using shorthand, but not in definition order.
5638
@test unsafe fn testResolveMatchRecordPatternShorthandReversed() throws (testing::TestError) {
5639
    let mut testArena378 = testArena();
5640
    let testStorage378: 'test378 = &mut testArena378 in {
5641
        let mut a = testResolver(testStorage378);
5642
        let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { height, width } => return width + height } }";
5643
        let result = try resolveProgramStr(&mut a, program);
5644
        try expectNoErrors(&result);
5645
    }
5646
}
5647
5648
/// Test record pattern with `..` ignoring fields.
5649
@test unsafe fn testResolveMatchRecordPatternIgnoreRest() throws (testing::TestError) {
5650
    {
5651
        let mut testArena379 = testArena();
5652
        let testStorage379: 'test379 = &mut testArena379 in {
5653
            let mut a = testResolver(testStorage379);
5654
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { x, .. } => return x } }";
5655
            let result = try resolveProgramStr(&mut a, program);
5656
            try expectNoErrors(&result);
5657
        }
5658
    } {
5659
        let mut testArena380 = testArena();
5660
        let testStorage380: 'test380 = &mut testArena380 in {
5661
            let mut a = testResolver(testStorage380);
5662
            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 } }";
5663
            let result = try resolveProgramStr(&mut a, program);
5664
            try expectNoErrors(&result);
5665
        }
5666
    } {
5667
        let mut testArena381 = testArena();
5668
        let testStorage381: 'test381 = &mut testArena381 in {
5669
            let mut a = testResolver(testStorage381);
5670
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { z, .. } => return z } }";
5671
            let result = try resolveProgramStr(&mut a, program);
5672
            try expectNoErrors(&result);
5673
        }
5674
    } {
5675
        let mut testArena382 = testArena();
5676
        let testStorage382: 'test382 = &mut testArena382 in {
5677
            let mut a = testResolver(testStorage382);
5678
            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 } }";
5679
            let result = try resolveProgramStr(&mut a, program);
5680
            try expectNoErrors(&result);
5681
        }
5682
    } {
5683
        let mut testArena383 = testArena();
5684
        let testStorage383: 'test383 = &mut testArena383 in {
5685
            let mut a = testResolver(testStorage383);
5686
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> bool { match g { case G::Point { .. } => return true } }";
5687
            let result = try resolveProgramStr(&mut a, program);
5688
            try expectNoErrors(&result);
5689
        }
5690
    }
5691
}
5692
5693
/// Test standalone record pattern matching with unlabeled patterns.
5694
@test unsafe fn testResolveMatchStandaloneRecordUnlabeledPattern() throws (testing::TestError) {
5695
    let mut testArena384 = testArena();
5696
    let testStorage384: 'test384 = &mut testArena384 in {
5697
        let mut a = testResolver(testStorage384);
5698
        let program = "record S(i32); fn f(s: S) -> i32 { match s { case S(x) => return x, else => return 0 } }";
5699
        let result = try resolveProgramStr(&mut a, program);
5700
        try expectNoErrors(&result);
5701
    }
5702
}
5703
5704
/// Test standalone record pattern matching with labeled patterns.
5705
/// Pattern syntax: `T { x }` matches a named record and binds x to the field.
5706
@test unsafe fn testResolveMatchStandaloneRecordLabeledPattern() throws (testing::TestError) {
5707
    let mut testArena385 = testArena();
5708
    let testStorage385: 'test385 = &mut testArena385 in {
5709
        let mut a = testResolver(testStorage385);
5710
        let program = "record T { x: i32 } fn f(t: T) -> i32 { match t { case T { x } => return x, else => return 0 } }";
5711
        let result = try resolveProgramStr(&mut a, program);
5712
        try expectNoErrors(&result);
5713
    }
5714
}
5715
5716
/// Test standalone record pattern with multiple fields.
5717
/// Pattern syntax: `R(a, b)` matches an unlabeled record with multiple fields.
5718
@test unsafe fn testResolveMatchStandaloneRecordMultipleFields() throws (testing::TestError) {
5719
    let mut testArena386 = testArena();
5720
    let testStorage386: 'test386 = &mut testArena386 in {
5721
        let mut a = testResolver(testStorage386);
5722
        let program = "record R(bool, u8); fn f(r: R) -> u8 { match r { case R(_, x) => return x, else => return 0 } }";
5723
        let result = try resolveProgramStr(&mut a, program);
5724
        try expectNoErrors(&result);
5725
    }
5726
}
5727
5728
/// Test standalone record pattern with wrong field count.
5729
/// Pattern `S(x, y)` should fail for a single-field record.
5730
@test unsafe fn testResolveMatchStandaloneRecordWrongFieldCount() throws (testing::TestError) {
5731
    let mut testArena387 = testArena();
5732
    let testStorage387: 'test387 = &mut testArena387 in {
5733
        let mut a = testResolver(testStorage387);
5734
        let program = "record S(i32); fn f(s: S) -> i32 { match s { case S(x, y) => return x + y, else => return 0 } }";
5735
        let result = try resolveProgramStr(&mut a, program);
5736
        let err = try expectError(&result);
5737
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5738
            else throw testing::TestError::Failed;
5739
    }
5740
}
5741
5742
/// Test array pattern matching with element bindings.
5743
/// Pattern syntax: `[x, y]` matches an array and binds elements.
5744
@test unsafe fn testResolveMatchArrayPattern() throws (testing::TestError) {
5745
    let mut testArena388 = testArena();
5746
    let testStorage388: 'test388 = &mut testArena388 in {
5747
        let mut a = testResolver(testStorage388);
5748
        let program = "fn f(arr: [i32; 2]) -> i32 { match arr { case [x, y] => return x + y } }";
5749
        let result = try resolveProgramStr(&mut a, program);
5750
        try expectNoErrors(&result);
5751
    }
5752
}
5753
5754
/// Test array pattern with placeholder elements.
5755
/// Pattern syntax: `[_, y]` ignores first element.
5756
@test unsafe fn testResolveMatchArrayPatternPlaceholder() throws (testing::TestError) {
5757
    let mut testArena389 = testArena();
5758
    let testStorage389: 'test389 = &mut testArena389 in {
5759
        let mut a = testResolver(testStorage389);
5760
        let program = "fn f(arr: [i32; 2]) -> i32 { match arr { case [_, y] => return y } }";
5761
        let result = try resolveProgramStr(&mut a, program);
5762
        try expectNoErrors(&result);
5763
    }
5764
}
5765
5766
/// Test identifier pattern that binds the whole value.
5767
/// Pattern syntax: `x` matches any value and binds it.
5768
@test unsafe fn testResolveMatchIdentPattern() throws (testing::TestError) {
5769
    let mut testArena390 = testArena();
5770
    let testStorage390: 'test390 = &mut testArena390 in {
5771
        let mut a = testResolver(testStorage390);
5772
        let program = "fn f(val: i32) -> i32 { match val { x => return x } }";
5773
        let result = try resolveProgramStr(&mut a, program);
5774
        try expectNoErrors(&result);
5775
    }
5776
}
5777
5778
/// Test numeric literal pattern matching.
5779
@test unsafe fn testResolveMatchNumericLiteralPattern() throws (testing::TestError) {
5780
    let mut testArena391 = testArena();
5781
    let testStorage391: 'test391 = &mut testArena391 in {
5782
        let mut a = testResolver(testStorage391);
5783
        let program = "fn f(val: i32) -> i32 { match val { case 42 => return 1, else => return 0 } }";
5784
        let result = try resolveProgramStr(&mut a, program);
5785
        try expectNoErrors(&result);
5786
    }
5787
}
5788
5789
/// Test string literal pattern matching.
5790
@test unsafe fn testResolveMatchStringLiteralPattern() throws (testing::TestError) {
5791
    let mut testArena392 = testArena();
5792
    let testStorage392: 'test392 = &mut testArena392 in {
5793
        let mut a = testResolver(testStorage392);
5794
        let program = "fn f(val: *[u8]) -> i32 { match val { case \"hello\" => return 1, else => return 0 } }";
5795
        let result = try resolveProgramStr(&mut a, program);
5796
        try expectNoErrors(&result);
5797
    }
5798
}
5799
5800
/// Test boolean literal pattern matching.
5801
@test unsafe fn testResolveMatchBoolLiteralPattern() throws (testing::TestError) {
5802
    let mut testArena393 = testArena();
5803
    let testStorage393: 'test393 = &mut testArena393 in {
5804
        let mut a = testResolver(testStorage393);
5805
        let program = "fn f(val: bool) -> i32 { match val { case true => return 1, case false => return 0 } }";
5806
        let result = try resolveProgramStr(&mut a, program);
5807
        try expectNoErrors(&result);
5808
    }
5809
}
5810
5811
/// Test @sliceOf with correct arguments succeeds.
5812
@test unsafe fn testResolveSliceOfCorrect() throws (testing::TestError) {
5813
    // Immutable pointer.
5814
    {
5815
        let mut testArena394 = testArena();
5816
        let testStorage394: 'test394 = &mut testArena394 in {
5817
            let mut a = testResolver(testStorage394);
5818
            let program = "unsafe fn f(ptr: *u8, len: u32) -> *[u8] { return @sliceOf(ptr, len); }";
5819
            let result = try resolveProgramStr(&mut a, program);
5820
            try expectNoErrors(&result);
5821
        }
5822
    }
5823
    // Mutable pointer produces mutable slice.
5824
    {
5825
        let mut testArena395 = testArena();
5826
        let testStorage395: 'test395 = &mut testArena395 in {
5827
            let mut a = testResolver(testStorage395);
5828
            let program = "unsafe fn f(ptr: *mut u8, len: u32) -> *mut [u8] { return @sliceOf(ptr, len); }";
5829
            let result = try resolveProgramStr(&mut a, program);
5830
            try expectNoErrors(&result);
5831
        }
5832
    }
5833
}
5834
5835
/// Test @sliceOf with wrong argument count produces an error.
5836
@test unsafe fn testResolveSliceOfWrongArgCount() throws (testing::TestError) {
5837
    // No arguments.
5838
    {
5839
        let mut testArena396 = testArena();
5840
        let testStorage396: 'test396 = &mut testArena396 in {
5841
            let mut a = testResolver(testStorage396);
5842
            let program = "fn f() -> *[u8] { return @sliceOf(); }";
5843
            let result = try resolveProgramStr(&mut a, program);
5844
            let err = try expectError(&result);
5845
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5846
                else throw testing::TestError::Failed;
5847
            try testing::expect(mismatch.expected == 2);
5848
            try testing::expect(mismatch.actual == 0);
5849
        }
5850
    }
5851
    // Too few arguments.
5852
    {
5853
        let mut testArena397 = testArena();
5854
        let testStorage397: 'test397 = &mut testArena397 in {
5855
            let mut a = testResolver(testStorage397);
5856
            let program = "fn f(ptr: *u8) -> *[u8] { return @sliceOf(ptr); }";
5857
            let result = try resolveProgramStr(&mut a, program);
5858
            let err = try expectError(&result);
5859
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5860
                else throw testing::TestError::Failed;
5861
            try testing::expect(mismatch.expected == 2);
5862
            try testing::expect(mismatch.actual == 1);
5863
        }
5864
    }
5865
    // Too many arguments.
5866
    {
5867
        let mut testArena398 = testArena();
5868
        let testStorage398: 'test398 = &mut testArena398 in {
5869
            let mut a = testResolver(testStorage398);
5870
            let program = "fn f(ptr: *u8, len: u32, cap: u32, extra: u32) -> *[u8] { return @sliceOf(ptr, len, cap, extra); }";
5871
            let result = try resolveProgramStr(&mut a, program);
5872
            let err = try expectError(&result);
5873
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5874
                else throw testing::TestError::Failed;
5875
            try testing::expect(mismatch.expected == 2);
5876
            try testing::expect(mismatch.actual == 4);
5877
        }
5878
    }
5879
}
5880
5881
/// Test @sliceOf with wrong argument types produces errors.
5882
@test unsafe fn testResolveSliceOfWrongArgTypes() throws (testing::TestError) {
5883
    // Non-pointer first argument.
5884
    {
5885
        let mut testArena399 = testArena();
5886
        let testStorage399: 'test399 = &mut testArena399 in {
5887
            let mut a = testResolver(testStorage399);
5888
            let program = "fn f(val: u32, len: u32) -> *[u8] { return @sliceOf(val, len); }";
5889
            let result = try resolveProgramStr(&mut a, program);
5890
            let err = try expectError(&result);
5891
            let case super::ErrorKind::ExpectedPointer = err.kind
5892
                else throw testing::TestError::Failed;
5893
        }
5894
    }
5895
    // Array instead of pointer.
5896
    {
5897
        let mut testArena400 = testArena();
5898
        let testStorage400: 'test400 = &mut testArena400 in {
5899
            let mut a = testResolver(testStorage400);
5900
            let program = "fn f(arr: [u8; 4], len: u32) -> *[u8] { return @sliceOf(arr, len); }";
5901
            let result = try resolveProgramStr(&mut a, program);
5902
            let err = try expectError(&result);
5903
            let case super::ErrorKind::ExpectedPointer = err.kind
5904
                else throw testing::TestError::Failed;
5905
        }
5906
    }
5907
    // Non-numeric second argument.
5908
    {
5909
        let mut testArena401 = testArena();
5910
        let testStorage401: 'test401 = &mut testArena401 in {
5911
            let mut a = testResolver(testStorage401);
5912
            let program = "fn f(ptr: *u8, len: bool) -> *[u8] { return @sliceOf(ptr, len); }";
5913
            let result = try resolveProgramStr(&mut a, program);
5914
            let err = try expectError(&result);
5915
            let case super::ErrorKind::TypeMismatch(_) = err.kind
5916
                else throw testing::TestError::Failed;
5917
        }
5918
    }
5919
    // Pointer second argument.
5920
    {
5921
        let mut testArena402 = testArena();
5922
        let testStorage402: 'test402 = &mut testArena402 in {
5923
            let mut a = testResolver(testStorage402);
5924
            let program = "fn f(ptr: *u8, len: *u32) -> *[u8] { return @sliceOf(ptr, len); }";
5925
            let result = try resolveProgramStr(&mut a, program);
5926
            let err = try expectError(&result);
5927
            let case super::ErrorKind::TypeMismatch(_) = err.kind
5928
                else throw testing::TestError::Failed;
5929
        }
5930
    }
5931
}
5932
5933
/// Test @sliceOf with 3 arguments (ptr, len, cap) succeeds.
5934
@test unsafe fn testResolveSliceOfWithCap() throws (testing::TestError) {
5935
    {
5936
        let mut testArena403 = testArena();
5937
        let testStorage403: 'test403 = &mut testArena403 in {
5938
            let mut a = testResolver(testStorage403);
5939
            let program = "unsafe fn f(ptr: *u8, len: u32, cap: u32) -> *[u8] { return @sliceOf(ptr, len, cap); }";
5940
            let result = try resolveProgramStr(&mut a, program);
5941
            try expectNoErrors(&result);
5942
        }
5943
    }
5944
    // Mutable pointer produces mutable slice.
5945
    {
5946
        let mut testArena404 = testArena();
5947
        let testStorage404: 'test404 = &mut testArena404 in {
5948
            let mut a = testResolver(testStorage404);
5949
            let program = "unsafe fn f(ptr: *mut u8, len: u32, cap: u32) -> *mut [u8] { return @sliceOf(ptr, len, cap); }";
5950
            let result = try resolveProgramStr(&mut a, program);
5951
            try expectNoErrors(&result);
5952
        }
5953
    }
5954
}
5955
5956
/// Test @sliceOf with 3 arguments but wrong cap type.
5957
@test unsafe fn testResolveSliceOfCapWrongType() throws (testing::TestError) {
5958
    let mut testArena405 = testArena();
5959
    let testStorage405: 'test405 = &mut testArena405 in {
5960
        let mut a = testResolver(testStorage405);
5961
        let program = "fn f(ptr: *u8, len: u32, cap: bool) -> *[u8] { return @sliceOf(ptr, len, cap); }";
5962
        let result = try resolveProgramStr(&mut a, program);
5963
        let err = try expectError(&result);
5964
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5965
            else throw testing::TestError::Failed;
5966
    }
5967
}
5968
5969
/// Test .cap field access on slices resolves to u32.
5970
@test unsafe fn testResolveSliceCapField() throws (testing::TestError) {
5971
    let mut testArena406 = testArena();
5972
    let testStorage406: 'test406 = &mut testArena406 in {
5973
        let mut a = testResolver(testStorage406);
5974
        let program = "fn f(s: *[u8]) -> u32 { return s.cap; }";
5975
        let result = try resolveProgramStr(&mut a, program);
5976
        try expectNoErrors(&result);
5977
    }
5978
}
5979
5980
/// Test `.append()` on immutable slice produces an error.
5981
@test unsafe fn testResolveSliceAppendImmutable() throws (testing::TestError) {
5982
    let mut testArena407 = testArena();
5983
    let testStorage407: 'test407 = &mut testArena407 in {
5984
        let mut a = testResolver(testStorage407);
5985
        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); }";
5986
        let result = try resolveProgramStr(&mut a, program);
5987
        let err = try expectError(&result);
5988
        let case super::ErrorKind::ImmutableBinding = err.kind
5989
            else throw testing::TestError::Failed;
5990
    }
5991
}
5992
5993
/// Test `.append()` with wrong argument count produces an error.
5994
@test unsafe fn testResolveSliceAppendWrongArgCount() throws (testing::TestError) {
5995
    // Too few arguments.
5996
    {
5997
        let mut testArena408 = testArena();
5998
        let testStorage408: 'test408 = &mut testArena408 in {
5999
            let mut a = testResolver(testStorage408);
6000
            let program = "fn f(s: *mut [i32]) { s.append(1); }";
6001
            let result = try resolveProgramStr(&mut a, program);
6002
            let err = try expectError(&result);
6003
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
6004
                else throw testing::TestError::Failed;
6005
            try testing::expect(m.expected == 2);
6006
            try testing::expect(m.actual == 1);
6007
        }
6008
    }
6009
    // Too many arguments.
6010
    {
6011
        let mut testArena409 = testArena();
6012
        let testStorage409: 'test409 = &mut testArena409 in {
6013
            let mut a = testResolver(testStorage409);
6014
            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); }";
6015
            let result = try resolveProgramStr(&mut a, program);
6016
            let err = try expectError(&result);
6017
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
6018
                else throw testing::TestError::Failed;
6019
            try testing::expect(m.expected == 2);
6020
            try testing::expect(m.actual == 3);
6021
        }
6022
    }
6023
}
6024
6025
/// Test `.append()` with correct arguments succeeds.
6026
@test unsafe fn testResolveSliceAppendCorrect() throws (testing::TestError) {
6027
    let mut testArena410 = testArena();
6028
    let testStorage410: 'test410 = &mut testArena410 in {
6029
        let mut a = testResolver(testStorage410);
6030
        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); }";
6031
        let result = try resolveProgramStr(&mut a, program);
6032
        try expectNoErrors(&result);
6033
    }
6034
}
6035
6036
/// Test `.append()` with wrong element type produces an error.
6037
@test unsafe fn testResolveSliceAppendWrongElemType() throws (testing::TestError) {
6038
    let mut testArena411 = testArena();
6039
    let testStorage411: 'test411 = &mut testArena411 in {
6040
        let mut a = testResolver(testStorage411);
6041
        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); }";
6042
        let result = try resolveProgramStr(&mut a, program);
6043
        let err = try expectError(&result);
6044
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6045
            else throw testing::TestError::Failed;
6046
    }
6047
}
6048
6049
/// Test `.delete()` on immutable slice produces an error.
6050
@test unsafe fn testResolveSliceDeleteImmutable() throws (testing::TestError) {
6051
    let mut testArena412 = testArena();
6052
    let testStorage412: 'test412 = &mut testArena412 in {
6053
        let mut a = testResolver(testStorage412);
6054
        let program = "fn f(s: *[i32]) { s.delete(0); }";
6055
        let result = try resolveProgramStr(&mut a, program);
6056
        let err = try expectError(&result);
6057
        let case super::ErrorKind::ImmutableBinding = err.kind
6058
            else throw testing::TestError::Failed;
6059
    }
6060
}
6061
6062
/// Test `.delete()` with wrong argument count produces an error.
6063
@test unsafe fn testResolveSliceDeleteWrongArgCount() throws (testing::TestError) {
6064
    // No arguments.
6065
    {
6066
        let mut testArena413 = testArena();
6067
        let testStorage413: 'test413 = &mut testArena413 in {
6068
            let mut a = testResolver(testStorage413);
6069
            let program = "fn f(s: *mut [i32]) { s.delete(); }";
6070
            let result = try resolveProgramStr(&mut a, program);
6071
            let err = try expectError(&result);
6072
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
6073
                else throw testing::TestError::Failed;
6074
            try testing::expect(m.expected == 1);
6075
            try testing::expect(m.actual == 0);
6076
        }
6077
    }
6078
    // Too many arguments.
6079
    {
6080
        let mut testArena414 = testArena();
6081
        let testStorage414: 'test414 = &mut testArena414 in {
6082
            let mut a = testResolver(testStorage414);
6083
            let program = "fn f(s: *mut [i32]) { s.delete(0, 1); }";
6084
            let result = try resolveProgramStr(&mut a, program);
6085
            let err = try expectError(&result);
6086
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
6087
                else throw testing::TestError::Failed;
6088
            try testing::expect(m.expected == 1);
6089
            try testing::expect(m.actual == 2);
6090
        }
6091
    }
6092
}
6093
6094
/// Test `.delete()` with correct arguments succeeds.
6095
@test unsafe fn testResolveSliceDeleteCorrect() throws (testing::TestError) {
6096
    let mut testArena415 = testArena();
6097
    let testStorage415: 'test415 = &mut testArena415 in {
6098
        let mut a = testResolver(testStorage415);
6099
        let program = "fn f(s: *mut [i32]) { s.delete(0); }";
6100
        let result = try resolveProgramStr(&mut a, program);
6101
        try expectNoErrors(&result);
6102
    }
6103
}
6104
6105
/// Test `.delete()` with wrong argument type produces an error.
6106
@test unsafe fn testResolveSliceDeleteWrongArgType() throws (testing::TestError) {
6107
    let mut testArena416 = testArena();
6108
    let testStorage416: 'test416 = &mut testArena416 in {
6109
        let mut a = testResolver(testStorage416);
6110
        let program = "fn f(s: *mut [i32]) { s.delete(true); }";
6111
        let result = try resolveProgramStr(&mut a, program);
6112
        let err = try expectError(&result);
6113
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6114
            else throw testing::TestError::Failed;
6115
    }
6116
}
6117
6118
/// Test `match &opt` produces immutable pointer bindings.
6119
@test unsafe fn testResolveMatchRefUnionBinding() throws (testing::TestError) {
6120
    let mut testArena417 = testArena();
6121
    let testStorage417: 'test417 = &mut testArena417 in {
6122
        let mut a = testResolver(testStorage417);
6123
        let program = "union Opt { Some(i32), None } fn f() { let opt = Opt::Some(42); match &opt { case Opt::Some(x) => { *x; } else => {} } }";
6124
        let result = try resolveProgramStr(&mut a, program);
6125
        try expectNoErrors(&result);
6126
6127
        let fnBlock = try getFnBody(&a, result.root, "f");
6128
        let matchNode = fnBlock.statements[1];
6129
        let case ast::NodeValue::Match(sw) = matchNode.value
6130
            else throw testing::TestError::Failed;
6131
        let caseNode = sw.prongs[0];
6132
6133
        let scope = super::scopeFor(&a, caseNode)
6134
            else throw testing::TestError::Failed;
6135
        let payloadSym = super::findSymbolInScope(scope, "x")
6136
            else throw testing::TestError::Failed;
6137
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
6138
            else throw testing::TestError::Failed;
6139
        let case super::Type::Pointer { class: types::PointerClass::Ref, target, mutable } = payloadValType
6140
            else throw testing::TestError::Failed;
6141
        try testing::expect(not mutable);
6142
        try testing::expect(*target == super::Type::I32);
6143
    }
6144
}
6145
6146
/// Test `match &mut opt` produces mutable pointer bindings.
6147
@test unsafe fn testResolveMatchMutRefUnionBinding() throws (testing::TestError) {
6148
    let mut testArena418 = testArena();
6149
    let testStorage418: 'test418 = &mut testArena418 in {
6150
        let mut a = testResolver(testStorage418);
6151
        let program = "union Opt { Some(i32), None } fn f() { let mut opt = Opt::Some(42); match &mut opt { case Opt::Some(x) => { *x; } else => {} } }";
6152
        let result = try resolveProgramStr(&mut a, program);
6153
        try expectNoErrors(&result);
6154
6155
        let fnBlock = try getFnBody(&a, result.root, "f");
6156
        let matchNode = fnBlock.statements[1];
6157
        let case ast::NodeValue::Match(sw) = matchNode.value
6158
            else throw testing::TestError::Failed;
6159
        let caseNode = sw.prongs[0];
6160
6161
        let scope = super::scopeFor(&a, caseNode)
6162
            else throw testing::TestError::Failed;
6163
        let payloadSym = super::findSymbolInScope(scope, "x")
6164
            else throw testing::TestError::Failed;
6165
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
6166
            else throw testing::TestError::Failed;
6167
        let case super::Type::Pointer { class: types::PointerClass::Ref, target, mutable } = payloadValType
6168
            else throw testing::TestError::Failed;
6169
        try testing::expect(mutable);
6170
        try testing::expect(*target == super::Type::I32);
6171
    }
6172
}
6173
6174
/// Non-constant integer widening must use an explicit cast.
6175
@test unsafe fn testResolveIntegerWideningRequiresCast() throws (testing::TestError) {
6176
    {
6177
        let mut testArena419 = testArena();
6178
        let testStorage419: 'test419 = &mut testArena419 in {
6179
            let mut a = testResolver(testStorage419);
6180
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = x;");
6181
            let err = try expectError(&result);
6182
            try expectTypeMismatch(err, super::Type::U32, super::Type::U8);
6183
        }
6184
    } {
6185
        let mut testArena420 = testArena();
6186
        let testStorage420: 'test420 = &mut testArena420 in {
6187
            let mut a = testResolver(testStorage420);
6188
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u16 = x;");
6189
            let err = try expectError(&result);
6190
            try expectTypeMismatch(err, super::Type::U16, super::Type::U8);
6191
        }
6192
    } {
6193
        let mut testArena421 = testArena();
6194
        let testStorage421: 'test421 = &mut testArena421 in {
6195
            let mut a = testResolver(testStorage421);
6196
            let result = try resolveBlockStr(&mut a, "let x: u16 = 1; let y: u32 = x;");
6197
            let err = try expectError(&result);
6198
            try expectTypeMismatch(err, super::Type::U32, super::Type::U16);
6199
        }
6200
    } {
6201
        let mut testArena422 = testArena();
6202
        let testStorage422: 'test422 = &mut testArena422 in {
6203
            let mut a = testResolver(testStorage422);
6204
            let result = try resolveBlockStr(&mut a, "let x: i8 = 1; let y: i32 = x;");
6205
            let err = try expectError(&result);
6206
            try expectTypeMismatch(err, super::Type::I32, super::Type::I8);
6207
        }
6208
    } {
6209
        let mut testArena423 = testArena();
6210
        let testStorage423: 'test423 = &mut testArena423 in {
6211
            let mut a = testResolver(testStorage423);
6212
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = x as u32;");
6213
            try expectNoErrors(&result);
6214
        }
6215
    } {
6216
        let mut testArena424 = testArena();
6217
        let testStorage424: 'test424 = &mut testArena424 in {
6218
            let mut a = testResolver(testStorage424);
6219
            let result = try resolveBlockStr(&mut a, "let x: i8 = 1; let y: i32 = x as i32;");
6220
            try expectNoErrors(&result);
6221
        }
6222
    }
6223
}
6224
6225
/// Mixed-width integer binary ops require an explicit cast.
6226
@test unsafe fn testResolveIntegerWideningBinOpRequiresCast() throws (testing::TestError) {
6227
    {
6228
        let mut testArena425 = testArena();
6229
        let testStorage425: 'test425 = &mut testArena425 in {
6230
            let mut a = testResolver(testStorage425);
6231
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = x | y;");
6232
            let err = try expectError(&result);
6233
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
6234
        }
6235
    } {
6236
        let mut testArena426 = testArena();
6237
        let testStorage426: 'test426 = &mut testArena426 in {
6238
            let mut a = testResolver(testStorage426);
6239
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 0xFF; let z: u32 = x & y;");
6240
            let err = try expectError(&result);
6241
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
6242
        }
6243
    } {
6244
        let mut testArena427 = testArena();
6245
        let testStorage427: 'test427 = &mut testArena427 in {
6246
            let mut a = testResolver(testStorage427);
6247
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = x + y;");
6248
            let err = try expectError(&result);
6249
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
6250
        }
6251
    } {
6252
        let mut testArena428 = testArena();
6253
        let testStorage428: 'test428 = &mut testArena428 in {
6254
            let mut a = testResolver(testStorage428);
6255
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u8 = x << 2;");
6256
            try expectNoErrors(&result);
6257
        }
6258
    } {
6259
        let mut testArena429 = testArena();
6260
        let testStorage429: 'test429 = &mut testArena429 in {
6261
            let mut a = testResolver(testStorage429);
6262
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = (x as u32) | y;");
6263
            try expectNoErrors(&result);
6264
        }
6265
    } {
6266
        let mut testArena430 = testArena();
6267
        let testStorage430: 'test430 = &mut testArena430 in {
6268
            let mut a = testResolver(testStorage430);
6269
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = (x as u32) + y;");
6270
            try expectNoErrors(&result);
6271
        }
6272
    }
6273
}
6274
6275
/// A mutable slice pointer should be assignable to an immutable slice pointer.
6276
@test unsafe fn testResolveMutSliceAssignableToImmutSlice() throws (testing::TestError) {
6277
    let mut testArena431 = testArena();
6278
    let testStorage431: 'test431 = &mut testArena431 in {
6279
        let mut a = testResolver(testStorage431);
6280
        let result = try resolveBlockStr(&mut a, "static arr: [i32; 3] = [1, 2, 3]; let p: *mut [i32] = &mut arr[..]; let q: *[i32] = p;");
6281
        try expectNoErrors(&result);
6282
    }
6283
}
6284
6285
/// Comprehensive tests for `as` cast expressions.
6286
@test unsafe fn testResolveAsCasts() throws (testing::TestError) {
6287
    { // Pointer to numeric.
6288
        let mut testArena432 = testArena();
6289
        let testStorage432: 'test432 = &mut testArena432 in {
6290
            let mut a = testResolver(testStorage432);
6291
            let result = try resolveBlockStr(&mut a, "static x: i32 = 0; let p = &x; p as u32;");
6292
            try expectNoErrors(&result);
6293
        }
6294
    } { // Function pointer to numeric.
6295
        let mut testArena433 = testArena();
6296
        let testStorage433: 'test433 = &mut testArena433 in {
6297
            let mut a = testResolver(testStorage433);
6298
            let result = try resolveProgramStr(&mut a, "fn run(f: fn()) { f as u32; }");
6299
            try expectNoErrors(&result);
6300
        }
6301
    } { // *u8 to *i32 (u8 to i32 is valid).
6302
        let mut testArena434 = testArena();
6303
        let testStorage434: 'test434 = &mut testArena434 in {
6304
            let mut a = testResolver(testStorage434);
6305
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: *u8 = undefined; p as *i32; }");
6306
            try expectNoErrors(&result);
6307
        }
6308
    } { // **u8 to **i32 (*u8 to *i32 is valid).
6309
        let mut testArena435 = testArena();
6310
        let testStorage435: 'test435 = &mut testArena435 in {
6311
            let mut a = testResolver(testStorage435);
6312
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: **u8 = undefined; p as **i32; }");
6313
            try expectNoErrors(&result);
6314
        }
6315
    }
6316
6317
    { // *[i32] to *[opaque].
6318
        let mut testArena436 = testArena();
6319
        let testStorage436: 'test436 = &mut testArena436 in {
6320
            let mut a = testResolver(testStorage436);
6321
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as *[opaque]; }");
6322
            try expectNoErrors(&result);
6323
        }
6324
    } { // *[opaque] to *[i32].
6325
        let mut testArena437 = testArena();
6326
        let testStorage437: 'test437 = &mut testArena437 in {
6327
            let mut a = testResolver(testStorage437);
6328
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[opaque] = undefined; s as *[i32]; }");
6329
            try expectNoErrors(&result);
6330
        }
6331
    }
6332
6333
    { // *[i32] to *[u8].
6334
        let mut testArena438 = testArena();
6335
        let testStorage438: 'test438 = &mut testArena438 in {
6336
            let mut a = testResolver(testStorage438);
6337
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[i32] = undefined; s as *[u8]; }");
6338
            try expectNoErrors(&result);
6339
        }
6340
    } { // *[record] to *[u8].
6341
        let mut testArena439 = testArena();
6342
        let testStorage439: 'test439 = &mut testArena439 in {
6343
            let mut a = testResolver(testStorage439);
6344
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } unsafe fn f(s: *[R]) { s as *[u8]; }");
6345
            try expectNoErrors(&result);
6346
        }
6347
    }
6348
6349
    { // *[u8] to *[i32].
6350
        let mut testArena440 = testArena();
6351
        let testStorage440: 'test440 = &mut testArena440 in {
6352
            let mut a = testResolver(testStorage440);
6353
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[u8] = undefined; s as *[i32]; }");
6354
            try expectNoErrors(&result);
6355
        }
6356
    } { // *[*u8] to *[*i32]
6357
        let mut testArena441 = testArena();
6358
        let testStorage441: 'test441 = &mut testArena441 in {
6359
            let mut a = testResolver(testStorage441);
6360
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[*u8] = undefined; s as *[*i32]; }");
6361
            try expectNoErrors(&result);
6362
        }
6363
    }
6364
6365
    { // Identity cast: *mut [i32] to *mut [i32].
6366
        let mut testArena442 = testArena();
6367
        let testStorage442: 'test442 = &mut testArena442 in {
6368
            let mut a = testResolver(testStorage442);
6369
            let result = try resolveProgramStr(&mut a, "fn run(s: *mut [i32]) { s as *mut [i32]; }");
6370
            try expectNoErrors(&result);
6371
        }
6372
    } { // Identity cast: *i32 to *i32.
6373
        let mut testArena443 = testArena();
6374
        let testStorage443: 'test443 = &mut testArena443 in {
6375
            let mut a = testResolver(testStorage443);
6376
            let result = try resolveProgramStr(&mut a, "fn run(p: *i32) { p as *i32; }");
6377
            try expectNoErrors(&result);
6378
        }
6379
    } { // Identity cast: i32 to i32.
6380
        let mut testArena444 = testArena();
6381
        let testStorage444: 'test444 = &mut testArena444 in {
6382
            let mut a = testResolver(testStorage444);
6383
            let result = try resolveBlockStr(&mut a, "let x: i32 = 0; x as i32;");
6384
            try expectNoErrors(&result);
6385
        }
6386
    }
6387
}
6388
6389
/// Tests for invalid `as` casts that should be rejected.
6390
@test unsafe fn testResolveAsCastsInvalid() throws (testing::TestError) {
6391
    { // Pointer to slice is invalid.
6392
        let mut testArena445 = testArena();
6393
        let testStorage445: 'test445 = &mut testArena445 in {
6394
            let mut a = testResolver(testStorage445);
6395
            let result = try resolveProgramStr(&mut a, "fn run(p: *i32) { p as *[i32]; }");
6396
            let err = try expectError(&result);
6397
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6398
                else throw testing::TestError::Failed;
6399
        }
6400
    } { // Slice to pointer is invalid.
6401
        let mut testArena446 = testArena();
6402
        let testStorage446: 'test446 = &mut testArena446 in {
6403
            let mut a = testResolver(testStorage446);
6404
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as *i32; }");
6405
            let err = try expectError(&result);
6406
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6407
                else throw testing::TestError::Failed;
6408
        }
6409
    } { // *T to *i32 is invalid.
6410
        let mut testArena447 = testArena();
6411
        let testStorage447: 'test447 = &mut testArena447 in {
6412
            let mut a = testResolver(testStorage447);
6413
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(p: *R) { p as *i32; }");
6414
            let err = try expectError(&result);
6415
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6416
                else throw testing::TestError::Failed;
6417
        }
6418
    } { // *[T] to *[i32] is invalid.
6419
        let mut testArena448 = testArena();
6420
        let testStorage448: 'test448 = &mut testArena448 in {
6421
            let mut a = testResolver(testStorage448);
6422
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(s: *[R]) { s as *[i32]; }");
6423
            let err = try expectError(&result);
6424
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6425
                else throw testing::TestError::Failed;
6426
        }
6427
    } { // Slice to numeric is invalid.
6428
        let mut testArena449 = testArena();
6429
        let testStorage449: 'test449 = &mut testArena449 in {
6430
            let mut a = testResolver(testStorage449);
6431
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as u32; }");
6432
            let err = try expectError(&result);
6433
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6434
                else throw testing::TestError::Failed;
6435
        }
6436
    } { // *record to *u8 is invalid.
6437
        let mut testArena450 = testArena();
6438
        let testStorage450: 'test450 = &mut testArena450 in {
6439
            let mut a = testResolver(testStorage450);
6440
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(p: *R) { p as *u8; }");
6441
            let err = try expectError(&result);
6442
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6443
                else throw testing::TestError::Failed;
6444
        }
6445
    }
6446
}
6447
6448
/// Test that catch binding is available in catch block scope.
6449
@test unsafe fn testResolveTryCatchBinding() throws (testing::TestError) {
6450
    {
6451
        let mut testArena451 = testArena();
6452
        let testStorage451: 'test451 = &mut testArena451 in {
6453
            let mut a = testResolver(testStorage451);
6454
            let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; } fn caller() -> u32 { return try fallible() catch err { return 0; }; }";
6455
            let result = try resolveProgramStr(&mut a, program);
6456
            try expectNoErrors(&result);
6457
        }
6458
    } {
6459
        let mut testArena452 = testArena();
6460
        let testStorage452: 'test452 = &mut testArena452 in {
6461
            let mut a = testResolver(testStorage452);
6462
            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; } }; }";
6463
            let result = try resolveProgramStr(&mut a, program);
6464
            try expectNoErrors(&result);
6465
        }
6466
    } {
6467
        let mut testArena453 = testArena();
6468
        let testStorage453: 'test453 = &mut testArena453 in {
6469
            let mut a = testResolver(testStorage453);
6470
            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; }; }";
6471
            let result = try resolveProgramStr(&mut a, program);
6472
            try expectNoErrors(&result);
6473
        }
6474
    } {
6475
        let mut testArena454 = testArena();
6476
        let testStorage454: 'test454 = &mut testArena454 in {
6477
            let mut a = testResolver(testStorage454);
6478
            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, } }; }";
6479
            let result = try resolveProgramStr(&mut a, program);
6480
            try expectNoErrors(&result);
6481
        }
6482
    }
6483
}
6484
6485
/// Test that duplicate union variant patterns are detected.
6486
@test unsafe fn testResolveMatchDuplicateUnionPattern() throws (testing::TestError) {
6487
    {
6488
        let mut testArena455 = testArena();
6489
        let testStorage455: 'test455 = &mut testArena455 in {
6490
            let mut a = testResolver(testStorage455);
6491
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::A => {}, else => {} } }";
6492
            let result = try resolveProgramStr(&mut a, program);
6493
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6494
        }
6495
    } {
6496
        // No duplicate: distinct variants are fine.
6497
        let mut testArena456 = testArena();
6498
        let testStorage456: 'test456 = &mut testArena456 in {
6499
            let mut a = testResolver(testStorage456);
6500
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::B => {} } }";
6501
            let result = try resolveProgramStr(&mut a, program);
6502
            try expectNoErrors(&result);
6503
        }
6504
    }
6505
}
6506
6507
/// Test that duplicate bool patterns are detected.
6508
@test unsafe fn testResolveMatchDuplicateBoolPattern() throws (testing::TestError) {
6509
    {
6510
        let mut testArena457 = testArena();
6511
        let testStorage457: 'test457 = &mut testArena457 in {
6512
            let mut a = testResolver(testStorage457);
6513
            let program = "fn f(x: bool) { match x { case true => {}, case true => {}, else => {} } }";
6514
            let result = try resolveProgramStr(&mut a, program);
6515
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6516
        }
6517
    } {
6518
        let mut testArena458 = testArena();
6519
        let testStorage458: 'test458 = &mut testArena458 in {
6520
            let mut a = testResolver(testStorage458);
6521
            let program = "fn f(x: bool) { match x { case false => {}, case false => {}, else => {} } }";
6522
            let result = try resolveProgramStr(&mut a, program);
6523
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6524
        }
6525
    }
6526
}
6527
6528
/// Test that duplicate nil patterns in optional match are detected.
6529
@test unsafe fn testResolveMatchDuplicateOptionalPattern() throws (testing::TestError) {
6530
    {
6531
        let mut testArena459 = testArena();
6532
        let testStorage459: 'test459 = &mut testArena459 in {
6533
            let mut a = testResolver(testStorage459);
6534
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {}, case nil => {} } }";
6535
            let result = try resolveProgramStr(&mut a, program);
6536
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6537
        }
6538
    } {
6539
        // Duplicate value binding.
6540
        let mut testArena460 = testArena();
6541
        let testStorage460: 'test460 = &mut testArena460 in {
6542
            let mut a = testResolver(testStorage460);
6543
            let program = "fn f(opt: ?i32) { match opt { v => {}, w => {}, case nil => {} } }";
6544
            let result = try resolveProgramStr(&mut a, program);
6545
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6546
        }
6547
    }
6548
}
6549
6550
/// Test that guarded match arms are not considered duplicates.
6551
@test unsafe fn testResolveMatchGuardedNotDuplicate() throws (testing::TestError) {
6552
    {
6553
        // Guarded union variant followed by same variant is fine.
6554
        let mut testArena461 = testArena();
6555
        let testStorage461: 'test461 = &mut testArena461 in {
6556
            let mut a = testResolver(testStorage461);
6557
            let program = "union U { A, B } fn f(u: U) { match u { case U::A if true => {}, case U::A => {}, case U::B => {} } }";
6558
            let result = try resolveProgramStr(&mut a, program);
6559
            try expectNoErrors(&result);
6560
        }
6561
    } {
6562
        // Guarded bool pattern followed by same bool is fine.
6563
        let mut testArena462 = testArena();
6564
        let testStorage462: 'test462 = &mut testArena462 in {
6565
            let mut a = testResolver(testStorage462);
6566
            let program = "fn f(x: bool) { match x { case true if true => {}, case true => {}, case false => {} } }";
6567
            let result = try resolveProgramStr(&mut a, program);
6568
            try expectNoErrors(&result);
6569
        }
6570
    } {
6571
        // Guarded nil pattern followed by nil is fine.
6572
        let mut testArena463 = testArena();
6573
        let testStorage463: 'test463 = &mut testArena463 in {
6574
            let mut a = testResolver(testStorage463);
6575
            let program = "fn f(opt: ?i32) { match opt { case nil if true => {}, case nil => {}, v => {} } }";
6576
            let result = try resolveProgramStr(&mut a, program);
6577
            try expectNoErrors(&result);
6578
        }
6579
    } {
6580
        // Guarded value binding followed by another binding is fine.
6581
        let mut testArena464 = testArena();
6582
        let testStorage464: 'test464 = &mut testArena464 in {
6583
            let mut a = testResolver(testStorage464);
6584
            let program = "fn f(opt: ?i32) { match opt { v if true => {}, w => {}, case nil => {} } }";
6585
            let result = try resolveProgramStr(&mut a, program);
6586
            try expectNoErrors(&result);
6587
        }
6588
    }
6589
}
6590
6591
/// Test that unreachable else is detected when all union variants are covered.
6592
@test unsafe fn testResolveMatchUnreachableElseUnion() throws (testing::TestError) {
6593
    {
6594
        let mut testArena465 = testArena();
6595
        let testStorage465: 'test465 = &mut testArena465 in {
6596
            let mut a = testResolver(testStorage465);
6597
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::B => {}, else => {} } }";
6598
            let result = try resolveProgramStr(&mut a, program);
6599
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6600
        }
6601
    } {
6602
        // Partial coverage with else is fine.
6603
        let mut testArena466 = testArena();
6604
        let testStorage466: 'test466 = &mut testArena466 in {
6605
            let mut a = testResolver(testStorage466);
6606
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, else => {} } }";
6607
            let result = try resolveProgramStr(&mut a, program);
6608
            try expectNoErrors(&result);
6609
        }
6610
    }
6611
}
6612
6613
/// Test that unreachable else is detected when both bool cases are covered.
6614
@test unsafe fn testResolveMatchUnreachableElseBool() throws (testing::TestError) {
6615
    {
6616
        let mut testArena467 = testArena();
6617
        let testStorage467: 'test467 = &mut testArena467 in {
6618
            let mut a = testResolver(testStorage467);
6619
            let program = "fn f(x: bool) { match x { case true => {}, case false => {}, else => {} } }";
6620
            let result = try resolveProgramStr(&mut a, program);
6621
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6622
        }
6623
    } {
6624
        // Only one case with else is fine.
6625
        let mut testArena468 = testArena();
6626
        let testStorage468: 'test468 = &mut testArena468 in {
6627
            let mut a = testResolver(testStorage468);
6628
            let program = "fn f(x: bool) { match x { case true => {}, else => {} } }";
6629
            let result = try resolveProgramStr(&mut a, program);
6630
            try expectNoErrors(&result);
6631
        }
6632
    }
6633
}
6634
6635
/// Test that unreachable else is detected when both optional cases are covered.
6636
@test unsafe fn testResolveMatchUnreachableElseOptional() throws (testing::TestError) {
6637
    {
6638
        let mut testArena469 = testArena();
6639
        let testStorage469: 'test469 = &mut testArena469 in {
6640
            let mut a = testResolver(testStorage469);
6641
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {}, else => {} } }";
6642
            let result = try resolveProgramStr(&mut a, program);
6643
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6644
        }
6645
    } {
6646
        // Only value binding with else is fine.
6647
        let mut testArena470 = testArena();
6648
        let testStorage470: 'test470 = &mut testArena470 in {
6649
            let mut a = testResolver(testStorage470);
6650
            let program = "fn f(opt: ?i32) { match opt { v => {}, else => {} } }";
6651
            let result = try resolveProgramStr(&mut a, program);
6652
            try expectNoErrors(&result);
6653
        }
6654
    }
6655
}
6656
6657
// --- Multi-error typed catch tests ---
6658
6659
@test unsafe fn testTypedCatchExhaustive() throws (testing::TestError) {
6660
    let mut testArena471 = testArena();
6661
    let testStorage471: 'test471 = &mut testArena471 in {
6662
        let mut a = testResolver(testStorage471);
6663
        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; }; }";
6664
        let result = try resolveProgramStr(&mut a, program);
6665
        try expectNoErrors(&result);
6666
    }
6667
}
6668
6669
@test unsafe fn testTypedCatchNonExhaustive() throws (testing::TestError) {
6670
    let mut testArena472 = testArena();
6671
    let testStorage472: 'test472 = &mut testArena472 in {
6672
        let mut a = testResolver(testStorage472);
6673
        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; }; }";
6674
        let result = try resolveProgramStr(&mut a, program);
6675
        try expectErrorKind(&result, super::ErrorKind::TryCatchNonExhaustive);
6676
    }
6677
}
6678
6679
@test unsafe fn testTypedCatchDuplicate() throws (testing::TestError) {
6680
    let mut testArena473 = testArena();
6681
    let testStorage473: 'test473 = &mut testArena473 in {
6682
        let mut a = testResolver(testStorage473);
6683
        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; }; }";
6684
        let result = try resolveProgramStr(&mut a, program);
6685
        try expectErrorKind(&result, super::ErrorKind::TryCatchDuplicateType);
6686
    }
6687
}
6688
6689
@test unsafe fn testTypedCatchWithCatchAll() throws (testing::TestError) {
6690
    let mut testArena474 = testArena();
6691
    let testStorage474: 'test474 = &mut testArena474 in {
6692
        let mut a = testResolver(testStorage474);
6693
        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; }; }";
6694
        let result = try resolveProgramStr(&mut a, program);
6695
        try expectNoErrors(&result);
6696
    }
6697
}
6698
6699
@test unsafe fn testTypedCatchWrongType() throws (testing::TestError) {
6700
    let mut testArena475 = testArena();
6701
    let testStorage475: 'test475 = &mut testArena475 in {
6702
        let mut a = testResolver(testStorage475);
6703
        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; }; }";
6704
        let result = try resolveProgramStr(&mut a, program);
6705
        try expectErrorKind(&result, super::ErrorKind::TryIncompatibleError);
6706
    }
6707
}
6708
6709
@test unsafe fn testInferredCatchMultiError() throws (testing::TestError) {
6710
    let mut testArena476 = testArena();
6711
    let testStorage476: 'test476 = &mut testArena476 in {
6712
        let mut a = testResolver(testStorage476);
6713
        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; }; }";
6714
        let result = try resolveProgramStr(&mut a, program);
6715
        try expectErrorKind(&result, super::ErrorKind::TryCatchMultiError);
6716
    }
6717
}
6718
6719
@test unsafe fn testResolveInstanceMissingMethod() throws (testing::TestError) {
6720
    let mut testArena477 = testArena();
6721
    let testStorage477: 'test477 = &mut testArena477 in {
6722
        let mut a = testResolver(testStorage477);
6723
        let program = "trait S { fn (*S) f() -> i32; } record R { x: i32 } instance S for R {}";
6724
        let result = try resolveProgramStr(&mut a, program);
6725
        try expectErrorKind(&result, super::ErrorKind::MissingTraitMethod("f"));
6726
    }
6727
}
6728
6729
@test unsafe fn testResolveInstanceUnknownMethod() throws (testing::TestError) {
6730
    let mut testArena478 = testArena();
6731
    let testStorage478: 'test478 = &mut testArena478 in {
6732
        let mut a = testResolver(testStorage478);
6733
        let program = "trait S { fn (*S) f() -> i32; } record R { x: i32 } instance S for R { fn (self: *R) x() -> i32 { return 0; } }";
6734
        let result = try resolveProgramStr(&mut a, program);
6735
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
6736
    }
6737
}
6738
6739
@test unsafe fn testResolveTraitDuplicateMethodRejected() throws (testing::TestError) {
6740
    let mut testArena479 = testArena();
6741
    let testStorage479: 'test479 = &mut testArena479 in {
6742
        let mut a = testResolver(testStorage479);
6743
        let program = "trait Adder { fn (*mut Adder) add(n: i32) -> i32; fn (*mut Adder) add(n: i32) -> i32; }";
6744
        let result = try resolveProgramStr(&mut a, program);
6745
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("add"));
6746
    }
6747
}
6748
6749
@test unsafe fn testResolveInstanceReceiverTypeMustMatchTarget() throws (testing::TestError) {
6750
    let mut testArena480 = testArena();
6751
    let testStorage480: 'test480 = &mut testArena480 in {
6752
        let mut a = testResolver(testStorage480);
6753
        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; } }";
6754
        let result = try resolveProgramStr(&mut a, program);
6755
        let err = try expectError(&result);
6756
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6757
            else throw testing::TestError::Failed;
6758
    }
6759
}
6760
6761
@test unsafe fn testResolveTraitMethodThrowsRequireTry() throws (testing::TestError) {
6762
    let mut testArena481 = testArena();
6763
    let testStorage481: 'test481 = &mut testArena481 in {
6764
        let mut a = testResolver(testStorage481);
6765
        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); }";
6766
        let result = try resolveProgramStr(&mut a, program);
6767
        try expectErrorKind(&result, super::ErrorKind::MissingTry);
6768
    }
6769
}
6770
6771
/// Trait declares immutable receiver (*Trait) but instance uses mutable (*mut Type).
6772
/// The instance method could mutate through what was originally an immutable pointer.
6773
@test unsafe fn testResolveInstanceMutReceiverOnImmutableTrait() throws (testing::TestError) {
6774
    let mut testArena482 = testArena();
6775
    let testStorage482: 'test482 = &mut testArena482 in {
6776
        let mut a = testResolver(testStorage482);
6777
        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; } }";
6778
        let result = try resolveProgramStr(&mut a, program);
6779
        // Should reject: instance declares *mut receiver but trait only requires immutable.
6780
        try expectErrorKind(&result, super::ErrorKind::ReceiverMutabilityMismatch);
6781
    }
6782
}
6783
6784
/// Instance method declares different parameter types than the trait.
6785
/// The resolver should reject the mismatch rather than silently using the trait's types.
6786
@test unsafe fn testResolveInstanceParamTypeMismatch() throws (testing::TestError) {
6787
    let mut testArena483 = testArena();
6788
    let testStorage483: 'test483 = &mut testArena483 in {
6789
        let mut a = testResolver(testStorage483);
6790
        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; } }";
6791
        let result = try resolveProgramStr(&mut a, program);
6792
        // Should reject: instance param type u8 doesn't match trait param type i32.
6793
        let err = try expectError(&result);
6794
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6795
            else throw testing::TestError::Failed;
6796
    }
6797
}
6798
6799
/// Duplicate instance declarations for the same (trait, type) pair should be rejected.
6800
@test unsafe fn testResolveInstanceDuplicateRejected() throws (testing::TestError) {
6801
    let mut testArena484 = testArena();
6802
    let testStorage484: 'test484 = &mut testArena484 in {
6803
        let mut a = testResolver(testStorage484);
6804
        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; } }";
6805
        let result = try resolveProgramStr(&mut a, program);
6806
        // Should reject: duplicate instance for (Adder, Counter).
6807
        try expectErrorKind(&result, super::ErrorKind::DuplicateInstance);
6808
    }
6809
}
6810
6811
/// Trait method receiver must point to the declaring trait type.
6812
@test unsafe fn testResolveTraitReceiverMismatch() throws (testing::TestError) {
6813
    let mut testArena485 = testArena();
6814
    let testStorage485: 'test485 = &mut testArena485 in {
6815
        let mut a = testResolver(testStorage485);
6816
        let program = "record Other { x: i32 } trait Foo { fn (*mut Other) bar() -> i32; }";
6817
        let result = try resolveProgramStr(&mut a, program);
6818
        try expectErrorKind(&result, super::ErrorKind::TraitReceiverMismatch);
6819
    }
6820
}
6821
6822
/// Using a trait name as a value expression should be rejected.
6823
@test unsafe fn testResolveTraitNameAsValueRejected() throws (testing::TestError) {
6824
    let mut testArena486 = testArena();
6825
    let testStorage486: 'test486 = &mut testArena486 in {
6826
        let mut a = testResolver(testStorage486);
6827
        let program = "trait Foo { fn (*Foo) bar() -> i32; } fn test() -> i32 { let x = Foo; return 0; }";
6828
        let result = try resolveProgramStr(&mut a, program);
6829
        try expectErrorKind(&result, super::ErrorKind::UnexpectedTraitName);
6830
    }
6831
}
6832
6833
/// Cross-module trait: coerce to trait object and dispatch from a different module.
6834
@test unsafe fn testResolveTraitCrossModuleCoercion() throws (testing::TestError) {
6835
    let mut testArena487 = testArena();
6836
    let testStorage487: 'test487 = &mut testArena487 in {
6837
        let mut a = testResolver(testStorage487);
6838
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6839
6840
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; mod app;", &mut arena);
6841
        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);
6842
        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);
6843
6844
        let result = try resolveModuleTree(&mut a, rootId);
6845
        try expectNoErrors(&result);
6846
    }
6847
}
6848
6849
/// Instance in a different module from trait and type.
6850
@test unsafe fn testResolveInstanceCrossModule() throws (testing::TestError) {
6851
    let mut testArena488 = testArena();
6852
    let testStorage488: 'test488 = &mut testArena488 in {
6853
        let mut a = testResolver(testStorage488);
6854
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6855
6856
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; export mod impls; mod app;", &mut arena);
6857
        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);
6858
        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);
6859
        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);
6860
6861
        let result = try resolveModuleTree(&mut a, rootId);
6862
        try expectNoErrors(&result);
6863
    }
6864
}
6865
6866
/// Calling a mutable-receiver trait method on an immutable trait object
6867
/// must be rejected.
6868
@test unsafe fn testResolveTraitMutMethodOnImmutableObject() throws (testing::TestError) {
6869
    let mut testArena489 = testArena();
6870
    let testStorage489: 'test489 = &mut testArena489 in {
6871
        let mut a = testResolver(testStorage489);
6872
        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); }";
6873
        let result = try resolveProgramStr(&mut a, program);
6874
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
6875
    }
6876
}
6877
6878
/// Immutable methods on an immutable trait object should be accepted.
6879
@test unsafe fn testResolveTraitImmutableMethodOnImmutableObject() throws (testing::TestError) {
6880
    let mut testArena490 = testArena();
6881
    let testStorage490: 'test490 = &mut testArena490 in {
6882
        let mut a = testResolver(testStorage490);
6883
        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(); }";
6884
        let result = try resolveProgramStr(&mut a, program);
6885
        try expectNoErrors(&result);
6886
    }
6887
}
6888
6889
/// Both mutable and immutable methods on a mutable trait object should work.
6890
@test unsafe fn testResolveTraitMixedMethodsOnMutableObject() throws (testing::TestError) {
6891
    let mut testArena491 = testArena();
6892
    let testStorage491: 'test491 = &mut testArena491 in {
6893
        let mut a = testResolver(testStorage491);
6894
        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(); }";
6895
        let result = try resolveProgramStr(&mut a, program);
6896
        try expectNoErrors(&result);
6897
    }
6898
}
6899
6900
/// Instance method body type must match the trait return type.
6901
/// The trait declares `-> i32` but the body returns `bool`.
6902
@test unsafe fn testResolveInstanceReturnTypeMismatch() throws (testing::TestError) {
6903
    let mut testArena492 = testArena();
6904
    let testStorage492: 'test492 = &mut testArena492 in {
6905
        let mut a = testResolver(testStorage492);
6906
        let program = "record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() -> bool { return true; } }";
6907
        let result = try resolveProgramStr(&mut a, program);
6908
        let err = try expectError(&result);
6909
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6910
            else throw testing::TestError::Failed;
6911
    }
6912
}
6913
6914
/// Diamond supertrait inheritance: traits B and C both extend A.
6915
/// Declaring them independently should work fine.
6916
@test unsafe fn testResolveTraitDiamondSupertrait() throws (testing::TestError) {
6917
    let mut testArena493 = testArena();
6918
    let testStorage493: 'test493 = &mut testArena493 in {
6919
        let mut a = testResolver(testStorage493);
6920
        let program = "trait A { fn (*A) f() -> i32; } trait B: A { fn (*B) g() -> i32; } trait C: A { fn (*C) h() -> i32; }";
6921
        let result = try resolveProgramStr(&mut a, program);
6922
        try expectNoErrors(&result);
6923
    }
6924
}
6925
6926
/// Diamond supertrait with a combined trait that would cause duplicate
6927
/// method names should be detected.
6928
@test unsafe fn testResolveTraitDiamondDuplicateMethod() throws (testing::TestError) {
6929
    let mut testArena494 = testArena();
6930
    let testStorage494: 'test494 = &mut testArena494 in {
6931
        let mut a = testResolver(testStorage494);
6932
        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; }";
6933
        let result = try resolveProgramStr(&mut a, program);
6934
        // B inherits `f` from A, C inherits `f` from A. D: B + C sees duplicate `f`.
6935
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("f"));
6936
    }
6937
}
6938
6939
/// Supertrait instance must exist when declaring a combined trait instance.
6940
@test unsafe fn testResolveInstanceMissingSupertraitInstance() throws (testing::TestError) {
6941
    let mut testArena495 = testArena();
6942
    let testStorage495: 'test495 = &mut testArena495 in {
6943
        let mut a = testResolver(testStorage495);
6944
        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; } }";
6945
        let result = try resolveProgramStr(&mut a, program);
6946
        try expectErrorKind(&result, super::ErrorKind::MissingSupertraitInstance("Base"));
6947
    }
6948
}
6949
6950
/// Instance method omits return type when the trait declares `-> i32`.
6951
/// This is rejected -- the return type must be stated explicitly.
6952
@test unsafe fn testResolveInstanceReturnTypeOmitted() throws (testing::TestError) {
6953
    let mut testArena496 = testArena();
6954
    let testStorage496: 'test496 = &mut testArena496 in {
6955
        let mut a = testResolver(testStorage496);
6956
        let program = "record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() { } }";
6957
        let result = try resolveProgramStr(&mut a, program);
6958
        let err = try expectError(&result);
6959
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6960
            else throw testing::TestError::Failed;
6961
    }
6962
}
6963
6964
/// Instance method declares throws but the trait method does not throw.
6965
@test unsafe fn testResolveInstanceThrowsMismatchExtra() throws (testing::TestError) {
6966
    let mut testArena497 = testArena();
6967
    let testStorage497: 'test497 = &mut testArena497 in {
6968
        let mut a = testResolver(testStorage497);
6969
        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; } }";
6970
        let result = try resolveProgramStr(&mut a, program);
6971
        let err = try expectError(&result);
6972
        let case super::ErrorKind::FnThrowCountMismatch(_) = err.kind
6973
            else throw testing::TestError::Failed;
6974
    }
6975
}
6976
6977
/// Instance method declares a different throws type than the trait.
6978
@test unsafe fn testResolveInstanceThrowsMismatchWrongType() throws (testing::TestError) {
6979
    let mut testArena498 = testArena();
6980
    let testStorage498: 'test498 = &mut testArena498 in {
6981
        let mut a = testResolver(testStorage498);
6982
        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; } }";
6983
        let result = try resolveProgramStr(&mut a, program);
6984
        let err = try expectError(&result);
6985
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6986
            else throw testing::TestError::Failed;
6987
    }
6988
}
6989
6990
/// Instance method omits throws clause when trait declares throws.
6991
/// This is rejected -- the throws clause must match exactly.
6992
@test unsafe fn testResolveInstanceThrowsOmitted() throws (testing::TestError) {
6993
    let mut testArena499 = testArena();
6994
    let testStorage499: 'test499 = &mut testArena499 in {
6995
        let mut a = testResolver(testStorage499);
6996
        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; } }";
6997
        let result = try resolveProgramStr(&mut a, program);
6998
        let err = try expectError(&result);
6999
        let case super::ErrorKind::FnThrowCountMismatch(_) = err.kind
7000
            else throw testing::TestError::Failed;
7001
    }
7002
}
7003
7004
/// Instance method correctly matches the trait's throws clause.
7005
@test unsafe fn testResolveInstanceThrowsMatch() throws (testing::TestError) {
7006
    let mut testArena500 = testArena();
7007
    let testStorage500: 'test500 = &mut testArena500 in {
7008
        let mut a = testResolver(testStorage500);
7009
        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; } }";
7010
        let result = try resolveProgramStr(&mut a, program);
7011
        try expectNoErrors(&result);
7012
    }
7013
}
7014
7015
// Constant expression folding tests //////////////////////////////////////////
7016
7017
/// Resolve a program and verify that the constant at the given statement index
7018
/// has the expected integer magnitude.
7019
unsafe fn expectConstFold(program: *[u8], stmtIdx: u32, expected: u64)
7020
    throws (testing::TestError)
7021
{
7022
    let mut testArena501 = testArena();
7023
    let testStorage501: 'test501 = &mut testArena501 in {
7024
        let mut a = testResolver(testStorage501);
7025
        let result = try resolveProgramStr(&mut a, program);
7026
        try expectNoErrors(&result);
7027
7028
        let stmt = try getBlockStmt(result.root, stmtIdx);
7029
        let sym = super::symbolFor(&a, stmt)
7030
            else throw testing::TestError::Failed;
7031
        let case super::SymbolData::Constant { value, .. } = sym.data
7032
            else throw testing::TestError::Failed;
7033
        let val = value else throw testing::TestError::Failed;
7034
        let case super::ConstValue::Int(intVal) = val
7035
            else throw testing::TestError::Failed;
7036
        try testing::expect(intVal.magnitude == expected);
7037
    }
7038
}
7039
7040
/// Test arithmetic constant folding: add, sub, mul, div.
7041
@test unsafe fn testConstExprArithmetic() throws (testing::TestError) {
7042
    try expectConstFold("constant A: i32 = 10; constant B: i32 = 20; constant C: i32 = A + B;", 2, 30);
7043
    try expectConstFold("constant A: i32 = 50; constant B: i32 = 20; constant C: i32 = A - B;", 2, 30);
7044
    try expectConstFold("constant A: i32 = 6; constant B: i32 = 7; constant C: i32 = A * B;", 2, 42);
7045
    try expectConstFold("constant A: i32 = 100; constant B: i32 = 5; constant C: i32 = A / B;", 2, 20);
7046
}
7047
7048
/// Test bitwise constant folding: and, or, xor.
7049
@test unsafe fn testConstExprBitwise() throws (testing::TestError) {
7050
    try expectConstFold("constant A: i32 = 0xFF; constant B: i32 = 0x0F; constant C: i32 = A & B;", 2, 0x0F);
7051
    try expectConstFold("constant A: i32 = 0xF0; constant B: i32 = 0x0F; constant C: i32 = A | B;", 2, 0xFF);
7052
    try expectConstFold("constant A: i32 = 0xFF; constant B: i32 = 0x0F; constant C: i32 = A ^ B;", 2, 0xF0);
7053
}
7054
7055
/// Test shift constant folding.
7056
@test unsafe fn testConstExprShift() throws (testing::TestError) {
7057
    try expectConstFold("constant A: i32 = 1; constant B: i32 = A << 4;", 1, 16);
7058
    try expectConstFold("constant A: i32 = 32; constant B: i32 = A >> 2;", 1, 8);
7059
}
7060
7061
/// Test chained constant expressions (C depends on A + B, D depends on C).
7062
@test unsafe fn testConstExprChained() throws (testing::TestError) {
7063
    try expectConstFold("constant A: i32 = 10; constant B: i32 = 20; constant C: i32 = A + B; constant D: i32 = C * 2;", 3, 60);
7064
}
7065
7066
/// Test constant expression used as array size.
7067
@test unsafe fn testConstExprAsArraySize() throws (testing::TestError) {
7068
    let mut testArena502 = testArena();
7069
    let testStorage502: 'test502 = &mut testArena502 in {
7070
        let mut a = testResolver(testStorage502);
7071
        let program = "constant A: u32 = 2; constant B: u32 = 3; constant SIZE: u32 = A + B; constant ARR: [i32; SIZE] = [1, 2, 3, 4, 5];";
7072
        let result = try resolveProgramStr(&mut a, program);
7073
        try expectNoErrors(&result);
7074
7075
        let arrStmt = try getBlockStmt(result.root, 3);
7076
        let sym = super::symbolFor(&a, arrStmt)
7077
            else throw testing::TestError::Failed;
7078
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
7079
            else throw testing::TestError::Failed;
7080
        try testing::expect(arrType.length == 5);
7081
    }
7082
}
7083
7084
/// Test cross-module constant expression: a constant in one module references
7085
/// a constant from another module via scope access.
7086
@test unsafe fn testCrossModuleConstExpr() throws (testing::TestError) {
7087
    let mut testArena503 = testArena();
7088
    let testStorage503: 'test503 = &mut testArena503 in {
7089
        let mut a = testResolver(testStorage503);
7090
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
7091
7092
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
7093
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant BASE: i32 = 100;", &mut arena);
7094
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; constant DERIVED: i32 = consts::BASE + 50;", &mut arena);
7095
7096
        let result = try resolveModuleTree(&mut a, rootId);
7097
        try expectNoErrors(&result);
7098
    }
7099
}
7100
7101
/// Test cross-module constant expression used as array size.
7102
@test unsafe fn testCrossModuleConstExprArraySize() throws (testing::TestError) {
7103
    let mut testArena504 = testArena();
7104
    let testStorage504: 'test504 = &mut testArena504 in {
7105
        let mut a = testResolver(testStorage504);
7106
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
7107
7108
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
7109
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant WIDTH: u32 = 8; export constant HEIGHT: u32 = 4;", &mut arena);
7110
        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);
7111
7112
        let result = try resolveModuleTree(&mut a, rootId);
7113
        try expectNoErrors(&result);
7114
    }
7115
}
7116
7117
/// Test that non-constant expressions in constant declarations are still rejected.
7118
@test unsafe fn testConstExprNonConstRejected() throws (testing::TestError) {
7119
    let mut testArena505 = testArena();
7120
    let testStorage505: 'test505 = &mut testArena505 in {
7121
        let mut a = testResolver(testStorage505);
7122
        let program = "fn value() -> i32 { return 1; } constant BAD: i32 = value() + 1;";
7123
        let result = try resolveProgramStr(&mut a, program);
7124
        let err = try expectError(&result);
7125
        let case super::ErrorKind::ConstExprRequired = err.kind
7126
            else throw testing::TestError::Failed;
7127
    }
7128
}
7129
7130
/// Test unary negation in constant expressions.
7131
@test unsafe fn testConstExprUnaryNeg() throws (testing::TestError) {
7132
    let mut testArena506 = testArena();
7133
    let testStorage506: 'test506 = &mut testArena506 in {
7134
        let mut a = testResolver(testStorage506);
7135
        let program = "constant A: i32 = 10; constant B: i32 = -A;";
7136
        let result = try resolveProgramStr(&mut a, program);
7137
        try expectNoErrors(&result);
7138
    }
7139
}
7140
7141
/// Test unary not in constant expressions.
7142
@test unsafe fn testConstExprUnaryNot() throws (testing::TestError) {
7143
    let mut testArena507 = testArena();
7144
    let testStorage507: 'test507 = &mut testArena507 in {
7145
        let mut a = testResolver(testStorage507);
7146
        let program = "constant A: bool = true; constant B: bool = not A;";
7147
        let result = try resolveProgramStr(&mut a, program);
7148
        try expectNoErrors(&result);
7149
    }
7150
}
7151
7152
/// Test `as` casts in constant expressions: widening, narrowing, sign changes, chaining.
7153
@test unsafe fn testConstExprCast() throws (testing::TestError) {
7154
    try expectConstFold("constant A: i32 = 42; constant B: u64 = A as u64;", 1, 42);
7155
    try expectConstFold("constant A: u64 = 10; constant B: u8 = A as u8;", 1, 10);
7156
    try expectConstFold("constant A: i32 = 7; constant B: u32 = A as u32;", 1, 7);
7157
    try expectConstFold("constant A: u32 = 100; constant B: i32 = A as i32;", 1, 100);
7158
    try expectConstFold("constant A: u8 = 5; constant B: u64 = (A as u32) as u64;", 1, 5);
7159
    try expectConstFold("constant A: u8 = 3; constant B: u8 = 4; constant C: i32 = (A as i32) + (B as i32);", 2, 7);
7160
    // Cast of unsuffixed literal arithmetic.
7161
    try expectConstFold("constant A: u32 = (3 + 4) as u32;", 0, 7);
7162
    try expectConstFold("constant A: u32 = ((3 + 4) as u64) as u32;", 0, 7);
7163
    try expectConstFold("constant A: u32 = (3 + 4) as u32 + 1;", 0, 8);
7164
    try expectConstFold("constant A: i32 = (2 as i32) * (3 + 4);", 0, 14);
7165
}
7166
7167
/// Test `as` cast in constant expressions used as array size.
7168
@test unsafe fn testConstExprCastAsArraySize() throws (testing::TestError) {
7169
    let mut testArena508 = testArena();
7170
    let testStorage508: 'test508 = &mut testArena508 in {
7171
        let mut a = testResolver(testStorage508);
7172
        let program = "constant LEN: u64 = 4; constant SIZE: u32 = LEN as u32; constant ARR: [i32; SIZE] = [1, 2, 3, 4];";
7173
        let result = try resolveProgramStr(&mut a, program);
7174
        try expectNoErrors(&result);
7175
7176
        let arrStmt = try getBlockStmt(result.root, 2);
7177
        let sym = super::symbolFor(&a, arrStmt)
7178
            else throw testing::TestError::Failed;
7179
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
7180
            else throw testing::TestError::Failed;
7181
        try testing::expect(arrType.length == 4);
7182
    }
7183
}
7184
7185
/// Test unsuffixed integer literals in constant expressions.
7186
@test unsafe fn testConstExprUnsuffixedLiterals() throws (testing::TestError) {
7187
    try expectConstFold("constant A: u32 = 4 * 4;", 0, 16);
7188
    try expectConstFold("constant B: u32 = 10; constant C: u32 = B * 2;", 1, 20);
7189
    try expectConstFold("constant D: u32 = 3 + 7;", 0, 10);
7190
    try expectConstFold("constant E: u32 = 2 * 3 + 4;", 0, 10);
7191
    try expectConstFold("constant F: i32 = -(3 + 4);", 0, 7);
7192
}
7193
7194
/// References cannot escape through return types.
7195
@test unsafe fn testRefReturnRejected() throws (testing::TestError) {
7196
    let mut testArena509 = testArena();
7197
    let testStorage509: 'test509 = &mut testArena509 in {
7198
        let mut a = testResolver(testStorage509);
7199
        let program = "record Marker: Once {} fn bad(value: &u32) -> &u32 { return value; }";
7200
        let result = try resolveProgramStr(&mut a, program);
7201
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7202
    }
7203
}
7204
7205
/// Case-pattern fallbacks must terminate instead of synthesizing bindings.
7206
@test unsafe fn testCaseLetElseFallbackMustTerminate() throws (testing::TestError) {
7207
    let mut testArena510 = testArena();
7208
    let testStorage510: 'test510 = &mut testArena510 in {
7209
        let mut a = testResolver(testStorage510);
7210
        let program = "union Value { Item(u32) } fn run(value: Value) { let case Value::Item(item) = value else value; item; }";
7211
        let result = try resolveProgramStr(&mut a, program);
7212
        try expectErrorKind(&result, super::ErrorKind::LinearLetElseMustTerminate);
7213
    }
7214
}
7215
7216
/// Case bindings are unavailable on the pattern-failure path.
7217
@test unsafe fn testCaseLetElseFallbackCannotUseBinding() throws (testing::TestError) {
7218
    let mut testArena511 = testArena();
7219
    let testStorage511: 'test511 = &mut testArena511 in {
7220
        let mut a = testResolver(testStorage511);
7221
        let program = "union Value { Item(u32) } fn run(value: Value) { let case Value::Item(item) = value else item; }";
7222
        let result = try resolveProgramStr(&mut a, program);
7223
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("item"));
7224
    }
7225
}
7226
7227
/// Unsafe pointer dereference requires an unsafe declaration.
7228
@test unsafe fn testUnsafePointerOperationRejected() throws (testing::TestError) {
7229
    let mut testArena512 = testArena();
7230
    let testStorage512: 'test512 = &mut testArena512 in {
7231
        let mut a = testResolver(testStorage512);
7232
        let program = "record Marker: Once {} fn load(pointer: *unsafe u32) -> u32 { return *pointer; }";
7233
        let result = try resolveProgramStr(&mut a, program);
7234
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7235
    }
7236
}
7237
7238
/// Unsafe pointers remain freely copyable inside an unsafe declaration.
7239
@test unsafe fn testUnsafePointerOperationAllowed() throws (testing::TestError) {
7240
    let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; }";
7241
    try expectAnalyzeOk(program);
7242
}
7243
7244
/// Safe code cannot call a function that accepts unsafe operations.
7245
@test unsafe fn testUnsafeFunctionCallRejected() throws (testing::TestError) {
7246
    let mut testArena513 = testArena();
7247
    let testStorage513: 'test513 = &mut testArena513 in {
7248
        let mut a = testResolver(testStorage513);
7249
        let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } fn run(pointer: *unsafe u32) -> u32 { return load(pointer); }";
7250
        let result = try resolveProgramStr(&mut a, program);
7251
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7252
    }
7253
}
7254
7255
/// Unsafe function values retain their call-site safety requirement.
7256
@test unsafe fn testUnsafeFunctionAliasCallRejected() throws (testing::TestError) {
7257
    let mut testArena514 = testArena();
7258
    let testStorage514: 'test514 = &mut testArena514 in {
7259
        let mut a = testResolver(testStorage514);
7260
        let program = "unsafe fn dangerous() -> u32 { return 42; } fn run() -> u32 { let alias = dangerous; return alias(); }";
7261
        let result = try resolveProgramStr(&mut a, program);
7262
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7263
    }
7264
}
7265
7266
/// References cannot be embedded in aggregate fields.
7267
@test unsafe fn testRefFieldRejected() throws (testing::TestError) {
7268
    let mut testArena515 = testArena();
7269
    let testStorage515: 'test515 = &mut testArena515 in {
7270
        let mut a = testResolver(testStorage515);
7271
        let program = "record Marker: Once {} record Bad { value: &u32 }";
7272
        let result = try resolveProgramStr(&mut a, program);
7273
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7274
    }
7275
}
7276
7277
/// Trait methods may use reference receivers.
7278
@test unsafe fn testTraitRefReceiver() throws (testing::TestError) {
7279
    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); }";
7280
    try expectAnalyzeOk(program);
7281
}
7282
7283
/// Trait implementations must preserve the receiver pointer class.
7284
@test unsafe fn testTraitReceiverClassMismatch() throws (testing::TestError) {
7285
    let mut testArena516 = testArena();
7286
    let testStorage516: 'test516 = &mut testArena516 in {
7287
        let mut a = testResolver(testStorage516);
7288
        let program = "record Value { number: i32 } trait Read { fn (&Read) get() -> i32; } instance Read for Value { fn (value: *Value) get() -> i32 { return value.number; } }";
7289
        let result = try resolveProgramStr(&mut a, program);
7290
        try expectErrorKind(&result, super::ErrorKind::TraitReceiverMismatch);
7291
    }
7292
}
7293
7294
/// Unmarked composite values may be discarded.
7295
@test unsafe fn testAffineCompositeMayBeDiscarded() throws (testing::TestError) {
7296
    let program = "record Value { number: u32 } fn run() { let value = Value { number: 1 }; }";
7297
    try expectAnalyzeOk(program);
7298
}
7299
7300
/// A by-value use moves an unmarked composite value.
7301
@test unsafe fn testAffineCompositeUseAfterMoveRejected() throws (testing::TestError) {
7302
    let mut testArena517 = testArena();
7303
    let testStorage517: 'test517 = &mut testArena517 in {
7304
        let mut a = testResolver(testStorage517);
7305
        let program = "record Value { number: u32 } fn take(value: Value) {} fn run() { let value = Value { number: 1 }; take(value); take(value); }";
7306
        let result = try resolveProgramStr(&mut a, program);
7307
        try expectErrorKind(&result, super::ErrorKind::AffineUseAfterMove("value"));
7308
    }
7309
}
7310
7311
/// Affine values may move on only one branch when not used later.
7312
@test unsafe fn testAffineConditionalMoveMayBeDiscarded() throws (testing::TestError) {
7313
    let program = "record Value { number: u32 } fn take(value: Value) {} fn run(condition: bool) { let value = Value { number: 1 }; if condition { take(value); } }";
7314
    try expectAnalyzeOk(program);
7315
}
7316
7317
/// A `Copy` composite remains available after a by-value use.
7318
@test unsafe fn testCopyCompositeMayBeReused() throws (testing::TestError) {
7319
    let program = "record Value: Copy { number: u32 } fn take(value: Value) {} fn run() { let value = Value { number: 1 }; take(value); take(value); }";
7320
    try expectAnalyzeOk(program);
7321
}
7322
7323
/// A `Copy` composite may contain only copy values.
7324
@test unsafe fn testCopyCompositeRejectsAffineField() throws (testing::TestError) {
7325
    let mut testArena518 = testArena();
7326
    let testStorage518: 'test518 = &mut testArena518 in {
7327
        let mut a = testResolver(testStorage518);
7328
        let program = "record Inner { number: u32 } record Outer: Copy { inner: Inner }";
7329
        let result = try resolveProgramStr(&mut a, program);
7330
        try expectErrorKind(&result, super::ErrorKind::CopyContainsNonCopy);
7331
    }
7332
}
7333
7334
/// A composite cannot carry conflicting ownership markers.
7335
@test unsafe fn testConflictingOwnershipMarkersRejected() throws (testing::TestError) {
7336
    let mut testArena519 = testArena();
7337
    let testStorage519: 'test519 = &mut testArena519 in {
7338
        let mut a = testResolver(testStorage519);
7339
        let program = "record Value: Copy + Once { number: u32 }";
7340
        let result = try resolveProgramStr(&mut a, program);
7341
        try expectErrorKind(&result, super::ErrorKind::ConflictingOwnershipMarkers);
7342
    }
7343
}
7344
7345
/// Linear composites still require one consuming use.
7346
@test unsafe fn testLinearCompositeMustBeConsumed() throws (testing::TestError) {
7347
    let mut testArena520 = testArena();
7348
    let testStorage520: 'test520 = &mut testArena520 in {
7349
        let mut a = testResolver(testStorage520);
7350
        let program = "record Token: Once { number: u32 } fn run() { let token = Token { number: 1 }; }";
7351
        let result = try resolveProgramStr(&mut a, program);
7352
        try expectErrorKind(&result, super::ErrorKind::LinearNotConsumed("token"));
7353
    }
7354
}
7355
7356
/// The compiler-known marker cannot be derived more than once.
7357
@test unsafe fn testDuplicateOnceMarkerRejected() throws (testing::TestError) {
7358
    let mut testArena521 = testArena();
7359
    let testStorage521: 'test521 = &mut testArena521 in {
7360
        let mut a = testResolver(testStorage521);
7361
        let program = "record Token: Once + Once { value: u32 }";
7362
        let result = try resolveProgramStr(&mut a, program);
7363
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("Once"));
7364
    }
7365
}
7366
7367
/// Stack storage cannot produce a safe stored pointer or slice.
7368
@test unsafe fn testStackPointerRejected() throws (testing::TestError) {
7369
    let programs = &[
7370
        "fn run() { let value: u32 = 0; let pointer: *u32 = &value; }",
7371
        "fn run() -> *u32 { let value: u32 = 0; return &value; }",
7372
        "fn run(value: u32) -> *u32 { return &value; }",
7373
        "record Cell { value: u32 } fn run() { let cell = Cell { value: 1 }; let pointer: *u32 = &(cell.value); }",
7374
        "fn run() { let values = [1, 2]; let pointer: *i32 = &values[0]; }",
7375
        "fn run() { let values = [1, 2]; let slice: *[i32] = &values[..]; }",
7376
        "fn run(value: i32) { let slice: *[i32] = &[value]; }",
7377
        "fn run(value: &u32) -> *u32 { return value; }",
7378
        "fn run(value: &u32) -> *u32 { return &*value; }",
7379
        "fn run(values: &[u32]) -> *[u32] { return values; }",
7380
        "fn run(values: &[u32]) -> *[u32] { return &values[..]; }",
7381
        "fn run(values: &[u32]) -> *u32 { return values.ptr; }",
7382
        "fn run() -> *i32 { return &[1, 2][0]; }",
7383
        "fn run() -> *[i32] { return &[1, 2][..]; }",
7384
        "fn run(value: *u32) -> **u32 { return &value; }",
7385
        "fn run(values: *[u32]) -> *u32 { return &values.len; }",
7386
        "unsafe fn run(value: *unsafe u32) -> *u32 { return &*value; }",
7387
        "fn run() { let value: u32 = 7; let pointer: *unsafe u32 = &value; }",
7388
        "record Cell { value: u32 } fn run(value: &Cell) -> *u32 { return &value.value; }",
7389
        "record Cell { value: *u32 } fn run(value: &u32) -> Cell { return Cell { value }; }",
7390
        "fn run(value: &u32) -> *[u32] { return @sliceOf(value, 1); }",
7391
    ];
7392
    for program in programs {
7393
        let mut testArena522 = testArena();
7394
        let testStorage522: 'test522 = &mut testArena522 in {
7395
            let mut resolver = testResolver(testStorage522);
7396
            let result = try resolveProgramStr(&mut resolver, program);
7397
            let _ = try expectError(&result);
7398
        }
7399
    }
7400
}
7401
7402
/// Stack values can be borrowed for a call.
7403
@test unsafe fn testStackBorrowAllowed() throws (testing::TestError) {
7404
    try expectAnalyzeOk("fn read(value: &u32) -> u32 { return *value; } fn run() -> u32 { let value: u32 = 7; return read(&value); }");
7405
    try expectAnalyzeOk("fn write(values: &mut [u32]) { set values[0] = 7; } fn run() { let mut values: [u32; 2] = [1, 2]; write(&mut values[..]); }");
7406
}
7407
7408
/// Raw pointers and slices can be borrowed in an unsafe context.
7409
@test unsafe fn testImplicitRawBorrowAllowed() throws (testing::TestError) {
7410
    let programs = &[
7411
        "fn read(p: &u32) -> u32 { return *p; } unsafe fn run(p: *unsafe u32) -> u32 { return read(p); }",
7412
        "fn write(p: &mut u32) { set *p = 7; } fn run(p: *unsafe mut u32) { unsafe { write(p); write(p); } }",
7413
        "fn read(p: &[u32]) -> u32 { return p[0]; } unsafe fn run(p: *unsafe [u32]) -> u32 { return read(p); }",
7414
        "fn write(p: &mut [u32]) { set p[0] = 7; } unsafe fn run(p: *unsafe mut [u32]) { write(p); write(p); }",
7415
        "fn read(p: &u32) {} unsafe fn run(p: *unsafe mut u32) { read(p); }",
7416
        "trait Read { fn (&Read) get(); } fn read(p: &opaque Read) {} unsafe fn run(p: *unsafe opaque Read) { read(p); }",
7417
    ];
7418
    for program in programs {
7419
        try expectAnalyzeOk(program);
7420
    }
7421
}
7422
7423
/// An implicit borrow of raw storage requires an unsafe context.
7424
@test unsafe fn testImplicitRawBorrowRequiresUnsafe() throws (testing::TestError) {
7425
    let programs = &[
7426
        "fn read(p: &u32) {} fn run(p: *unsafe u32) { read(p); }",
7427
        "fn write(p: &mut u32) {} fn run(p: *unsafe mut u32) { write(p); }",
7428
        "fn read(p: &[u32]) {} fn run(p: *unsafe [u32]) { read(p); }",
7429
        "fn write(p: &mut [u32]) {} fn run(p: *unsafe mut [u32]) { write(p); }",
7430
        "trait Read { fn (&Read) get(); } fn read(p: &opaque Read) {} fn run(p: *unsafe opaque Read) { read(p); }",
7431
        "fn read(p: &u32) {} fn run(p: *unsafe u32) { unsafe { read(p); } read(p); }",
7432
    ];
7433
    for program in programs {
7434
        let mut testArena523 = testArena();
7435
        let testStorage523: 'test523 = &mut testArena523 in {
7436
            let mut a = testResolver(testStorage523);
7437
            let result = try resolveProgramStr(&mut a, program);
7438
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7439
        }
7440
    }
7441
}
7442
7443
/// Raw borrows preserve mutability, storage type, and ownership constraints.
7444
@test unsafe fn testImplicitRawBorrowPreservesTypes() throws (testing::TestError) {
7445
    let programs = &[
7446
        "fn write(p: &mut u32) {} unsafe fn run(p: *unsafe u32) { write(p); }",
7447
        "fn write(p: &mut [u32]) {} unsafe fn run(p: *unsafe [u32]) { write(p); }",
7448
        "fn read(p: &u64) {} unsafe fn run(p: *unsafe u32) { read(p); }",
7449
        "fn read(p: &[u64]) {} unsafe fn run(p: *unsafe [u32]) { read(p); }",
7450
        "fn take(p: *u32) {} unsafe fn run(p: *unsafe u32) { take(p); }",
7451
        "fn take(p: *[u32]) {} unsafe fn run(p: *unsafe [u32]) { take(p); }",
7452
        "fn read(p: &*u32) {} unsafe fn run(p: *unsafe *unsafe u32) { read(p); }",
7453
    ];
7454
    for program in programs {
7455
        let mut testArena524 = testArena();
7456
        let testStorage524: 'test524 = &mut testArena524 in {
7457
            let mut a = testResolver(testStorage524);
7458
            let result = try resolveProgramStr(&mut a, program);
7459
            let err = try expectError(&result);
7460
            let case super::ErrorKind::TypeMismatch(_) = err.kind
7461
                else throw testing::TestError::Failed;
7462
        }
7463
    }
7464
}
7465
7466
/// Implicit raw borrows retain the call's exclusive-borrow checks.
7467
@test unsafe fn testImplicitRawBorrowConflict() throws (testing::TestError) {
7468
    let mut testArena525 = testArena();
7469
    let testStorage525: 'test525 = &mut testArena525 in {
7470
        let mut a = testResolver(testStorage525);
7471
        let result = try resolveProgramStr(&mut a,
7472
            "fn useBoth(a: &mut u32, b: &u32) {} unsafe fn run(p: *unsafe mut u32) { useBoth(p, p); }");
7473
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("p"));
7474
    }
7475
}
7476
7477
/// Unsafe declarations can store raw pointers to stack values.
7478
@test unsafe fn testUnsafeStackPointerAllowed() throws (testing::TestError) {
7479
    try expectAnalyzeOk("unsafe fn run() { let mut value: u32 = 0; let pointer: *unsafe mut u32 = &mut value as *unsafe mut u32; set *pointer = 7; }");
7480
    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; }");
7481
    try expectAnalyzeOk("unsafe fn run() { let value: u32 = 7; let pointer: *unsafe u32 = &value; }");
7482
    try expectAnalyzeOk("unsafe fn run() { let values: [u32; 2] = [1, 2]; let slice: *unsafe [u32] = &values[..]; }");
7483
}
7484
7485
/// Permanent storage can produce safe stored pointers and slices.
7486
@test unsafe fn testPermanentPointerAllowed() throws (testing::TestError) {
7487
    try expectAnalyzeOk("static VALUE: u32 = 7; fn run() -> *u32 { return &VALUE; }");
7488
    try expectAnalyzeOk("static VALUES: [u32; 2] = [1, 2]; fn run() -> *[u32] { return &VALUES[..]; }");
7489
    try expectAnalyzeOk("fn run() -> *[u32] { return &[1, 2]; }");
7490
    try expectAnalyzeOk("fn run(value: *u32) -> *u32 { return &*value; }");
7491
    try expectAnalyzeOk("fn run(values: *[u32]) -> *[u32] { return &values[..]; }");
7492
    try expectAnalyzeOk("record Cell { value: u32 } fn run(value: *Cell) -> *u32 { return &value.value; }");
7493
    try expectAnalyzeOk("fn run(values: *[u32]) -> *u32 { return &values[0]; }");
7494
    try expectAnalyzeOk("unsafe fn run(values: *[u32]) -> *u32 { return values.ptr; }");
7495
    try expectAnalyzeOk("unsafe fn run(value: *u32) -> *[u32] { return @sliceOf(value, 1); }");
7496
}
7497
7498
/// References are rejected from every nested or storable type position.
7499
@test unsafe fn testNestedRefPositionsRejected() throws (testing::TestError) {
7500
    {
7501
        let mut testArena526 = testArena();
7502
        let testStorage526: 'test526 = &mut testArena526 in {
7503
            let mut a = testResolver(testStorage526);
7504
            let program = "record Marker: Once {} union Bad { Value(&u32) }";
7505
            let result = try resolveProgramStr(&mut a, program);
7506
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7507
        }
7508
    } {
7509
        let mut testArena527 = testArena();
7510
        let testStorage527: 'test527 = &mut testArena527 in {
7511
            let mut a = testResolver(testStorage527);
7512
            let program = "record Marker: Once {} fn bad(value: ?&u32) {}";
7513
            let result = try resolveProgramStr(&mut a, program);
7514
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7515
        }
7516
    } {
7517
        let mut testArena528 = testArena();
7518
        let testStorage528: 'test528 = &mut testArena528 in {
7519
            let mut a = testResolver(testStorage528);
7520
            let program = "record Marker: Once {} fn bad(value: [&u32; 1]) {}";
7521
            let result = try resolveProgramStr(&mut a, program);
7522
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7523
        }
7524
    } {
7525
        let mut testArena529 = testArena();
7526
        let testStorage529: 'test529 = &mut testArena529 in {
7527
            let mut a = testResolver(testStorage529);
7528
            let program = "record Marker: Once {} fn bad(value: *&u32) {}";
7529
            let result = try resolveProgramStr(&mut a, program);
7530
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7531
        }
7532
    } {
7533
        let mut testArena530 = testArena();
7534
        let testStorage530: 'test530 = &mut testArena530 in {
7535
            let mut a = testResolver(testStorage530);
7536
            let program = "record Marker: Once {} static BAD: &u32 = undefined;";
7537
            let result = try resolveProgramStr(&mut a, program);
7538
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7539
        }
7540
    } {
7541
        let mut testArena531 = testArena();
7542
        let testStorage531: 'test531 = &mut testArena531 in {
7543
            let mut a = testResolver(testStorage531);
7544
            let program = "record Marker: Once {} fn bad(callback: fn() -> &u32) {}";
7545
            let result = try resolveProgramStr(&mut a, program);
7546
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7547
        }
7548
    }
7549
}
7550
7551
/// Function pointer parameter references remain call-scoped and valid.
7552
@test unsafe fn testFunctionPointerRefParameterAllowed() throws (testing::TestError) {
7553
    let program = "record Marker: Once {} fn invoke(callback: fn(&u32), value: &u32) { callback(value); }";
7554
    try expectAnalyzeOk(program);
7555
}
7556
7557
/// Pointer and slice casts cannot change reference ownership.
7558
@test unsafe fn testRefCastClassPreserved() throws (testing::TestError) {
7559
    {
7560
        let mut testArena532 = testArena();
7561
        let testStorage532: 'test532 = &mut testArena532 in {
7562
            let mut a = testResolver(testStorage532);
7563
            let program = "record Marker: Once {} fn cast(value: &u32) { value as *u32; }";
7564
            let result = try resolveProgramStr(&mut a, program);
7565
            let err = try expectError(&result);
7566
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
7567
                else throw testing::TestError::Failed;
7568
        }
7569
    } {
7570
        let mut testArena533 = testArena();
7571
        let testStorage533: 'test533 = &mut testArena533 in {
7572
            let mut a = testResolver(testStorage533);
7573
            let program = "record Marker: Once {} fn cast(values: &[u32]) { values as *[u32]; }";
7574
            let result = try resolveProgramStr(&mut a, program);
7575
            let err = try expectError(&result);
7576
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
7577
                else throw testing::TestError::Failed;
7578
        }
7579
    }
7580
}
7581
7582
/// Every operation that interprets an unsafe address requires an unsafe declaration.
7583
@test unsafe fn testUnsafePointerOperationsRejected() throws (testing::TestError) {
7584
    {
7585
        let mut testArena534 = testArena();
7586
        let testStorage534: 'test534 = &mut testArena534 in {
7587
            let mut a = testResolver(testStorage534);
7588
            let program = "record Marker: Once {} fn cast(pointer: *unsafe u32) -> u64 { return pointer as u64; }";
7589
            let result = try resolveProgramStr(&mut a, program);
7590
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7591
        }
7592
    } {
7593
        let mut testArena535 = testArena();
7594
        let testStorage535: 'test535 = &mut testArena535 in {
7595
            let mut a = testResolver(testStorage535);
7596
            let program = "record Marker: Once {} fn compare(pointer: *unsafe u32) -> bool { return pointer == pointer; }";
7597
            let result = try resolveProgramStr(&mut a, program);
7598
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7599
        }
7600
    } {
7601
        let mut testArena536 = testArena();
7602
        let testStorage536: 'test536 = &mut testArena536 in {
7603
            let mut a = testResolver(testStorage536);
7604
            let program = "record Marker: Once {} fn offset(pointer: *unsafe u32) -> *unsafe u32 { return pointer + 1; }";
7605
            let result = try resolveProgramStr(&mut a, program);
7606
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7607
        }
7608
    } {
7609
        let mut testArena537 = testArena();
7610
        let testStorage537: 'test537 = &mut testArena537 in {
7611
            let mut a = testResolver(testStorage537);
7612
            let program = "record Marker: Once {} fn index(values: *unsafe [u32]) -> u32 { return values[0]; }";
7613
            let result = try resolveProgramStr(&mut a, program);
7614
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7615
        }
7616
    } {
7617
        let mut testArena538 = testArena();
7618
        let testStorage538: 'test538 = &mut testArena538 in {
7619
            let mut a = testResolver(testStorage538);
7620
            let program = "record Marker: Once {} record Cell { value: u32 } fn field(cell: *unsafe Cell) -> u32 { return cell.value; }";
7621
            let result = try resolveProgramStr(&mut a, program);
7622
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7623
        }
7624
    } {
7625
        let mut testArena539 = testArena();
7626
        let testStorage539: 'test539 = &mut testArena539 in {
7627
            let mut a = testResolver(testStorage539);
7628
            let program = "record Marker: Once {} fn store(pointer: *unsafe mut u32) { set *pointer = 1; }";
7629
            let result = try resolveProgramStr(&mut a, program);
7630
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7631
        }
7632
    } {
7633
        let mut testArena540 = testArena();
7634
        let testStorage540: 'test540 = &mut testArena540 in {
7635
            let mut a = testResolver(testStorage540);
7636
            let program = "record Marker: Once {} fn cast() { let value: u32 = 0; let pointer = &value as *unsafe u32; }";
7637
            let result = try resolveProgramStr(&mut a, program);
7638
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7639
        }
7640
    }
7641
}
7642
7643
/// Pointer offsets require an unsafe function for either operand order.
7644
@test unsafe fn testPointerArithmeticRequiresUnsafe() throws (testing::TestError) {
7645
    let programs = &[
7646
        "fn run(p: *u8) -> *u8 { return p + 1; }",
7647
        "fn run(p: *u8) -> *u8 { return 1 + p; }",
7648
        "fn run(p: *u8) -> *u8 { return p - 1; }",
7649
        "fn run(input: *mut u8) { let mut p = input; set p += 1; }",
7650
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let p = &DATA[0]; return *(p + 1); }",
7651
    ];
7652
    for program in programs {
7653
        let mut testArena541 = testArena();
7654
        let testStorage541: 'test541 = &mut testArena541 in {
7655
            let mut a = testResolver(testStorage541);
7656
            let result = try resolveProgramStr(&mut a, program);
7657
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7658
        }
7659
    }
7660
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return p + 1; }");
7661
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return 1 + p; }");
7662
    try expectAnalyzeOk("unsafe fn run(p: *mut u8) -> *mut u8 { return p - 1; }");
7663
    try expectAnalyzeOk("fn run(value: u32) -> u32 { return value + 1; }");
7664
}
7665
7666
/// Casts that reinterpret storage require an unsafe function.
7667
@test unsafe fn testStorageCastsRequireUnsafe() throws (testing::TestError) {
7668
    let programs = &[
7669
        "fn run(p: *u8) -> *u64 { return p as *u64; }",
7670
        "fn run(p: &u8) -> u64 { return *(p as &u64); }",
7671
        "fn run(p: *mut u8) -> *mut u64 { return p as *mut u64; }",
7672
        "fn run(p: *opaque) -> *u64 { return p as *u64; }",
7673
        "fn run(p: **u8) -> **u64 { return p as **u64; }",
7674
        "fn run(s: *[u8]) -> *[u64] { return s as *[u64]; }",
7675
        "fn run(s: *[opaque]) -> *[u64] { return s as *[u64]; }",
7676
        "fn run(s: &mut [u64]) { let _ = s as &mut [u8]; }",
7677
        "static DATA: [u8; 1] = [42]; fn run() -> u64 { return *(&DATA[0] as *u64); }",
7678
    ];
7679
    for program in programs {
7680
        let mut testArena542 = testArena();
7681
        let testStorage542: 'test542 = &mut testArena542 in {
7682
            let mut a = testResolver(testStorage542);
7683
            let result = try resolveProgramStr(&mut a, program);
7684
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7685
        }
7686
    }
7687
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u64 { return p as *u64; }");
7688
    try expectAnalyzeOk("unsafe fn run(p: &u8) -> u64 { return *(p as &u64); }");
7689
    try expectAnalyzeOk("unsafe fn run(s: *[u8]) -> *[u64] { return s as *[u64]; }");
7690
    try expectAnalyzeOk("fn run(p: *u8) -> *u8 { return p as *u8; }");
7691
    try expectAnalyzeOk("fn run(p: *u8) -> *opaque { return p as *opaque; }");
7692
    try expectAnalyzeOk("fn run(s: *[u8]) -> *[opaque] { return s as *[opaque]; }");
7693
    try expectAnalyzeOk("fn run(p: *mut u8) -> *u8 { return p as *u8; }");
7694
}
7695
7696
/// Explicit slice bounds require an unsafe function.
7697
@test unsafe fn testSliceConstructionRequiresUnsafe() throws (testing::TestError) {
7698
    let programs = &[
7699
        "fn run(p: *u8) -> *[u8] { return @sliceOf(p, 100); }",
7700
        "fn run(p: *mut u8) -> *mut [u8] { return @sliceOf(p, 0, 100); }",
7701
        "fn run(p: &u8) -> u8 { return @sliceOf(p, 100)[99]; }",
7702
        "fn run(p: &mut u8) { set @sliceOf(p, 100)[99] = 1; }",
7703
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let s = @sliceOf(&DATA[0], 100); return s[99]; }",
7704
    ];
7705
    for program in programs {
7706
        let mut testArena543 = testArena();
7707
        let testStorage543: 'test543 = &mut testArena543 in {
7708
            let mut a = testResolver(testStorage543);
7709
            let result = try resolveProgramStr(&mut a, program);
7710
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7711
        }
7712
    }
7713
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *[u8] { return @sliceOf(p, 100); }");
7714
    try expectAnalyzeOk("unsafe fn run(p: *mut u8) -> *mut [u8] { return @sliceOf(p, 0, 100); }");
7715
    try expectAnalyzeOk("unsafe fn run(p: &u8) -> u8 { return @sliceOf(p, 1)[0]; }");
7716
    try expectAnalyzeOk("fn run(s: *[u8]) -> *[u8] { return &s[..]; }");
7717
}
7718
7719
/// Slice header writes and mutable field borrows require an unsafe function.
7720
@test unsafe fn testSliceHeaderMutationRequiresUnsafe() throws (testing::TestError) {
7721
    let programs = &[
7722
        "fn run(s: *mut [u8]) { set s.len = 100; }",
7723
        "fn run(s: *mut [u8]) { set s.cap = 100; }",
7724
        "fn run(s: *mut [u8], p: *mut u8) { set s.ptr = p; }",
7725
        "fn run(s: *mut [u8]) { set s.len += 1; }",
7726
        "fn change(n: &mut u32) { set *n = 100; } fn run(s: *mut [u8]) { change(&mut s.len); }",
7727
        "fn change(n: &mut u32) { set *n = 100; } fn run(s: *mut [u8]) { change(&mut s.cap); }",
7728
        "fn change(p: &mut *u8, q: *u8) { set *p = q; } fn run(q: *u8) { let mut s: *[u8] = &[]; change(&mut s.ptr, q); }",
7729
        "fn run(s: &mut *[u8]) { set s.len = 100; }",
7730
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let mut s = &DATA[..]; set s.len = 100; return s[99]; }",
7731
    ];
7732
    for program in programs {
7733
        let mut testArena544 = testArena();
7734
        let testStorage544: 'test544 = &mut testArena544 in {
7735
            let mut a = testResolver(testStorage544);
7736
            let result = try resolveProgramStr(&mut a, program);
7737
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7738
        }
7739
    }
7740
    try expectAnalyzeOk("unsafe fn run(s: *mut [u8]) { set s.len = 0; set s.cap = 0; }");
7741
    try expectAnalyzeOk("unsafe fn run(s: *mut [u8], p: *mut u8) { set s.ptr = p; }");
7742
    try expectAnalyzeOk("fn change(n: &mut u32) { set *n = 0; } unsafe fn run(s: *mut [u8]) { change(&mut s.len); }");
7743
    try expectAnalyzeOk("fn run(s: *mut [u8]) { set s[0] = 1; }");
7744
    try expectAnalyzeOk("record R { len: u32 } fn run(r: &mut R) { set r.len = 1; }");
7745
}
7746
7747
/// Unsafe blocks permit operations within a safe function.
7748
@test unsafe fn testUnsafeBlocksAllowed() throws (testing::TestError) {
7749
    try expectAnalyzeOk("fn run(p: *u8) -> *u8 { unsafe { return p + 1; } }");
7750
    try expectAnalyzeOk("unsafe fn read(p: *unsafe u8) -> u8 { return *p; } fn run(p: *unsafe u8) -> u8 { unsafe { return read(p); } }");
7751
    try expectAnalyzeOk("fn run(p: *u8) -> *[u8] { unsafe { { return @sliceOf(p, 1); } } }");
7752
    try expectAnalyzeOk("fn run(p: *u8) -> *u64 { unsafe { unsafe { return p as *u64; } } }");
7753
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { unsafe {} return p + 1; }");
7754
}
7755
7756
/// Unsafe permission ends at the closing brace and at function boundaries.
7757
@test unsafe fn testUnsafeBlockContextRestored() throws (testing::TestError) {
7758
    let programs = &[
7759
        "fn run(p: *u8) -> *u8 { unsafe { let q = p + 1; } return p + 1; }",
7760
        "fn run(p: *u8) -> *u8 { unsafe { unsafe {} } return p + 1; }",
7761
        "unsafe fn first(p: *u8) -> *u8 { return p + 1; } fn second(p: *u8) -> *u8 { return p + 1; }",
7762
    ];
7763
    for program in programs {
7764
        let mut testArena545 = testArena();
7765
        let testStorage545: 'test545 = &mut testArena545 in {
7766
            let mut a = testResolver(testStorage545);
7767
            let result = try resolveProgramStr(&mut a, program);
7768
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7769
        }
7770
    }
7771
    let mut testArena546 = testArena();
7772
    let testStorage546: 'test546 = &mut testArena546 in {
7773
        let mut a = testResolver(testStorage546);
7774
        let result = try resolveProgramStr(&mut a, "unsafe fn act() {} fn run() { unsafe { act(); } act(); }");
7775
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7776
    }
7777
}
7778
7779
/// Resolution errors do not extend an unsafe block's permission.
7780
@test unsafe fn testUnsafeBlockErrorRestoresContext() throws (testing::TestError) {
7781
    let mut testArena547 = testArena();
7782
    let testStorage547: 'test547 = &mut testArena547 in {
7783
        let mut a = testResolver(testStorage547);
7784
        let result = try resolveProgramStr(&mut a, "fn run(p: *u8) { unsafe { missing; } let q = p + 1; }");
7785
        let mut found = false;
7786
        for err in result.diagnostics.errors {
7787
            if let case super::ErrorKind::UnsafeOperation = err.kind {
7788
                set found = true;
7789
            }
7790
        }
7791
        try testing::expect(found);
7792
    }
7793
}
7794
7795
/// Unsafe blocks preserve reference lifetime checks.
7796
@test unsafe fn testUnsafeBlockPreservesReferences() throws (testing::TestError) {
7797
    let mut testArena548 = testArena();
7798
    let testStorage548: 'test548 = &mut testArena548 in {
7799
        let mut a = testResolver(testStorage548);
7800
        let result = try resolveProgramStr(&mut a, "fn run() { let mut n: u32 = 1; let p = &n; unsafe { set n = 2; } }");
7801
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("n"));
7802
    }
7803
}
7804
7805
/// Slice pointer access requires an unsafe context for every slice class.
7806
@test unsafe fn testSlicePointerRequiresUnsafe() throws (testing::TestError) {
7807
    let programs = &[
7808
        "fn run(s: *[u8]) -> *u8 { return s.ptr; }",
7809
        "fn run(s: *mut [u8]) -> *mut u8 { return s.ptr; }",
7810
        "fn run(s: &[u8]) -> u8 { return *s.ptr; }",
7811
        "fn run(s: &mut [u8]) { set *s.ptr = 1; }",
7812
        "fn run(s: &*[u8]) -> *u8 { return s.ptr; }",
7813
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let s = &DATA[1..]; return *s.ptr; }",
7814
        "fn run(s: *[u8]) -> u64 { return s.ptr as u64; }",
7815
    ];
7816
    for program in programs {
7817
        let mut testArena549 = testArena();
7818
        let testStorage549: 'test549 = &mut testArena549 in {
7819
            let mut a = testResolver(testStorage549);
7820
            let result = try resolveProgramStr(&mut a, program);
7821
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7822
        }
7823
    }
7824
    try expectAnalyzeOk("unsafe fn run(s: *[u8]) -> *u8 { return s.ptr; }");
7825
    try expectAnalyzeOk("fn run(s: *[u8]) -> u64 { unsafe { return s.ptr as u64; } }");
7826
    try expectAnalyzeOk("fn run(s: *[u8]) -> *u8 { return &s[0]; }");
7827
    try expectAnalyzeOk("fn run(s: *[u8]) -> u32 { return s.len + s.cap; }");
7828
    try expectAnalyzeOk("record R { ptr: u32 } fn run(r: R) -> u32 { return r.ptr; }");
7829
}
7830
7831
/// Unsafe statics require unsafe permission for reads, writes, and addresses.
7832
@test unsafe fn testUnsafeStaticAccessRejected() throws (testing::TestError) {
7833
    let programs = &[
7834
        "unsafe static VALUE: u32 = 7; fn run() -> u32 { return VALUE; }",
7835
        "unsafe static VALUE: u32 = 7; fn run() { set VALUE = 8; }",
7836
        "unsafe static VALUE: u32 = 7; fn run() -> *u32 { return &VALUE; }",
7837
        "unsafe static VALUE: u32 = 7; fn run() -> *mut u32 { return &mut VALUE; }",
7838
        "unsafe static DATA: [u8; 1] = [42]; fn run() -> u8 { return DATA[0]; }",
7839
        "unsafe static DATA: [u8; 1] = [42]; fn run() -> u32 { return DATA.len; }",
7840
        "record R { value: u32 } unsafe static DATA: R = R { value: 7 }; fn run() -> u32 { return DATA.value; }",
7841
    ];
7842
    for program in programs {
7843
        let mut testArena550 = testArena();
7844
        let testStorage550: 'test550 = &mut testArena550 in {
7845
            let mut a = testResolver(testStorage550);
7846
            let result = try resolveProgramStr(&mut a, program);
7847
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7848
        }
7849
    }
7850
}
7851
7852
/// Unsafe blocks and functions can access unsafe statics.
7853
@test unsafe fn testUnsafeStaticAccessAllowed() throws (testing::TestError) {
7854
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; unsafe fn run() -> u32 { set VALUE = 8; return VALUE; }");
7855
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; fn run() -> u32 { unsafe { return VALUE; } }");
7856
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; unsafe fn run() -> *mut u32 { return &mut VALUE; }");
7857
    try expectAnalyzeOk("static VALUE: u32 = 7; fn run() -> u32 { return VALUE; }");
7858
    try expectAnalyzeOk("constant BYTES: *[u8] = \"x\"; unsafe static DATA: *[u64] = BYTES as *[u64];");
7859
}
7860
7861
/// Imports preserve the unsafe access requirement of a static.
7862
@test unsafe fn testUnsafeStaticImportsRejected() throws (testing::TestError) {
7863
    let programs = &[
7864
        "use root::storage; fn run() -> u32 { return storage::VALUE; }",
7865
        "use root::storage::*; fn run() -> u32 { return VALUE; }",
7866
    ];
7867
    for program in programs {
7868
        let mut testArena551 = testArena();
7869
        let testStorage551: 'test551 = &mut testArena551 in {
7870
            let mut a = testResolver(testStorage551);
7871
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
7872
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod storage; mod app;", &mut arena);
7873
            let _ = try registerModule(&mut MODULE_GRAPH, rootId, "storage", "export unsafe static VALUE: u32 = 7;", &mut arena);
7874
            let _ = try registerModule(&mut MODULE_GRAPH, rootId, "app", program, &mut arena);
7875
            let result = try resolveModuleTree(&mut a, rootId);
7876
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7877
        }
7878
    }
7879
}
7880
7881
/// An invalid unsafe static initializer does not grant permission to other initializers.
7882
@test unsafe fn testUnsafeStaticInitializerRestoresContext() throws (testing::TestError) {
7883
    let mut testArena552 = testArena();
7884
    let testStorage552: 'test552 = &mut testArena552 in {
7885
        let mut a = testResolver(testStorage552);
7886
        let result = try resolveProgramStr(&mut a, "unsafe static BAD: u32 = true; static DATA: *[u64] = &[1 as u8] as *[u64];");
7887
        let _ = try expectError(&result);
7888
        try testing::expect(not a.inUnsafeContext);
7889
7890
        let mut testArena553 = testArena();
7891
        let testStorage553: 'test553 = &mut testArena553 in {
7892
            let mut b = testResolver(testStorage553);
7893
            let next = try resolveProgramStr(&mut b, "constant BYTES: *[u8] = \"x\"; unsafe static VALUE: u32 = 7; static DATA: *[u64] = BYTES as *[u64];");
7894
            try expectErrorKind(&next, super::ErrorKind::UnsafeOperation);
7895
        }
7896
    }
7897
}
7898
7899
/// Uninitialized values require an explicit unsafe context in every value position.
7900
@test unsafe fn testUndefinedRequiresUnsafe() throws (testing::TestError) {
7901
    let programs = &[
7902
        "fn run() -> u8 { let pointers: [*u8; 1] = undefined; return *pointers[0]; }",
7903
        "fn run() { let n: u32 = undefined; }",
7904
        "fn run() -> *u8 { return undefined; }",
7905
        "fn take(p: *u8) {} fn run() { take(undefined); }",
7906
        "fn run(p: *u8) { let mut q = p; set q = undefined; }",
7907
        "fn run() { let pointers: [*u8; 1] = [undefined]; }",
7908
        "fn run() { let pointers: [*u8; 2] = [undefined; 2]; }",
7909
        "record R: Copy { p: *u8 } fn run() { let r = R { p: undefined }; }",
7910
        "union U: Copy { Value { p: *u8 } } fn run() { let u = U::Value { p: undefined }; }",
7911
        "static P: *u8 = undefined;",
7912
        "constant P: *u8 = undefined;",
7913
        "static DATA: [u8; 4] = undefined;",
7914
        "record R: Copy { p: *u8 } static VALUE: R = R { p: undefined };",
7915
    ];
7916
    for program in programs {
7917
        let mut testArena554 = testArena();
7918
        let testStorage554: 'test554 = &mut testArena554 in {
7919
            let mut a = testResolver(testStorage554);
7920
            let result = try resolveProgramStr(&mut a, program);
7921
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7922
        }
7923
    }
7924
    try expectAnalyzeOk("unsafe fn run() { let p: *u8 = undefined; }");
7925
    try expectAnalyzeOk("fn run() -> u32 { unsafe { let mut n: u32 = undefined; set n = 7; return n; } }");
7926
    try expectAnalyzeOk("unsafe static P: *u8 = undefined;");
7927
    try expectAnalyzeOk("record R: Copy { p: *u8 } unsafe static VALUE: R = R { p: undefined };");
7928
    try expectAnalyzeOk("fn run() { let data: [u8; 4] = [0; 4]; let pointer: ?*u8 = nil; }");
7929
    try expectAnalyzeOk("static DATA: [u8; 4] = [0; 4];");
7930
}
7931
7932
/// Unsafe initialization does not grant permission to subsequent safe expressions.
7933
@test unsafe fn testUndefinedContextRestored() throws (testing::TestError) {
7934
    let mut testArena555 = testArena();
7935
    let testStorage555: 'test555 = &mut testArena555 in {
7936
        let mut a = testResolver(testStorage555);
7937
        let result = try resolveProgramStr(&mut a, "fn run() { unsafe { let p: *u8 = undefined; } let q: *u8 = undefined; }");
7938
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7939
        let mut testArena556 = testArena();
7940
        let testStorage556: 'test556 = &mut testArena556 in {
7941
            let mut b = testResolver(testStorage556);
7942
            let next = try resolveProgramStr(&mut b, "unsafe static P: *u8 = undefined; static Q: *u8 = undefined;");
7943
            try expectErrorKind(&next, super::ErrorKind::UnsafeOperation);
7944
        }
7945
    }
7946
}
7947
7948
/// Unsafe declarations may compose unsafe operations and calls.
7949
@test unsafe fn testUnsafePointerOperationsAllowed() throws (testing::TestError) {
7950
    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); }";
7951
    try expectAnalyzeOk(program);
7952
}
7953
7954
/// Unsafe code may drop a checked reference to an unsafe pointer.
7955
@test unsafe fn testUnsafePointerFromReference() throws (testing::TestError) {
7956
    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); }";
7957
    try expectAnalyzeOk(program);
7958
}
7959
7960
/// Dropping a reference to an unsafe pointer cannot add mutability.
7961
@test unsafe fn testUnsafePointerCastCannotAddMutability() throws (testing::TestError) {
7962
    let mut testArena557 = testArena();
7963
    let testStorage557: 'test557 = &mut testArena557 in {
7964
        let mut a = testResolver(testStorage557);
7965
        let program = "record Marker: Once {} unsafe fn run(value: &u32) { value as *unsafe mut u32; }";
7966
        let result = try resolveProgramStr(&mut a, program);
7967
        let err = try expectError(&result);
7968
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
7969
            else throw testing::TestError::Failed;
7970
    }
7971
}
7972
7973
/// Recursive cast validation cannot hide a checked-to-unsafe transition.
7974
@test unsafe fn testNestedUnsafePointerCastRejected() throws (testing::TestError) {
7975
    let mut testArena558 = testArena();
7976
    let testStorage558: 'test558 = &mut testArena558 in {
7977
        let mut a = testResolver(testStorage558);
7978
        let program = "record Marker: Once {} fn run(value: **u32) { value as **unsafe u32; }";
7979
        let result = try resolveProgramStr(&mut a, program);
7980
        let err = try expectError(&result);
7981
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
7982
            else throw testing::TestError::Failed;
7983
    }
7984
}
7985
7986
/// Unsafe code may drop a checked slice reference to an unsafe slice.
7987
@test unsafe fn testUnsafeSliceFromReference() throws (testing::TestError) {
7988
    let program = "record Marker: Once {} unsafe fn run(values: &[u32]) { let raw: *unsafe [u32] = values as *unsafe [u32]; }";
7989
    try expectAnalyzeOk(program);
7990
}
7991
7992
/// Slice casts cannot add mutability.
7993
@test unsafe fn testSliceCastCannotAddMutability() throws (testing::TestError) {
7994
    let mut testArena559 = testArena();
7995
    let testStorage559: 'test559 = &mut testArena559 in {
7996
        let mut a = testResolver(testStorage559);
7997
        let program = "record Marker: Once {} fn run(values: &[u32]) { values as &mut [u32]; }";
7998
        let result = try resolveProgramStr(&mut a, program);
7999
        let err = try expectError(&result);
8000
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
8001
            else throw testing::TestError::Failed;
8002
    }
8003
}
8004
8005
/// Mutable unsafe receivers do not create checked exclusive loans.
8006
@test unsafe fn testUnsafeReceiverDoesNotBorrowExclusively() throws (testing::TestError) {
8007
    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); }";
8008
    try expectAnalyzeOk(program);
8009
}
8010
8011
/// Unsafe instance-method attributes enable unsafe operations in the body.
8012
@test unsafe fn testUnsafeInstanceMethodBody() throws (testing::TestError) {
8013
    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; } }";
8014
    try expectAnalyzeOk(program);
8015
}
8016
8017
/// Unsafe instance methods cannot implement safe trait contracts.
8018
@test unsafe fn testUnsafeInstanceMethodSafetyMismatch() throws (testing::TestError) {
8019
    let mut testArena560 = testArena();
8020
    let testStorage560: 'test560 = &mut testArena560 in {
8021
        let mut a = testResolver(testStorage560);
8022
        let program = "record Value {} trait Read { fn (&Read) get(); } instance Read for Value { unsafe fn (value: &Value) get() {} }";
8023
        let result = try resolveProgramStr(&mut a, program);
8024
        try expectErrorKind(&result, super::ErrorKind::TraitMethodSafetyMismatch);
8025
    }
8026
}
8027
8028
/// Unsafe trait methods retain their call-site requirement through dispatch.
8029
@test unsafe fn testUnsafeTraitMethodCallRejected() throws (testing::TestError) {
8030
    let mut testArena561 = testArena();
8031
    let testStorage561: 'test561 = &mut testArena561 in {
8032
        let mut a = testResolver(testStorage561);
8033
        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(); }";
8034
        let result = try resolveProgramStr(&mut a, program);
8035
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
8036
    }
8037
}
8038
8039
/// An unsafe callback retains its requirement at an indirect call.
8040
@test unsafe fn testUnsafeCallbackCallRejected() throws (testing::TestError) {
8041
    let mut testArena562 = testArena();
8042
    let testStorage562: 'test562 = &mut testArena562 in {
8043
        let mut a = testResolver(testStorage562);
8044
        let result = try resolveProgramStr(&mut a,
8045
            "fn run(callback: unsafe fn() -> u32) -> u32 { return callback(); }");
8046
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
8047
    }
8048
}
8049
8050
/// An unsafe function cannot enter a safe callback slot.
8051
@test unsafe fn testUnsafeCallbackAssignmentRejected() throws (testing::TestError) {
8052
    let mut testArena563 = testArena();
8053
    let testStorage563: 'test563 = &mut testArena563 in {
8054
        let mut a = testResolver(testStorage563);
8055
        let result = try resolveProgramStr(&mut a,
8056
            "unsafe fn load() -> u32 { return 1; } fn run() { let callback: fn() -> u32 = load; }");
8057
        let err = try expectError(&result);
8058
        let case super::ErrorKind::TypeMismatch(_) = err.kind
8059
            else throw testing::TestError::Failed;
8060
    }
8061
}
8062
8063
/// A safe function can enter an unsafe callback slot.
8064
@test unsafe fn testSafeCallbackIntoUnsafeSlot() throws (testing::TestError) {
8065
    try expectAnalyzeOk(
8066
        "fn load() -> u32 { return 1; } unsafe fn run() -> u32 { let callback: unsafe fn() -> u32 = load; return callback(); }");
8067
}
8068
8069
/// Borrowed callback storage must preserve its function safety type.
8070
@test unsafe fn testBorrowedCallbackSafetyInvariant() throws (testing::TestError) {
8071
    let mut testArena564 = testArena();
8072
    let testStorage564: 'test564 = &mut testArena564 in {
8073
        let mut a = testResolver(testStorage564);
8074
        let result = try resolveProgramStr(&mut a,
8075
            "fn replace(slot: &mut unsafe fn()) {} fn load() {} fn run() { let mut callback: fn() = load; replace(&mut callback); }");
8076
        let err = try expectError(&result);
8077
        let case super::ErrorKind::TypeMismatch(_) = err.kind
8078
            else throw testing::TestError::Failed;
8079
    }
8080
}
8081
8082
/// Referenced storage must preserve its exact element type in every context.
8083
@test unsafe fn testPointerStorageCoercionsRejected() throws (testing::TestError) {
8084
    let programs = &[
8085
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; fn run() { let mut p = &DATA; replace(&mut p); }",
8086
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; unsafe fn run() { let mut p = &DATA; replace(&mut p); }",
8087
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; fn run() { let mut p = &DATA; unsafe { replace(&mut p); } }",
8088
        "fn take(p: *?u32) {} fn run(p: *u32) { take(p); }",
8089
        "unsafe fn take(p: *unsafe mut ?*u8) {} unsafe fn run(p: *unsafe mut *u8) { take(p); }",
8090
        "fn take(p: *[?*u8]) {} fn run(p: *[*u8]) { take(p); }",
8091
        "unsafe fn take(p: *mut [?*u8]) {} unsafe fn run(p: *mut [*u8]) { take(p); }",
8092
        "fn take(p: &mut **u8) {} fn run(p: &mut *mut *u8) { take(p); }",
8093
    ];
8094
    for program in programs {
8095
        let mut testArena565 = testArena();
8096
        let testStorage565: 'test565 = &mut testArena565 in {
8097
            let mut a = testResolver(testStorage565);
8098
            let result = try resolveProgramStr(&mut a, program);
8099
            let err = try expectError(&result);
8100
            let case super::ErrorKind::TypeMismatch(_) = err.kind
8101
                else throw testing::TestError::Failed;
8102
        }
8103
    }
8104
    try expectAnalyzeOk("fn take(p: &mut ?*u8) {} fn run() { let mut p: ?*u8 = nil; take(&mut p); }");
8105
    try expectAnalyzeOk("fn run(p: *mut u8) -> *u8 { return p; }");
8106
    try expectAnalyzeOk("fn run(p: *u8) -> *opaque { return p; }");
8107
}
8108
8109
/// Casts cannot add or remove optionality in referenced storage.
8110
@test unsafe fn testPointerOptionalStorageCastsRejected() throws (testing::TestError) {
8111
    let programs = &[
8112
        "fn run(p: **u8) { p as *?*u8; }",
8113
        "unsafe fn run(p: *mut *u8) { p as *mut ?*u8; }",
8114
        "fn run(p: *mut *u8) { unsafe { p as *mut ?*u8; } }",
8115
        "unsafe fn run(p: *mut ?*u8) { p as *mut *u8; }",
8116
        "unsafe fn run(p: *unsafe mut *u8) { p as *unsafe mut ?*u8; }",
8117
        "unsafe fn run(p: *mut [*u8]) { p as *mut [?*u8]; }",
8118
    ];
8119
    for program in programs {
8120
        let mut testArena566 = testArena();
8121
        let testStorage566: 'test566 = &mut testArena566 in {
8122
            let mut a = testResolver(testStorage566);
8123
            let result = try resolveProgramStr(&mut a, program);
8124
            let err = try expectError(&result);
8125
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
8126
                else throw testing::TestError::Failed;
8127
        }
8128
    }
8129
}
8130
8131
/// Pattern references prevent replacement of their source in every context.
8132
@test unsafe fn testPatternLoanMutationRejected() throws (testing::TestError) {
8133
    let programs = &[
8134
        "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 => {} } }",
8135
        "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 => {} } }",
8136
        "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 => {} } }",
8137
        "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 => {} } }",
8138
        "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; } }",
8139
        "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; } }",
8140
        "union U: Copy { A(u64), B(u64) } fn run(u: *mut U) { match u { case U::A(p) => { let moved = u; *p; } else => {} } }",
8141
        "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 => {} } }",
8142
        "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 => {} } }",
8143
    ];
8144
    for program in programs {
8145
        let mut testArena567 = testArena();
8146
        let testStorage567: 'test567 = &mut testArena567 in {
8147
            let mut a = testResolver(testStorage567);
8148
            let result = try resolveProgramStr(&mut a, program);
8149
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
8150
        }
8151
    }
8152
}
8153
8154
/// Pattern loans end at their scope and permit writes through mutable payload references.
8155
@test unsafe fn testPatternLoanScopeAllowed() throws (testing::TestError) {
8156
    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); }");
8157
    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); }");
8158
    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); }");
8159
}
8160
8161
/// Replacing a borrowed pointer payload cannot forge an address.
8162
@test unsafe fn testBorrowedPointerPayloadReplacementRejected() throws (testing::TestError) {
8163
    let programs = &[
8164
        "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, } }",
8165
        "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, } }",
8166
    ];
8167
    for program in programs {
8168
        let mut testArena568 = testArena();
8169
        let testStorage568: 'test568 = &mut testArena568 in {
8170
            let mut a = testResolver(testStorage568);
8171
            let result = try resolveProgramStr(&mut a, program);
8172
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
8173
        }
8174
    }
8175
}
8176
8177
/// Guards, nested patterns, and unsafe calls must preserve pattern source storage.
8178
@test unsafe fn testPatternLoanIndirectMutationRejected() throws (testing::TestError) {
8179
    let programs = &[
8180
        "fn run() { let mut u: ?u64 = 7; match &u { p => { set u = nil; *p; } else => {} } }",
8181
        "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 => {} } }",
8182
        "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 => {} } }",
8183
        "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 => {} } }",
8184
        "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 => {} } }",
8185
        "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 => {} } }",
8186
    ];
8187
    for program in programs {
8188
        let mut testArena569 = testArena();
8189
        let testStorage569: 'test569 = &mut testArena569 in {
8190
            let mut a = testResolver(testStorage569);
8191
            let result = try resolveProgramStr(&mut a, program);
8192
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
8193
        }
8194
    }
8195
}
8196
8197
/// Binding mutability does not permit writes through immutable pointers.
8198
@test unsafe fn testMutableBindingImmutableTargetRejected() throws (testing::TestError) {
8199
    let programs = &[
8200
        "record R: Copy { n: u8 } fn run(input: *R) { let mut p = input; set p.n = 1; }",
8201
        "record R: Copy { n: u8 } fn run(input: *R) { let mut p = input; let q = &mut p.n; }",
8202
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; set p[0] = 1; }",
8203
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; set p[..] = 1; }",
8204
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; let q = &mut p[0]; }",
8205
        "record R: Copy { n: u8 } fn (r: &mut R) change() { set r.n = 1; } fn run(input: *R) { let mut p = input; p.change(); }",
8206
        "fn run(p: *mut u8, q: *mut u8) { set p = q; }",
8207
    ];
8208
    for program in programs {
8209
        let mut testArena570 = testArena();
8210
        let testStorage570: 'test570 = &mut testArena570 in {
8211
            let mut a = testResolver(testStorage570);
8212
            let result = try resolveProgramStr(&mut a, program);
8213
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
8214
        }
8215
    }
8216
}
8217
8218
/// Mutable targets support access through fixed and mutable pointer bindings.
8219
@test unsafe fn testMutablePointerTargetsAllowed() throws (testing::TestError) {
8220
    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; }");
8221
    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; }");
8222
    try expectAnalyzeOk("fn run(first: *u8, second: *u8) { let mut p = first; set p = second; }");
8223
}
8224
8225
/// Pattern access through raw pointers requires an unsafe context.
8226
@test unsafe fn testRawPointerPatternRejected() throws (testing::TestError) {
8227
    let programs = &[
8228
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { match p { case U::A(n) => { *n; } else => {} } }",
8229
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { if let case U::A(n) = p { *n; } }",
8230
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { while let case U::A(n) = p { *n; break; } }",
8231
        "record R: Copy { n: u8 } fn run(p: *unsafe R) { let case R { n } = p else return; }",
8232
    ];
8233
    for program in programs {
8234
        let mut testArena571 = testArena();
8235
        let testStorage571: 'test571 = &mut testArena571 in {
8236
            let mut a = testResolver(testStorage571);
8237
            let result = try resolveProgramStr(&mut a, program);
8238
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
8239
        }
8240
    }
8241
}
8242
8243
/// Unsafe contexts permit pattern access through raw pointers.
8244
@test unsafe fn testRawPointerPatternsAllowed() throws (testing::TestError) {
8245
    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; } }");
8246
    try expectAnalyzeOk("record R: Copy { n: u8 } unsafe fn run(p: *unsafe R) { let case R { n } = p else return; }");
8247
}
8248
8249
/// Slice append requires the allocator layout and callback signature.
8250
@test unsafe fn testSliceAppendAllocatorRejected() throws (testing::TestError) {
8251
    let programs = &[
8252
        "record A {} fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8253
        "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8254
        "record A(fn(*mut opaque, u32, u32) -> *mut opaque, *mut opaque); fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8255
        "fn run(s: *mut [u8]) { s.append(1, 0); }",
8256
        "record A { ctx: *mut opaque, func: fn(*mut opaque, u32, u32) -> *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8257
        "record A { func: u64, ctx: u64 } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8258
        "record A { func: fn(*mut opaque, u64, u32) -> *mut opaque, ctx: *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8259
        "record A { func: fn(*mut opaque, u32, u32) -> *opaque, ctx: *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8260
        "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: u64 } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
8261
        "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); }",
8262
    ];
8263
    for program in programs {
8264
        let mut testArena572 = testArena();
8265
        let testStorage572: 'test572 = &mut testArena572 in {
8266
            let mut a = testResolver(testStorage572);
8267
            let result = try resolveProgramStr(&mut a, program);
8268
            try expectErrorKind(&result, super::ErrorKind::InvalidSliceAllocator);
8269
        }
8270
    }
8271
}
8272
8273
/// Slice allocators can use raw context pointers.
8274
@test unsafe fn testSliceAppendRawContextAllowed() throws (testing::TestError) {
8275
    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); }");
8276
}
8277
8278
/// A live pattern reference protects its payload from writes through copied pointers.
8279
@test unsafe fn testPatternPayloadPointerAliasesRejected() throws (testing::TestError) {
8280
    let programs = &[
8281
        "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 => {} } }",
8282
        "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, } }",
8283
        "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; } }",
8284
        "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; } }",
8285
    ];
8286
    for program in programs {
8287
        let mut testArena573 = testArena();
8288
        let testStorage573: 'test573 = &mut testArena573 in {
8289
            let mut a = testResolver(testStorage573);
8290
            let result = try resolveProgramStr(&mut a, program);
8291
            let _ = try expectError(&result);
8292
        }
8293
    }
8294
}
8295
8296
/// Every access to a moved safe mutable pointer is rejected.
8297
@test unsafe fn testMutablePointerMovesRejected() throws (testing::TestError) {
8298
    let programs = &[
8299
        "fn run(p: *mut u8) { let q = p; *p; }",
8300
        "fn run(p: *mut u8) { let q = p; set *p = 1; }",
8301
        "fn run(p: *mut u8) { let q = p; let r = &*p; }",
8302
        "fn read(p: &u8) {} fn run(p: *mut u8) { let q = p; read(p); }",
8303
        "fn run(p: &mut u8) { let q = p; *p; }",
8304
        "fn run(p: *mut [u8]) { let q = p; p.len; }",
8305
        "fn run(p: &mut [u8]) { let q = p; p[0]; }",
8306
        "record R { value: u8 } fn run(p: *mut R) { let q = p; p.value; }",
8307
        "trait T { fn (&T) read(); } fn run(p: *mut opaque T) { let q = p; p.read(); }",
8308
        "fn run(p: *mut u8, flag: bool) { if flag { let q = p; } *p; }",
8309
        "fn run(p: *mut u8) { loop { let q = p; } }",
8310
    ];
8311
    for program in programs {
8312
        let mut testArena574 = testArena();
8313
        let testStorage574: 'test574 = &mut testArena574 in {
8314
            let mut a = testResolver(testStorage574);
8315
            let result = try resolveProgramStr(&mut a, program);
8316
            let _ = try expectError(&result);
8317
        }
8318
    }
8319
}
8320
8321
/// Copy composites cannot contain safe mutable owners or their containers.
8322
@test unsafe fn testCopyMutablePointerFieldsRejected() throws (testing::TestError) {
8323
    let programs = &[
8324
        "record R: Copy { p: *mut u8 }",
8325
        "union U: Copy { A(*mut u8), B }",
8326
        "record R: Copy { p: ?*mut u8 }",
8327
        "record R: Copy { p: [*mut u8; 2] }",
8328
        "record R: Copy { p: *mut [u8] }",
8329
        "trait T {} record R: Copy { p: *mut opaque T }",
8330
        "record Inner { p: *mut u8 } record Outer: Copy { inner: Inner }",
8331
    ];
8332
    for program in programs {
8333
        let mut testArena575 = testArena();
8334
        let testStorage575: 'test575 = &mut testArena575 in {
8335
            let mut a = testResolver(testStorage575);
8336
            let result = try resolveProgramStr(&mut a, program);
8337
            try expectErrorKind(&result, super::ErrorKind::CopyContainsNonCopy);
8338
        }
8339
    }
8340
}
8341
8342
/// Moves transfer safe mutable pointers, and calls can borrow them temporarily.
8343
@test unsafe fn testMutablePointerMovesAllowed() throws (testing::TestError) {
8344
    try expectAnalyzeOk("fn run(p: *mut u8) -> u8 { let q = p; set *q = 1; return *q; }");
8345
    try expectAnalyzeOk("fn setValue(p: &mut u8) { set *p = 1; } fn run(p: *mut u8) { setValue(p); setValue(p); *p; }");
8346
    try expectAnalyzeOk("fn run(p: *u8) { let q = p; *p; *q; }");
8347
    try expectAnalyzeOk("fn run(p: *mut u8, q: *mut u8) { unsafe { p == q; p as u64; } set *p = 1; set *q = 2; }");
8348
    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; }");
8349
    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; }");
8350
}
8351
8352
/// Function signature inspection uses immutable descriptors in safe code.
8353
fn expectImmutableFunctionSignatures 'arena (res: &super::Resolver 'arena, root: *ast::Node) throws (testing::TestError) {
8354
    let first = try typeOf(res, try getBlockStmt(root, 0));
8355
    let equivalent = try typeOf(res, try getBlockStmt(root, 1));
8356
    let throwing = try typeOf(res, try getBlockStmt(root, 2));
8357
    let unsafeCall = try typeOf(res, try getBlockStmt(root, 3));
8358
    try testing::expect(super::typesEqual(first, equivalent));
8359
    try testing::expect(not super::typesEqual(first, throwing));
8360
    try testing::expect(not super::typesEqual(first, unsafeCall));
8361
}
8362
8363
/// Local analysis state does not change function signature identity.
8364
@test unsafe fn testImmutableFunctionSignatures() throws (testing::TestError) {
8365
    let mut testArena576 = testArena();
8366
    let testStorage576: 'test576 = &mut testArena576 in {
8367
        let mut res = testResolver(testStorage576);
8368
        let result = try resolveProgramStr(&mut res,
8369
            "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; }");
8370
        try expectNoErrors(&result);
8371
        try expectImmutableFunctionSignatures(&res, result.root);
8372
    }
8373
}
8374
8375
/// A diagnostic snapshot keeps its contents when the resolver buffer changes.
8376
@test unsafe fn testDiagnosticSnapshotOwnsItsErrors() throws (testing::TestError) {
8377
    let mut testArena577 = testArena();
8378
    let testStorage577: 'test577 = &mut testArena577 in {
8379
        let mut res = testResolver(testStorage577);
8380
        let result = try resolveProgramStr(&mut res, "fn run() { missing; }");
8381
        let snapshot = result.diagnostics;
8382
        let original = super::errorAt(snapshot.errors, 0) else throw testing::TestError::Failed;
8383
        set res.errors.entries[0] = super::Error {
8384
            kind: super::ErrorKind::Internal, node: nil, moduleId: 0,
8385
        };
8386
        let later = super::diagnostics(&mut res);
8387
        try testing::expect(snapshot.errors.len == 1);
8388
        try testing::expect(later.errors.len == 1);
8389
        let first = super::errorAt(snapshot.errors, 0) else throw testing::TestError::Failed;
8390
        try testing::expect(first.kind == original.kind);
8391
        try testing::expect(later.errors[0].kind == super::ErrorKind::Internal);
8392
        try testing::expect(super::errorAt(snapshot.errors, 1) == nil);
8393
    }
8394
}
8395
8396
/// Prefixes, equal fields, and uncertain element locations must conflict.
8397
@test unsafe fn testOverlappingFieldBorrows() throws (testing::TestError) {
8398
    let programs = &[
8399
        "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); }",
8400
        "record R: Copy { a: u32, b: u32 } fn take(a: &mut R, b: &u32) {} fn run(r: &mut R) { take(r, &r.b); }",
8401
        "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]); }",
8402
        "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); }",
8403
    ];
8404
    for program in programs {
8405
        let mut testArena578 = testArena();
8406
        let testStorage578: 'test578 = &mut testArena578 in {
8407
            let mut a = testResolver(testStorage578);
8408
            let result = try resolveProgramStr(&mut a, program);
8409
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8410
        }
8411
    }
8412
}
8413
8414
/// Local loans exclude writes, competing references, and source reads.
8415
@test unsafe fn testLocalReferenceConflicts() throws (testing::TestError) {
8416
    let programs = &[
8417
        "fn run() { let mut n: u32 = 4; let p = &n; set n = 1; }",
8418
        "fn run() { let mut n: u32 = 4; let p = &mut n; n; }",
8419
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &n; }",
8420
        "fn run() { let mut n: u32 = 4; let p = &n; let q = &mut n; }",
8421
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &mut *p; set *p = 1; }",
8422
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &*p; set *p = 1; }",
8423
        "fn take(p: &mut u32) {} fn run() { let mut n: u32 = 4; let p = &n; take(&mut n); }",
8424
        "fn run() { let mut n: u32 = 4; let p = &n; unsafe { set n = 1; } }",
8425
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &*p; let moved = p; }",
8426
    ];
8427
    for program in programs {
8428
        let mut testArena579 = testArena();
8429
        let testStorage579: 'test579 = &mut testArena579 in {
8430
            let mut a = testResolver(testStorage579);
8431
            let result = try resolveProgramStr(&mut a, program);
8432
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("n"));
8433
        }
8434
    }
8435
}
8436
8437
/// Reference bindings cannot outlive temporary storage or change their source.
8438
@test unsafe fn testLocalReferenceStorage() throws (testing::TestError) {
8439
    let programs = &[
8440
        "fn f 'r (p: &'r mut u32) { let mut cursor = p; }",
8441
        "unsafe fn f 'r (p: &'r mut u32) { let mut cursor = p; }",
8442
        "fn run() { let n: u32 = 4; let mut p: &u32 = &n; }",
8443
        "record R: Copy { n: u32 } fn make() -> R { return R { n: 4 }; } fn run() { let p: &u32 = &make().n; }",
8444
    ];
8445
    for program in programs {
8446
        let mut testArena580 = testArena();
8447
        let testStorage580: 'test580 = &mut testArena580 in {
8448
            let mut a = testResolver(testStorage580);
8449
            let result = try resolveProgramStr(&mut a, program);
8450
            try expectErrorKind(&result, super::ErrorKind::RefBinding);
8451
        }
8452
    }
8453
}
8454
8455
/// Stored and returned values cannot contain a local reference.
8456
@test unsafe fn testLocalReferenceEscapeRejected() throws (testing::TestError) {
8457
    let programs = &[
8458
        "fn run() -> *u32 { let n: u32 = 1; let p = &n; return p; }",
8459
        "fn run() -> *u32 { let n: u32 = 1; let p = &n; return p as *u32; }",
8460
        "static DATA: u32 = 0; static P: *u32 = &DATA; fn run() { let n: u32 = 1; let p = &n; set P = p; }",
8461
        "record R: Copy { p: *u32 } fn run() { let n: u32 = 1; let p = &n; let r = R { p }; }",
8462
    ];
8463
    for program in programs {
8464
        let mut testArena581 = testArena();
8465
        let testStorage581: 'test581 = &mut testArena581 in {
8466
            let mut a = testResolver(testStorage581);
8467
            let result = try resolveProgramStr(&mut a, program);
8468
            let _ = try expectError(&result);
8469
        }
8470
    }
8471
}
8472
8473
/// Pointer indirection cannot prove that sibling pointees are disjoint.
8474
@test unsafe fn testIndirectFieldBorrowConflict() throws (testing::TestError) {
8475
    let programs = &[
8476
        "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); }",
8477
        "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; }",
8478
    ];
8479
    for program in programs {
8480
        let mut testArena582 = testArena();
8481
        let testStorage582: 'test582 = &mut testArena582 in {
8482
            let mut a = testResolver(testStorage582);
8483
            let result = try resolveProgramStr(&mut a, program);
8484
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8485
        }
8486
    }
8487
}
8488
8489
/// Pattern references protect their field and permit writes to disjoint fields.
8490
@test unsafe fn testDisjointPatternFieldBorrow() throws (testing::TestError) {
8491
    let mut testArena583 = testArena();
8492
    let testStorage583: 'test583 = &mut testArena583 in {
8493
        let mut a = testResolver(testStorage583);
8494
        let result = try resolveProgramStr(&mut a,
8495
            "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 => {} } }");
8496
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8497
    }
8498
}
8499
8500
/// Slice mutations must preserve storage held by a local reference.
8501
@test unsafe fn testLocalReferenceSliceMutationRejected() throws (testing::TestError) {
8502
    let programs = &[
8503
        "fn run(s: *mut [u8]) { let p: &u8 = &s[0]; s.delete(0); }",
8504
        "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); }",
8505
    ];
8506
    for program in programs {
8507
        let mut testArena584 = testArena();
8508
        let testStorage584: 'test584 = &mut testArena584 in {
8509
            let mut a = testResolver(testStorage584);
8510
            let result = try resolveProgramStr(&mut a, program);
8511
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("s"));
8512
        }
8513
    }
8514
}
8515
8516
/// Owner moves and mutable methods cannot invalidate a local loan.
8517
@test unsafe fn testLocalReferenceOwnerMutationRejected() throws (testing::TestError) {
8518
    let programs = &[
8519
        "fn run(p: *mut u32) { let r: &u32 = &*p; let moved = p; }",
8520
        "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(); }",
8521
    ];
8522
    for program in programs {
8523
        let mut testArena585 = testArena();
8524
        let testStorage585: 'test585 = &mut testArena585 in {
8525
            let mut a = testResolver(testStorage585);
8526
            let result = try resolveProgramStr(&mut a, program);
8527
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("p"));
8528
        }
8529
    }
8530
}
8531
8532
/// Reference locals require a function scope and a reachable initializer result.
8533
@test unsafe fn testLocalReferenceDeclarationContext() throws (testing::TestError) {
8534
    let mut testArena586 = testArena();
8535
    let testStorage586: 'test586 = &mut testArena586 in {
8536
        let mut a = testResolver(testStorage586);
8537
        let result = try resolveProgramStr(&mut a, "let n: u32 = 1; let p: &u32 = &n;");
8538
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
8539
    }
8540
}
8541
8542
/// Test-only imports do not require their modules in a normal build.
8543
@test unsafe fn testConditionalUse() throws (testing::TestError) {
8544
    let mut testArena587 = testArena();
8545
    let testStorage587: 'test587 = &mut testArena587 in {
8546
        let mut a = testResolver(testStorage587);
8547
        set a.config.buildTest = false;
8548
        let source = "@test use missing::testing; fn value() -> u32 { return 1; }";
8549
        let result = try resolveProgramStr(&mut a, source);
8550
        try expectNoErrors(&result);
8551
        set a.config.buildTest = true;
8552
        let enabled = try resolveProgramStr(&mut a, source);
8553
        try testing::expect(enabled.diagnostics.errors.len > 0);
8554
    }
8555
}
8556
8557
/// Retained module identities are accessible through safe lookup.
8558
fn checkModuleQueries 'arena (
8559
    res: &super::Resolver 'arena, root: u16, child: u16
8560
) throws (testing::TestError) {
8561
    let rootEntry = super::moduleFor(res, root) else throw testing::TestError::Failed;
8562
    let childEntry = super::moduleFor(res, child) else throw testing::TestError::Failed;
8563
    assert rootEntry.id == root;
8564
    assert childEntry.id == child;
8565
    let parent = childEntry.parent else throw testing::TestError::Failed;
8566
    assert parent == root;
8567
    try testing::expectBytesEq(rootEntry.name, "root");
8568
    try testing::expectBytesEq(childEntry.name, "child");
8569
    if let _ = super::moduleFor(res, 0xffff) {
8570
        throw testing::TestError::Failed;
8571
    }
8572
}
8573
8574
/// Module identities remain valid independently of the graph container.
8575
@test unsafe fn testSafeModuleQueries() throws (testing::TestError) {
8576
    let mut arena = testArena();
8577
    let storage: 'test = &mut arena in {
8578
        let mut res = testResolver(storage);
8579
        if let _ = super::moduleFor(&res, 0) {
8580
            throw testing::TestError::Failed;
8581
        }
8582
        let root = try! module::registerRootWithName(&mut MODULE_GRAPH, &mut STRING_POOL, 0, "root", "/root.rad");
8583
        let child = try! module::registerChild(&mut MODULE_GRAPH, &mut STRING_POOL, root, "child", "/child.rad");
8584
        let diagnostics = try! super::resolve(&mut res, &MODULE_GRAPH, &[]);
8585
        assert super::success(&diagnostics);
8586
        set MODULE_GRAPH.entriesLen = 0;
8587
        set MODULE_ENTRIES[root as u32] = nil;
8588
        set MODULE_ENTRIES[child as u32] = nil;
8589
        try checkModuleQueries(&res, root, child);
8590
        let empty = try! super::resolve(&mut res, &MODULE_GRAPH, &[]);
8591
        assert super::success(&empty);
8592
        if let _ = super::moduleFor(&res, root) {
8593
            throw testing::TestError::Failed;
8594
        }
8595
    }
8596
}
8597
8598
/// Resolver metadata retains its caller's arena when the context moves.
8599
unsafe fn relocateResolver 'arena (context: super::Resolver 'arena) -> super::Resolver 'arena {
8600
    return context;
8601
}
8602
8603
@test unsafe fn testResolverRelocation() throws (testing::TestError) {
8604
    static DATA: [u8; 65536] = [0; 65536];
8605
    static AST_DATA: [u8; 8192] = [0; 8192];
8606
    static NODES: [super::NodeData; 128] = undefined;
8607
    static ERRORS: [super::Error; 8] = undefined;
8608
    static SCOPE: super::Scope = undefined;
8609
    static POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
8610
    let mut arena = alloc::new(&mut DATA[..]);
8611
    let mut astArena = ast::nodeArena(&mut AST_DATA[..]);
8612
    let root = try! parser::parse(scanner::SourceLoc::String,
8613
        "fn answer() -> u32 { return 42; }", &mut astArena, &mut POOL);
8614
    let storage = super::ResolverStorage {
8615
        nodeData: &mut NODES[..], pkgScope: &mut SCOPE, errors: &mut ERRORS[..],
8616
    };
8617
    let arenaRef: 'arena = &mut arena in {
8618
        let context = super::resolver(arenaRef, storage, super::Config { buildTest: false });
8619
        let initialized = alloc::used(context.arena);
8620
        try testing::expect(initialized > 0);
8621
        let mut moved = relocateResolver(context);
8622
        let diagnostics = try! super::resolveModuleRoot(&mut moved, root);
8623
        try testing::expect(super::success(&diagnostics));
8624
        try testing::expect(alloc::used(moved.arena) > initialized);
8625
        try testing::expect(moved.arena.offset == alloc::used(moved.arena));
8626
        let output = try! alloc::alloc(&mut *moved.arena, @sizeOf(u32), @alignOf(u32)) as *mut u32;
8627
        set *output = 42;
8628
        try testing::expect(*output == 42);
8629
    }
8630
}