lib/std/lang/resolver/tests.rad 383.5 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
/// Synthetic file path used for resolver tests.
17
constant MODULE_PATH: *[u8] = "/dev/test.rad";
18
19
/// AST arena storage used by resolver tests.
20
static AST_ARENA: [u8; 2097152] = [0; 2097152];
21
22
/// Resolver arena storage used by resolver tests.
23
static ARENA_STORAGE: [u8; 2097152] = [0; 2097152];
24
25
/// Node metadata storage used by resolver tests.
26
unsafe static NODE_DATA_STORAGE: [super::NodeData; 256] = undefined;
27
28
/// Diagnostic storage used by resolver tests.
29
unsafe static ERROR_STORAGE: [super::Error; 16] = undefined;
30
31
/// Package scope used by resolver tests.
32
unsafe static PKG_SCOPE: super::Scope = undefined;
33
34
/// Module entries used by resolver tests.
35
unsafe static MODULE_ENTRIES: [?*module::ModuleEntry; 8] = [nil; 8];
36
37
/// Module graph used by resolver tests.
38
unsafe static MODULE_GRAPH: module::ModuleGraph = undefined;
39
40
/// Module AST arena storage used by resolver tests.
41
static MODULE_ARENA_STORAGE: [u8; 16384] = [0; 16384];
42
43
/// Module AST arena used by resolver tests.
44
unsafe static MODULE_ARENA: ast::NodeArena = undefined;
45
46
/// Interned string pool used by resolver tests.
47
unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
48
49
/// String literals used in tests.
50
constant LITERALS: [*[u8]; 15] = [
51
    "Ok", "Error", "R", "S",
52
    "f", "Status", "Pending",
53
    "Some", "None", "First",
54
    "Second", "Opt", "x",
55
    "value", "idx"
56
];
57
58
/// Resolver result with AST, used by test helpers.
59
export record TestResult: Copy {
60
    /// Diagnostics from semantic analysis.
61
    diagnostics: super::Diagnostics,
62
    /// Root of the parsed test program.
63
    root: *ast::Node,
64
}
65
66
/// Create isolated storage for tests to avoid conflicts with global resolver storage.
67
unsafe fn testStorage() -> super::ResolverStorage {
68
    return super::ResolverStorage {
69
        nodeData: &mut NODE_DATA_STORAGE[..],
70
        pkgScope: &mut PKG_SCOPE,
71
        errors: &mut ERROR_STORAGE[..],
72
    };
73
}
74
75
/// Create an arena owner for one resolver test scope.
76
export unsafe fn testArena() -> alloc::Arena {
77
    return alloc::new(&mut ARENA_STORAGE[..]);
78
}
79
80
/// Construct a resolver backed by test storage and a synthetic module graph.
81
export unsafe fn testResolver 'arena (arena: &'arena mut alloc::Arena) -> super::Resolver 'arena {
82
    // TODO: This should be initialized only once.
83
    for i in 0..LITERALS.len {
84
        strings::intern(&mut STRING_POOL, LITERALS[i]);
85
    }
86
    // TODO: Use local static for this.
87
    // Reset the module graph for each test.
88
    set MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]);
89
    set MODULE_GRAPH = module::moduleGraph(&mut MODULE_ENTRIES[..], &mut MODULE_ARENA);
90
    let config = super::Config { buildTest: true };
91
    let res = super::resolver(arena, testStorage(), config);
92
93
    return res;
94
}
95
96
/// Resolve a block of statements by wrapping them in a synthetic function.
97
unsafe fn resolveStatements 'arena (
98
    self: &mut super::Resolver 'arena, block: ast::Block, arena: &mut ast::NodeArena
99
) -> TestResult throws (super::ResolveError) {
100
    let module = ast::synthFnModule(arena, super::ANALYZE_BLOCK_FN_NAME, block.statements);
101
    let diagnostics = try super::resolveModuleRoot(self, module.modBody) catch {
102
        return TestResult { diagnostics: super::diagnostics(self), root: module.modBody };
103
    };
104
    return TestResult { diagnostics, root: module.fnBody };
105
}
106
107
/// Parse and analyze an expression string for testing.
108
unsafe fn resolveExprStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
109
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
110
    let mut p = parser::mkParser(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL);
111
    parser::advance(&mut p);
112
113
    let expr = try parser::parseExpr(&mut p) catch {
114
        panic "resolveExprStr: parsing failed";
115
    };
116
    let diagnostics = try super::resolveExpr(self, expr, &mut arena) catch {
117
        throw testing::TestError::Failed;
118
    };
119
    return TestResult { diagnostics, root: expr };
120
}
121
122
/// Parse and analyze a module string for testing.
123
/// Use this for code with `fn`, `record`, `union`, etc. at the top level.
124
export unsafe fn resolveProgramStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
125
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
126
    let stmt: *ast::Node = try parser::parse(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL) catch {
127
        panic "resolveProgramStr: parsing failed";
128
    };
129
    let diagnostics = try super::resolveModuleRoot(self, stmt) catch {
130
        throw testing::TestError::Failed;
131
    };
132
    return TestResult { diagnostics, root: stmt };
133
}
134
135
/// Resolve session diagnostics against the standard allocator declaration contract.
136
export unsafe fn resolveSessionProgramStr 'arena (self: &mut super::Resolver 'arena, program: *[u8]) -> TestResult
137
    throws (testing::TestError)
138
{
139
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
140
    let root = try registerModule(&mut MODULE_GRAPH, nil, "std", "export mod lang; mod app;", &mut arena);
141
    let lang = try registerModule(&mut MODULE_GRAPH, root, "lang", "export mod alloc;", &mut arena);
142
    let allocator = try registerModule(&mut MODULE_GRAPH, lang, "alloc",
143
        "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; } }",
144
        &mut arena);
145
    let app = try registerModule(&mut MODULE_GRAPH, root, "app", program, &mut arena);
146
    return try resolveModuleTree(self, root);
147
}
148
149
/// Parse and analyze a block of statements (eg. inside a function body) for testing.
150
/// Use this for code with `let` bindings and expressions, not module-level declarations.
151
unsafe fn resolveBlockStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) {
152
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
153
    let parsed = try parser::parse(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL) catch {
154
        panic "resolveBlockStr: parsing failed";
155
    };
156
    let case ast::NodeValue::Block(block) = parsed.value
157
        else panic "resolveBlockStr: expected block root";
158
159
    let analysis = try resolveStatements(self, block, &mut arena) catch {
160
        throw testing::TestError::Failed;
161
    };
162
    return TestResult {
163
        diagnostics: analysis.diagnostics,
164
        root: analysis.root,
165
    };
166
}
167
168
/// Resolve a module with the full resolution process.
169
unsafe fn resolveModuleTree 'arena (
170
    res: &mut super::Resolver 'arena,
171
    rootId: u16
172
) -> TestResult throws (testing::TestError) {
173
    let root = module::get(&MODULE_GRAPH, rootId)
174
        else throw testing::TestError::Failed;
175
    let rootAst = module::astFor(root)
176
        else throw testing::TestError::Failed;
177
    let packages = [super::Pkg {
178
        rootEntry: root,
179
        rootAst,
180
    }];
181
    let diagnostics = try super::resolve(res, &MODULE_GRAPH, &packages[..]) catch {
182
        throw testing::TestError::Failed;
183
    };
184
    return TestResult { diagnostics, root: rootAst };
185
}
186
187
/// Register a module in the graph and attach a parsed AST to it.
188
/// If parentId is nil, registers as a root module.
189
unsafe fn registerModule(
190
    graph: &mut module::ModuleGraph,
191
    parentId: ?u16,
192
    name: *[u8],
193
    code: *[u8],
194
    arena: &mut ast::NodeArena
195
) -> u16 throws (testing::TestError) {
196
    let filePath = "<test>";
197
    let mut modId: u16 = undefined;
198
    if let parent = parentId {
199
        set modId = try module::registerChild(graph, &mut STRING_POOL, parent, name, filePath) catch {
200
            throw testing::TestError::Failed;
201
        };
202
    } else {
203
        set modId = try module::registerRootWithName(graph, &mut STRING_POOL, 0, name, filePath) catch {
204
            throw testing::TestError::Failed;
205
        };
206
    }
207
    let root = try parser::parse(scanner::SourceLoc::String, code, arena, &mut STRING_POOL) catch {
208
        panic "registerModule: parsing failed";
209
    };
210
    try module::setAst(graph, modId, root) catch {
211
        panic "registerModule: module not found";
212
    };
213
    return modId;
214
}
215
216
/// Ensure an expression statement produces the expected type and return the expression node.
217
fn expectExprStmtType 'arena (self: &super::Resolver 'arena, node: *ast::Node, expected: super::Type) -> *ast::Node
218
    throws (testing::TestError)
219
{
220
    let case ast::NodeValue::ExprStmt(expr) = node.value
221
        else throw testing::TestError::Failed;
222
    try expectType(self, expr, expected);
223
224
    return expr;
225
}
226
227
/// Assert that the test result contains no diagnostic errors.
228
export fn expectNoErrors(r: &TestResult) throws (testing::TestError) {
229
    try testing::expect(super::success(&r.diagnostics));
230
}
231
232
/// Extract the first error from a test result, failing if none exists.
233
export fn expectError(result: &TestResult) -> super::Error throws (testing::TestError) {
234
    let err = super::errorAt(&result.diagnostics.errors[..], 0)
235
        else throw testing::TestError::Failed;
236
    return err;
237
}
238
239
/// Check if two error kinds match.
240
fn errorKindMatches(actual: &super::ErrorKind, expected: super::ErrorKind) -> bool {
241
    if let case super::ErrorKind::DuplicateBinding(expectedName) = expected {
242
        if let case super::ErrorKind::DuplicateBinding(actualName) = *actual {
243
            return mem::eq(actualName, expectedName);
244
        }
245
        return false;
246
    }
247
    if let case super::ErrorKind::UnresolvedSymbol(expectedName) = expected {
248
        if let case super::ErrorKind::UnresolvedSymbol(actualName) = *actual {
249
            return mem::eq(actualName, expectedName);
250
        }
251
        return false;
252
    }
253
    if let case super::ErrorKind::RecordFieldMissing(expectedName) = expected {
254
        if let case super::ErrorKind::RecordFieldMissing(actualName) = *actual {
255
            return mem::eq(actualName, expectedName);
256
        }
257
        return false;
258
    }
259
    if let case super::ErrorKind::RecordFieldUnknown(expectedName) = expected {
260
        if let case super::ErrorKind::RecordFieldUnknown(actualName) = *actual {
261
            return mem::eq(actualName, expectedName);
262
        }
263
        return false;
264
    }
265
    if let case super::ErrorKind::ArrayFieldUnknown(expectedName) = expected {
266
        if let case super::ErrorKind::ArrayFieldUnknown(actualName) = *actual {
267
            return mem::eq(actualName, expectedName);
268
        }
269
        return false;
270
    }
271
    if let case super::ErrorKind::SliceFieldUnknown(expectedName) = expected {
272
        if let case super::ErrorKind::SliceFieldUnknown(actualName) = *actual {
273
            return mem::eq(actualName, expectedName);
274
        }
275
        return false;
276
    }
277
    if let case super::ErrorKind::UnionVariantPayloadMissing(expectedName) = expected {
278
        if let case super::ErrorKind::UnionVariantPayloadMissing(actualName) = *actual {
279
            return mem::eq(actualName, expectedName);
280
        }
281
        return false;
282
    }
283
    if let case super::ErrorKind::UnionVariantPayloadUnexpected(expectedName) = expected {
284
        if let case super::ErrorKind::UnionVariantPayloadUnexpected(actualName) = *actual {
285
            return mem::eq(actualName, expectedName);
286
        }
287
        return false;
288
    }
289
    if let case super::ErrorKind::UnionMatchNonExhaustive(expectedName) = expected {
290
        if let case super::ErrorKind::UnionMatchNonExhaustive(actualName) = *actual {
291
            return mem::eq(actualName, expectedName);
292
        }
293
        return false;
294
    }
295
    if let case super::ErrorKind::MissingTraitMethod(expectedName) = expected {
296
        if let case super::ErrorKind::MissingTraitMethod(actualName) = *actual {
297
            return mem::eq(actualName, expectedName);
298
        }
299
        return false;
300
    }
301
    if let case super::ErrorKind::MissingSupertraitInstance(expectedName) = expected {
302
        if let case super::ErrorKind::MissingSupertraitInstance(actualName) = *actual {
303
            return mem::eq(actualName, expectedName);
304
        }
305
        return false;
306
    }
307
    if let case super::ErrorKind::AffineUseAfterMove(expectedName) = expected {
308
        if let case super::ErrorKind::AffineUseAfterMove(actualName) = *actual {
309
            return mem::eq(actualName, expectedName);
310
        }
311
        return false;
312
    }
313
    if let case super::ErrorKind::LinearUseAfterConsume(expectedName) = expected {
314
        if let case super::ErrorKind::LinearUseAfterConsume(actualName) = *actual {
315
            return mem::eq(actualName, expectedName);
316
        }
317
        return false;
318
    }
319
    if let case super::ErrorKind::LinearNotConsumed(expectedName) = expected {
320
        if let case super::ErrorKind::LinearNotConsumed(actualName) = *actual {
321
            return mem::eq(actualName, expectedName);
322
        }
323
        return false;
324
    }
325
    if let case super::ErrorKind::LinearBranchMismatch(expectedName) = expected {
326
        if let case super::ErrorKind::LinearBranchMismatch(actualName) = *actual {
327
            return mem::eq(actualName, expectedName);
328
        }
329
        return false;
330
    }
331
    if let case super::ErrorKind::BorrowConflict(expectedName) = expected {
332
        if let case super::ErrorKind::BorrowConflict(actualName) = *actual {
333
            return mem::eq(actualName, expectedName);
334
        }
335
        return false;
336
    }
337
    return *actual == expected;
338
}
339
340
/// Extract the first error and ensure it has the expected kind.
341
export fn expectErrorKind(result: &TestResult, kind: super::ErrorKind) -> super::Error
342
    throws (testing::TestError)
343
{
344
    let err = try expectError(result);
345
    try testing::expect(errorKindMatches(&err.kind, kind));
346
    return err;
347
}
348
349
/// Ensure an expression resolves to the expected type annotation.
350
fn expectType 'arena (self: &super::Resolver 'arena, expr: *ast::Node, expected: super::Type)
351
    throws (testing::TestError)
352
{
353
    let actual = super::typeFor(self, expr)
354
        else throw testing::TestError::Failed;
355
356
    if actual <> expected {
357
        throw testing::TestError::Failed;
358
    }
359
}
360
361
/// Verify that an error represents a specific type mismatch.
362
fn expectTypeMismatch(err: super::Error, expected: super::Type, actual: super::Type)
363
    throws (testing::TestError)
364
{
365
    let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
366
        else throw testing::TestError::Failed;
367
    try testing::expect(mismatch.expected == expected);
368
    try testing::expect(mismatch.actual == actual);
369
}
370
371
/// Resolve a program and require successful analysis.
372
unsafe fn expectAnalyzeOk(program: *[u8]) throws (testing::TestError) {
373
    let mut testArena1 = testArena();
374
    let testStorage1: 'test1 = &mut testArena1 in {
375
        let mut a = testResolver(testStorage1);
376
        let result = try resolveProgramStr(&mut a, program);
377
        try expectNoErrors(&result);
378
    }
379
}
380
381
/// Require an inferred integer type mismatch.
382
unsafe fn expectIntMismatch(program: *[u8], expected: super::Type)
383
    throws (testing::TestError)
384
{
385
    let mut testArena2 = testArena();
386
    let testStorage2: 'test2 = &mut testArena2 in {
387
        let mut a = testResolver(testStorage2);
388
        let result = try resolveProgramStr(&mut a, program);
389
        let err = try expectError(&result);
390
        try expectTypeMismatch(err, expected, super::Type::Int);
391
    }
392
}
393
394
/// Retrieve the nth statement from a block node.
395
export fn getBlockStmt(block: *ast::Node, index: u32) -> *ast::Node
396
    throws (testing::TestError)
397
{
398
    let case ast::NodeValue::Block(body) = block.value
399
        else throw testing::TestError::Failed;
400
401
    if index >= body.statements.len {
402
        throw testing::TestError::Failed;
403
    }
404
    return body.statements[index];
405
}
406
407
/// Retrieve a function body block by function name from the program scope.
408
unsafe fn getFnBody 'arena (a: &super::Resolver 'arena, root: *ast::Node, name: *[u8]) -> ast::Block
409
    throws (testing::TestError)
410
{
411
    let scope = super::scopeFor(a, root)
412
        else throw testing::TestError::Failed;
413
    let sym = super::findSymbolInScope(scope, name)
414
        else throw testing::TestError::Failed;
415
    // Verify it's a value symbol by pattern matching.
416
    let case super::SymbolData::Value { .. } = sym.data
417
        else throw testing::TestError::Failed;
418
419
    let case ast::NodeValue::FnDecl(fnDecl) = sym.node.value
420
        else throw testing::TestError::Failed;
421
422
    let body = fnDecl.body
423
        else throw testing::TestError::Failed;
424
    let case ast::NodeValue::Block(blk) = body.value
425
        else throw testing::TestError::Failed;
426
427
    return blk;
428
}
429
430
/// Get the payload type of a union variant, if it has one.
431
/// For single-field unlabeled variants like `Variant(i32)`, unwraps to return the inner type.
432
unsafe fn getUnionVariantPayload(nominalTy: *unsafe super::NominalType, variantName: *[u8]) -> super::Type {
433
    let case super::NominalType::Union(unionType) = *nominalTy
434
        else panic "getUnionVariantPayload: not a union";
435
    for i in 0..unionType.variants.len {
436
        if mem::eq(unionType.variants[i].name, variantName) {
437
            let payloadType = unionType.variants[i].valueType;
438
            // Unwrap single-field unlabeled records to get the inner type.
439
            if let case super::Type::Nominal(super::NominalType::Record(recInfo)) = payloadType {
440
                if not recInfo.labeled and recInfo.fields.len == 1 {
441
                    return recInfo.fields[0].fieldType;
442
                }
443
            }
444
            return payloadType;
445
        }
446
    }
447
    panic "getUnionVariantPayload: variant not found";
448
}
449
450
/// Get a nominal type by name, in the scope of the given block node.
451
unsafe fn getTypeInScopeOf 'arena (a: &super::Resolver 'arena, blk: *ast::Node, name: *[u8]) -> *unsafe super::NominalType
452
    throws (testing::TestError)
453
{
454
    let scope = super::scopeFor(a, blk)
455
        else throw testing::TestError::Failed;
456
    let sym = super::findSymbolInScope(scope, name)
457
        else throw testing::TestError::Failed;
458
    let case super::SymbolData::Type(ty) = sym.data
459
        else throw testing::TestError::Failed;
460
    return ty;
461
}
462
463
/// Return the resolved type of a syntax node.
464
fn typeOf 'arena (a: &super::Resolver 'arena, node: *ast::Node) -> super::Type
465
    throws (testing::TestError)
466
{
467
    let ty = super::typeFor(a, node)
468
        else throw testing::TestError::Failed;
469
    return ty;
470
}
471
472
/// Require an array type and return its element type.
473
fn expectArrayType(ty: super::Type, length: u32) -> super::Type
474
    throws (testing::TestError)
475
{
476
    let case super::Type::Array(info) = ty
477
        else throw testing::TestError::Failed;
478
    try testing::expect(info.length == length);
479
480
    return *info.item;
481
}
482
483
/// Require a slice type and return its element type.
484
fn expectSliceType(ty: super::Type, mutable: bool) -> super::Type
485
    throws (testing::TestError)
486
{
487
    let case super::Type::Slice { item, mutable: sliceMut, .. } = ty
488
        else throw testing::TestError::Failed;
489
    try testing::expect(sliceMut == mutable);
490
491
    return *item;
492
}
493
494
/// Require a pointer type and return its target type.
495
fn expectPointerType(ty: super::Type, mutable: bool) -> super::Type
496
    throws (testing::TestError)
497
{
498
    let case super::Type::Pointer { target, mutable: ptrMut, .. } = ty
499
        else throw testing::TestError::Failed;
500
    try testing::expect(ptrMut == mutable);
501
502
    return *target;
503
}
504
505
/// Verify that a node has a constant integer value with the expected magnitude.
506
fn expectConstInt 'arena (a: &super::Resolver 'arena, node: *ast::Node, expected: u32)
507
    throws (testing::TestError)
508
{
509
    let constVal = super::constValueEntry(a, node)
510
        else throw testing::TestError::Failed;
511
512
    let case super::ConstValue::Int(int) = constVal
513
        else throw testing::TestError::Failed;
514
515
    try testing::expect(int.magnitude == expected);
516
}
517
518
/// Resolve an expression that should evaluate to a constant, and verify it equals the expected value.
519
unsafe fn resolveAndExpectConstExpr(expr: *[u8], expected: u32)
520
    throws (testing::TestError)
521
{
522
    let mut testArena3 = testArena();
523
    let testStorage3: 'test3 = &mut testArena3 in {
524
        let mut a = testResolver(testStorage3);
525
        let result = try resolveExprStr(&mut a, expr);
526
        try expectNoErrors(&result);
527
        try expectType(&a, result.root, super::Type::U32);
528
        try expectConstInt(&a, result.root, expected);
529
    }
530
}
531
532
/// Resolve a statement that should evaluate to a constant, and verify it equals the expected value.
533
unsafe fn resolveAndExpectConstStmt(expr: *[u8], expected: u32)
534
    throws (testing::TestError)
535
{
536
    let mut testArena4 = testArena();
537
    let testStorage4: 'test4 = &mut testArena4 in {
538
        let mut a = testResolver(testStorage4);
539
        let result = try resolveProgramStr(&mut a, expr);
540
        try expectNoErrors(&result);
541
        let stmt = try getBlockStmt(result.root, 1);
542
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
543
        try expectConstInt(&a, expr, expected);
544
    }
545
}
546
547
// Tests ///////////////////////////////////////////////////////////////////////
548
549
@test unsafe fn testResolveLit() throws (testing::TestError) {
550
    let mut testArena5 = testArena();
551
    let testStorage5: 'test5 = &mut testArena5 in {
552
        let mut a = testResolver(testStorage5);
553
        let result = try resolveExprStr(&mut a, "true");
554
555
        try expectNoErrors(&result);
556
        try expectType(&a, result.root, super::Type::Bool);
557
    }
558
}
559
560
@test unsafe fn testResolveStringLiteralType() throws (testing::TestError) {
561
    let mut testArena6 = testArena();
562
    let testStorage6: 'test6 = &mut testArena6 in {
563
        let mut a = testResolver(testStorage6);
564
        let result = try resolveExprStr(&mut a, "\"hello\"");
565
566
        try expectNoErrors(&result);
567
        let ty = try typeOf(&a, result.root);
568
        let elemTy = try expectSliceType(ty, false);
569
        try testing::expect(elemTy == super::Type::U8);
570
    }
571
}
572
573
@test unsafe fn testResolveAsNumeric() throws (testing::TestError) {
574
    {
575
        let mut testArena7 = testArena();
576
        let testStorage7: 'test7 = &mut testArena7 in {
577
            let mut a = testResolver(testStorage7);
578
            let result = try resolveExprStr(&mut a, "1 as u32");
579
            try expectNoErrors(&result);
580
            try expectType(&a, result.root, super::Type::U32);
581
        }
582
    } {
583
        let mut testArena8 = testArena();
584
        let testStorage8: 'test8 = &mut testArena8 in {
585
            let mut a = testResolver(testStorage8);
586
            let result = try resolveBlockStr(&mut a, "let x: u32 = 913; x as u8;");
587
            try expectNoErrors(&result);
588
589
            let x = try getBlockStmt(result.root, 1);
590
            try expectExprStmtType(&a, x, super::Type::U8);
591
        }
592
    }
593
}
594
595
@test unsafe fn testResolveAsInvalid() throws (testing::TestError) {
596
    let mut testArena9 = testArena();
597
    let testStorage9: 'test9 = &mut testArena9 in {
598
        let mut a = testResolver(testStorage9);
599
        let result = try resolveProgramStr(&mut a, "true as u32");
600
601
        try expectErrorKind(
602
            &result,
603
            super::ErrorKind::InvalidAsCast(super::InvalidAsCast {
604
                from: super::Type::Bool,
605
                to: super::Type::U32,
606
        })
607
        );
608
    }
609
}
610
611
@test unsafe fn testResolveAsUnionToInt() throws (testing::TestError) {
612
    let mut testArena10 = testArena();
613
    let testStorage10: 'test10 = &mut testArena10 in {
614
        let mut a = testResolver(testStorage10);
615
        let program = "union Color { Red } Color::Red as u32;";
616
        let result = try resolveProgramStr(&mut a, program);
617
        try expectNoErrors(&result);
618
619
        let red = try getBlockStmt(result.root, 1);
620
        try expectExprStmtType(&a, red, super::Type::U32);
621
    }
622
}
623
624
@test unsafe fn testResolveBinding() throws (testing::TestError) {
625
    let mut testArena11 = testArena();
626
    let testStorage11: 'test11 = &mut testArena11 in {
627
        let mut a = testResolver(testStorage11);
628
        let result = try resolveBlockStr(&mut a, "let x: bool = true; x;");
629
        let stmt = try parser::tests::getBlockLastStmt(result.root);
630
631
        try expectNoErrors(&result);
632
        try expectType(&a, stmt, super::Type::Void);
633
        try expectExprStmtType(&a, stmt, super::Type::Bool);
634
635
        let case ast::NodeValue::ExprStmt(x) = stmt.value
636
            else throw testing::TestError::Failed;
637
638
        let sym = super::symbolFor(&a, x)
639
            else throw testing::TestError::Failed;
640
        let case super::SymbolData::Value { type: valType, .. } = sym.data
641
            else throw testing::TestError::Failed;
642
        try testing::expect(valType == super::Type::Bool);
643
    }
644
}
645
646
@test unsafe fn testResolveBindingInvalid() throws (testing::TestError) {
647
    let mut testArena12 = testArena();
648
    let testStorage12: 'test12 = &mut testArena12 in {
649
        let mut a = testResolver(testStorage12);
650
        let result = try resolveBlockStr(&mut a, "let x: i32 = true;");
651
        let err = try expectError(&result);
652
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
653
    }
654
}
655
656
@test unsafe fn testResolveDuplicateBinding() throws (testing::TestError) {
657
    let mut testArena13 = testArena();
658
    let testStorage13: 'test13 = &mut testArena13 in {
659
        let mut a = testResolver(testStorage13);
660
        let result = try resolveBlockStr(&mut a, "let x: bool = true; let x: u8 = 1;");
661
        let stmt = try parser::tests::getBlockLastStmt(result.root);
662
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("x"));
663
    }
664
}
665
666
@test unsafe fn testResolveConstLiteralValue() throws (testing::TestError) {
667
    let mut testArena14 = testArena();
668
    let testStorage14: 'test14 = &mut testArena14 in {
669
        let mut a = testResolver(testStorage14);
670
        let program = "constant ANSWER: i32 = 42;";
671
        let result = try resolveProgramStr(&mut a, program);
672
        try expectNoErrors(&result);
673
674
        let constNode = try getBlockStmt(result.root, 0);
675
        let sym = super::symbolFor(&a, constNode)
676
            else throw testing::TestError::Failed;
677
        let case super::SymbolData::Constant { type: constType, .. } = sym.data
678
            else throw testing::TestError::Failed;
679
        try testing::expect(constType == super::Type::I32);
680
    }
681
}
682
683
@test unsafe fn testResolveConstRequiresConstantExpr() throws (testing::TestError) {
684
    let mut testArena15 = testArena();
685
    let testStorage15: 'test15 = &mut testArena15 in {
686
        let mut a = testResolver(testStorage15);
687
        let program = "fn value() -> i32 { return 1 } fn main() { constant ANSWER: i32 = value(); }";
688
        let result = try resolveProgramStr(&mut a, program);
689
        let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
690
691
        let errNode = err.node
692
            else throw testing::TestError::Failed;
693
        let case ast::NodeValue::Call(_) = errNode.value
694
            else throw testing::TestError::Failed;
695
    }
696
}
697
698
@test unsafe fn testResolveStaticLiteralValue() throws (testing::TestError) {
699
    let mut testArena16 = testArena();
700
    let testStorage16: 'test16 = &mut testArena16 in {
701
        let mut a = testResolver(testStorage16);
702
        let program = "static COUNTER: i32 = 0;";
703
        let result = try resolveProgramStr(&mut a, program);
704
        try expectNoErrors(&result);
705
706
        let staticNode = try getBlockStmt(result.root, 0);
707
        let sym = super::symbolFor(&a, staticNode)
708
            else throw testing::TestError::Failed;
709
        let case super::SymbolData::Value { type: valType, .. } = sym.data
710
            else throw testing::TestError::Failed;
711
        try testing::expect(valType == super::Type::I32);
712
    }
713
}
714
715
@test unsafe fn testResolveStaticRequiresConstantExpr() throws (testing::TestError) {
716
    let mut testArena17 = testArena();
717
    let testStorage17: 'test17 = &mut testArena17 in {
718
        let mut a = testResolver(testStorage17);
719
        let program = "fn seed() -> i32 { return 1; } static COUNTER: i32 = seed();";
720
        let result = try resolveProgramStr(&mut a, program);
721
        let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
722
723
        let errNode = err.node
724
            else throw testing::TestError::Failed;
725
        let case ast::NodeValue::Call(_) = errNode.value
726
            else throw testing::TestError::Failed;
727
    }
728
}
729
730
@test unsafe fn testSymbolStoresFnAttributes() throws (testing::TestError) {
731
    let mut testArena18 = testArena();
732
    let testStorage18: 'test18 = &mut testArena18 in {
733
        let mut a = testResolver(testStorage18);
734
        let program = "@default export fn f() { return; }";
735
        let result = try resolveProgramStr(&mut a, program);
736
        try expectNoErrors(&result);
737
738
        let scope = super::scopeFor(&a, result.root)
739
            else throw testing::TestError::Failed;
740
        let sym = super::findSymbolInScope(scope, "f")
741
            else throw testing::TestError::Failed;
742
743
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Export));
744
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Default));
745
        try testing::expectNot(ast::hasAttribute(sym.attrs, ast::Attribute::Extern));
746
    }
747
}
748
749
@test unsafe fn testSymbolStoresRecordAttributes() throws (testing::TestError) {
750
    let mut testArena19 = testArena();
751
    let testStorage19: 'test19 = &mut testArena19 in {
752
        let mut a = testResolver(testStorage19);
753
        let program = "export record S { value: i32 }";
754
        let result = try resolveProgramStr(&mut a, program);
755
        try expectNoErrors(&result);
756
757
        let scope = super::scopeFor(&a, result.root)
758
            else throw testing::TestError::Failed;
759
        let sym = super::findSymbolInScope(scope, "S")
760
            else throw testing::TestError::Failed;
761
762
        try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Export));
763
        try testing::expectNot(ast::hasAttribute(sym.attrs, ast::Attribute::Default));
764
    }
765
}
766
767
@test unsafe fn testDefaultAttributeRejectedOnRecord() throws (testing::TestError) {
768
    let mut testArena20 = testArena();
769
    let testStorage20: 'test20 = &mut testArena20 in {
770
        let mut a = testResolver(testStorage20);
771
        let program = "@default record T { value: i32 }";
772
        let result = try resolveProgramStr(&mut a, program);
773
        try expectErrorKind(&result, super::ErrorKind::DefaultAttrOnlyOnFn);
774
    }
775
}
776
777
@test unsafe fn testDefaultAttributeRejectedOnUnion() throws (testing::TestError) {
778
    let mut testArena21 = testArena();
779
    let testStorage21: 'test21 = &mut testArena21 in {
780
        let mut a = testResolver(testStorage21);
781
        let program = "@default union Result { Ok, Err }";
782
        let result = try resolveProgramStr(&mut a, program);
783
        try expectErrorKind(&result, super::ErrorKind::DefaultAttrOnlyOnFn);
784
    }
785
}
786
787
@test unsafe fn testResolveArrayLiteralTyped() throws (testing::TestError) {
788
    let mut testArena22 = testArena();
789
    let testStorage22: 'test22 = &mut testArena22 in {
790
        let mut a = testResolver(testStorage22);
791
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1, 2];");
792
        try expectNoErrors(&result);
793
794
        let stmt = try getBlockStmt(result.root, 0);
795
        let case ast::NodeValue::Let(decl) = stmt.value
796
            else throw testing::TestError::Failed;
797
        let arrayTy = try typeOf(&a, decl.value);
798
        let elemTy = try expectArrayType(arrayTy, 2);
799
        try testing::expect(elemTy == super::Type::I32);
800
    }
801
}
802
803
@test unsafe fn testResolveArrayLiteralElementMismatch() throws (testing::TestError) {
804
    let mut testArena23 = testArena();
805
    let testStorage23: 'test23 = &mut testArena23 in {
806
        let mut a = testResolver(testStorage23);
807
        let result = try resolveProgramStr(&mut a, "let xs: [bool; 2] = [true, 1];");
808
        let err = try expectError(&result);
809
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
810
    }
811
}
812
813
@test unsafe fn testResolveArrayLiteralCannotInfer() throws (testing::TestError) {
814
    let mut testArena24 = testArena();
815
    let testStorage24: 'test24 = &mut testArena24 in {
816
        let mut a = testResolver(testStorage24);
817
        let result = try resolveProgramStr(&mut a, "let xs = [1, 2];");
818
        try expectErrorKind(&result, super::ErrorKind::CannotInferType);
819
    }
820
}
821
822
@test unsafe fn testResolveArrayLiteralOverflow() throws (testing::TestError) {
823
    let mut testArena25 = testArena();
824
    let testStorage25: 'test25 = &mut testArena25 in {
825
        let mut a = testResolver(testStorage25);
826
        let result = try resolveProgramStr(&mut a, "let xs: [u8; 2] = [1, 256];");
827
        let err = try expectError(&result);
828
        let case super::ErrorKind::TypeMismatch(_) = err.kind
829
            else throw testing::TestError::Failed;
830
    }
831
}
832
833
@test unsafe fn testResolveArrayLiteralTooFewElements() throws (testing::TestError) {
834
    let mut testArena26 = testArena();
835
    let testStorage26: 'test26 = &mut testArena26 in {
836
        let mut a = testResolver(testStorage26);
837
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1];");
838
        let err = try expectError(&result);
839
        let case super::ErrorKind::TypeMismatch(_) = err.kind
840
            else throw testing::TestError::Failed;
841
    }
842
}
843
844
@test unsafe fn testResolveArrayLiteralTooManyElements() throws (testing::TestError) {
845
    let mut testArena27 = testArena();
846
    let testStorage27: 'test27 = &mut testArena27 in {
847
        let mut a = testResolver(testStorage27);
848
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1, 2, 3];");
849
        let err = try expectError(&result);
850
        let case super::ErrorKind::TypeMismatch(_) = err.kind
851
            else throw testing::TestError::Failed;
852
    }
853
}
854
855
@test unsafe fn testResolveArrayLiteralEmptyWithAnnotation() throws (testing::TestError) {
856
    let mut testArena28 = testArena();
857
    let testStorage28: 'test28 = &mut testArena28 in {
858
        let mut a = testResolver(testStorage28);
859
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 0] = [];");
860
        try expectNoErrors(&result);
861
    }
862
}
863
864
@test unsafe fn testResolveNestedArrayLiteralTyped() throws (testing::TestError) {
865
    let mut testArena29 = testArena();
866
    let testStorage29: 'test29 = &mut testArena29 in {
867
        let mut a = testResolver(testStorage29);
868
        let result = try resolveProgramStr(&mut a, "let grid: [[i32; 2]; 2] = [[1, 2], [3, 4]];");
869
        try expectNoErrors(&result);
870
871
        let stmt = try getBlockStmt(result.root, 0);
872
        let case ast::NodeValue::Let(decl) = stmt.value
873
            else throw testing::TestError::Failed;
874
        let gridTy = try typeOf(&a, decl.value);
875
        let rowTy = try expectArrayType(gridTy, 2);
876
        let elemTy = try expectArrayType(rowTy, 2);
877
        try testing::expect(elemTy == super::Type::I32);
878
    }
879
}
880
881
@test unsafe fn testResolveArrayLiteralWithOptionalElems() throws (testing::TestError) {
882
    let mut testArena30 = testArena();
883
    let testStorage30: 'test30 = &mut testArena30 in {
884
        let mut a = testResolver(testStorage30);
885
        let result = try resolveProgramStr(&mut a, "let xs: [?i32; 2] = [1, 2];");
886
        try expectNoErrors(&result);
887
888
        let stmt = try getBlockStmt(result.root, 0);
889
        let case ast::NodeValue::Let(decl) = stmt.value
890
            else throw testing::TestError::Failed;
891
        let arrayTy = try typeOf(&a, decl.value);
892
        let elemTy = try expectArrayType(arrayTy, 2);
893
        let case super::Type::Optional(inner) = elemTy
894
            else throw testing::TestError::Failed;
895
        try testing::expect(*inner == super::Type::I32);
896
    }
897
}
898
899
@test unsafe fn testResolveArrayLiteralOptionalMismatch() throws (testing::TestError) {
900
    let mut testArena31 = testArena();
901
    let testStorage31: 'test31 = &mut testArena31 in {
902
        let mut a = testResolver(testStorage31);
903
        let result = try resolveProgramStr(&mut a, "let xs: [?bool; 2] = [1, 2];");
904
        let err = try expectError(&result);
905
        let case super::ErrorKind::TypeMismatch(_) = err.kind
906
            else throw testing::TestError::Failed;
907
    }
908
}
909
910
@test unsafe fn testResolveArrayRepeatBasic() throws (testing::TestError) {
911
    let mut testArena32 = testArena();
912
    let testStorage32: 'test32 = &mut testArena32 in {
913
        let mut a = testResolver(testStorage32);
914
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 3] = [42; 3];");
915
        try expectNoErrors(&result);
916
917
        let stmt = try getBlockStmt(result.root, 0);
918
        let case ast::NodeValue::Let(decl) = stmt.value
919
            else throw testing::TestError::Failed;
920
        let arrayTy = try typeOf(&a, decl.value);
921
        let elemTy = try expectArrayType(arrayTy, 3);
922
        try testing::expect(elemTy == super::Type::I32);
923
    }
924
}
925
926
@test unsafe fn testResolveArrayRepeatWithExpression() throws (testing::TestError) {
927
    let mut testArena33 = testArena();
928
    let testStorage33: 'test33 = &mut testArena33 in {
929
        let mut a = testResolver(testStorage33);
930
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 5] = [3 + 2; 5];");
931
        try expectNoErrors(&result);
932
933
        let stmt = try getBlockStmt(result.root, 0);
934
        let case ast::NodeValue::Let(decl) = stmt.value
935
            else throw testing::TestError::Failed;
936
        let arrayTy = try typeOf(&a, decl.value);
937
        let elemTy = try expectArrayType(arrayTy, 5);
938
        try testing::expect(elemTy == super::Type::I32);
939
    }
940
}
941
942
@test unsafe fn testResolveArrayRepeatLiteralArithmetic() throws (testing::TestError) {
943
    let mut testArena34 = testArena();
944
    let testStorage34: 'test34 = &mut testArena34 in {
945
        let mut a = testResolver(testStorage34);
946
        // `3 * 1` folds to a compile-time constant, so the repeat count is valid.
947
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 3] = [42; 3 * 1];");
948
        try expectNoErrors(&result);
949
    }
950
}
951
952
@test unsafe fn testResolveArrayRepeatNonConstCount() throws (testing::TestError) {
953
    let mut testArena35 = testArena();
954
    let testStorage35: 'test35 = &mut testArena35 in {
955
        let mut a = testResolver(testStorage35);
956
        // A function call is not a constant expression.
957
        let result = try resolveProgramStr(&mut a, "fn f() -> u32 { return 3; } let xs: [i32; 3] = [42; f()];");
958
        try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
959
    }
960
}
961
962
@test unsafe fn testResolveArrayRepeatCountMismatch() throws (testing::TestError) {
963
    let mut testArena36 = testArena();
964
    let testStorage36: 'test36 = &mut testArena36 in {
965
        let mut a = testResolver(testStorage36);
966
        let result = try resolveProgramStr(&mut a, "let xs: [i32; 4] = [1; 3];");
967
        let err = try expectError(&result);
968
        let case super::ErrorKind::TypeMismatch(_) = err.kind
969
            else throw testing::TestError::Failed;
970
    }
971
}
972
973
@test unsafe fn testResolveArrayIndex() throws (testing::TestError) {
974
    let mut testArena37 = testArena();
975
    let testStorage37: 'test37 = &mut testArena37 in {
976
        let mut a = testResolver(testStorage37);
977
        let program = "let xs: [i32; 3] = [1, 2, 3]; xs[1];";
978
        let result = try resolveProgramStr(&mut a, program);
979
        try expectNoErrors(&result);
980
981
        let stmt = try getBlockStmt(result.root, 1);
982
        try expectExprStmtType(&a, stmt, super::Type::I32);
983
    }
984
}
985
986
@test unsafe fn testResolveSliceIndex() throws (testing::TestError) {
987
    let mut testArena38 = testArena();
988
    let testStorage38: 'test38 = &mut testArena38 in {
989
        let mut a = testResolver(testStorage38);
990
        let program = "static xs: [i32; 4] = [1, 2, 3, 4]; let slice = &xs[1..]; slice[1];";
991
        let result = try resolveProgramStr(&mut a, program);
992
        try expectNoErrors(&result);
993
994
        let sliceStmt = try getBlockStmt(result.root, 1);
995
        let case ast::NodeValue::Let(sliceDecl) = sliceStmt.value
996
            else throw testing::TestError::Failed;
997
        let sliceTy = try typeOf(&a, sliceDecl.value);
998
        let elemTy = try expectSliceType(sliceTy, false);
999
        try testing::expect(elemTy == super::Type::I32);
1000
1001
        let indexStmt = try getBlockStmt(result.root, 2);
1002
        try expectExprStmtType(&a, indexStmt, super::Type::I32);
1003
    }
1004
}
1005
1006
@test unsafe fn testResolveSliceFields() throws (testing::TestError) {
1007
    let mut testArena39 = testArena();
1008
    let testStorage39: 'test39 = &mut testArena39 in {
1009
        let mut a = testResolver(testStorage39);
1010
        let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[1..]; slice.len; unsafe { slice.ptr; }";
1011
        let result = try resolveProgramStr(&mut a, program);
1012
        try expectNoErrors(&result);
1013
1014
        let lenStmt = try getBlockStmt(result.root, 2);
1015
        let case ast::NodeValue::ExprStmt(lenExpr) = lenStmt.value
1016
            else throw testing::TestError::Failed;
1017
        let lenTy = try typeOf(&a, lenExpr);
1018
        try testing::expect(lenTy == super::Type::U32);
1019
1020
        let ptrStmt = try getBlockStmt(result.root, 3);
1021
        let case ast::NodeValue::Block(ptrBlock) = ptrStmt.value
1022
            else throw testing::TestError::Failed;
1023
        let case ast::NodeValue::ExprStmt(ptrExpr) = ptrBlock.statements[0].value
1024
            else throw testing::TestError::Failed;
1025
        let ptrTy = try typeOf(&a, ptrExpr);
1026
        let targetTy = try expectPointerType(ptrTy, false);
1027
        try testing::expect(targetTy == super::Type::I32);
1028
    }
1029
}
1030
1031
@test unsafe fn testResolveSliceLiteralImmutable() throws (testing::TestError) {
1032
    let mut testArena40 = testArena();
1033
    let testStorage40: 'test40 = &mut testArena40 in {
1034
        let mut a = testResolver(testStorage40);
1035
        let program = "let slice: *[i32] = &[1, 2, 3];";
1036
        let result = try resolveProgramStr(&mut a, program);
1037
        try expectNoErrors(&result);
1038
    }
1039
}
1040
1041
/// Empty array literal infers element type from slice annotation.
1042
@test unsafe fn testResolveSliceLiteralEmpty() throws (testing::TestError) {
1043
    let mut testArena41 = testArena();
1044
    let testStorage41: 'test41 = &mut testArena41 in {
1045
        let mut a = testResolver(testStorage41);
1046
        let program = "let slice: *[i32] = &[];";
1047
        let result = try resolveProgramStr(&mut a, program);
1048
        try expectNoErrors(&result);
1049
    }
1050
}
1051
1052
/// Nested array literal should infer inner element type from slice annotation.
1053
@test unsafe fn testResolveSliceLiteralNestedArray() throws (testing::TestError) {
1054
    let mut testArena42 = testArena();
1055
    let testStorage42: 'test42 = &mut testArena42 in {
1056
        let mut a = testResolver(testStorage42);
1057
        let program = "let slice: *[[i32; 2]] = &[[1, 2], [3, 4]];";
1058
        let result = try resolveProgramStr(&mut a, program);
1059
        try expectNoErrors(&result);
1060
    }
1061
}
1062
1063
@test unsafe fn testResolveSliceFromArray() throws (testing::TestError) {
1064
    {
1065
        let mut testArena43 = testArena();
1066
        let testStorage43: 'test43 = &mut testArena43 in {
1067
            let mut a = testResolver(testStorage43);
1068
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[..];";
1069
            let result = try resolveProgramStr(&mut a, program);
1070
            try expectNoErrors(&result);
1071
        }
1072
    } {
1073
        let mut testArena44 = testArena();
1074
        let testStorage44: 'test44 = &mut testArena44 in {
1075
            let mut a = testResolver(testStorage44);
1076
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[0..3];";
1077
            let result = try resolveProgramStr(&mut a, program);
1078
            try expectNoErrors(&result);
1079
        }
1080
    } {
1081
        let mut testArena45 = testArena();
1082
        let testStorage45: 'test45 = &mut testArena45 in {
1083
            let mut a = testResolver(testStorage45);
1084
            let program = "static xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[..3];";
1085
            let result = try resolveProgramStr(&mut a, program);
1086
            try expectNoErrors(&result);
1087
        }
1088
    } {
1089
        let mut testArena46 = testArena();
1090
        let testStorage46: 'test46 = &mut testArena46 in {
1091
            let mut a = testResolver(testStorage46);
1092
            let program = "static xs: [u8; 2] = [1, 2]; let slice = &xs[1..1];";
1093
            let result = try resolveProgramStr(&mut a, program);
1094
            try expectNoErrors(&result);
1095
        }
1096
    }
1097
}
1098
1099
@test unsafe fn testResolveSliceLiteralMutableRequiresMut() throws (testing::TestError) {
1100
    let mut testArena47 = testArena();
1101
    let testStorage47: 'test47 = &mut testArena47 in {
1102
        let mut a = testResolver(testStorage47);
1103
        let program = "let slice: *mut [i32] = &[1, 2, 3];";
1104
        let result = try resolveProgramStr(&mut a, program);
1105
        let err = try expectError(&result);
1106
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1107
            else throw testing::TestError::Failed;
1108
    }
1109
}
1110
1111
@test unsafe fn testResolveSliceLiteralMutable() throws (testing::TestError) {
1112
    let mut testArena48 = testArena();
1113
    let testStorage48: 'test48 = &mut testArena48 in {
1114
        let mut a = testResolver(testStorage48);
1115
        let program = "let slice: *mut [i32] = &mut [1, 2, 3];";
1116
        let result = try resolveProgramStr(&mut a, program);
1117
        try expectNoErrors(&result);
1118
    }
1119
}
1120
1121
@test unsafe fn testResolvePointerMutableAssignmentRequiresMut() throws (testing::TestError) {
1122
    let mut testArena49 = testArena();
1123
    let testStorage49: 'test49 = &mut testArena49 in {
1124
        let mut a = testResolver(testStorage49);
1125
        let program = "let x: i32 = 0; let ptr: *mut i32 = &x;";
1126
        let result = try resolveProgramStr(&mut a, program);
1127
        let err = try expectError(&result);
1128
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1129
            else throw testing::TestError::Failed;
1130
    }
1131
}
1132
1133
@test unsafe fn testResolvePointerMutableToImmutableAssignment() throws (testing::TestError) {
1134
    let mut testArena50 = testArena();
1135
    let testStorage50: 'test50 = &mut testArena50 in {
1136
        let mut a = testResolver(testStorage50);
1137
        let program = "static x: i32 = 0; let mptr: *mut i32 = &mut x; let ptr: *i32 = mptr;";
1138
        let result = try resolveProgramStr(&mut a, program);
1139
        try expectNoErrors(&result);
1140
    }
1141
}
1142
1143
@test unsafe fn testResolveAddressOfRequiresMutableBinding() throws (testing::TestError) {
1144
    {
1145
        let mut testArena51 = testArena();
1146
        let testStorage51: 'test51 = &mut testArena51 in {
1147
            let mut a = testResolver(testStorage51);
1148
            let program = "let x: i32 = 0; let ptr = &mut x;";
1149
            let result = try resolveProgramStr(&mut a, program);
1150
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1151
        }
1152
    } {
1153
        let mut testArena52 = testArena();
1154
        let testStorage52: 'test52 = &mut testArena52 in {
1155
            let mut a = testResolver(testStorage52);
1156
            let program = "let mut x: i32 = 0; &mut x;";
1157
            let result = try resolveProgramStr(&mut a, program);
1158
            try expectNoErrors(&result);
1159
        }
1160
    }
1161
}
1162
1163
@test unsafe fn testResolveAddressOfSliceRequiresMutableBinding() throws (testing::TestError) {
1164
    {
1165
        let mut testArena53 = testArena();
1166
        let testStorage53: 'test53 = &mut testArena53 in {
1167
            let mut a = testResolver(testStorage53);
1168
            let program = "let xs: [i32; 3] = [1, 2, 3]; let slice = &mut xs[..];";
1169
            let result = try resolveProgramStr(&mut a, program);
1170
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1171
        }
1172
    } {
1173
        let mut testArena54 = testArena();
1174
        let testStorage54: 'test54 = &mut testArena54 in {
1175
            let mut a = testResolver(testStorage54);
1176
            let program = "let mut xs: [i32; 3] = [1, 2, 3]; &mut xs[..];";
1177
            let result = try resolveProgramStr(&mut a, program);
1178
            try expectNoErrors(&result);
1179
        }
1180
    }
1181
}
1182
1183
@test unsafe fn testResolveSliceCannotAssignToArray() throws (testing::TestError) {
1184
    let mut testArena55 = testArena();
1185
    let testStorage55: 'test55 = &mut testArena55 in {
1186
        let mut a = testResolver(testStorage55);
1187
        let program = "let xs: *[u8] = &[1, 2]; let ys: [u8; 2] = xs;";
1188
        let result = try resolveProgramStr(&mut a, program);
1189
        let err = try expectError(&result);
1190
        let case super::ErrorKind::TypeMismatch(_) = err.kind
1191
            else throw testing::TestError::Failed;
1192
    }
1193
}
1194
1195
@test unsafe fn testResolveSliceSyntaxRequiresAddressOf() throws (testing::TestError) {
1196
    let mut testArena56 = testArena();
1197
    let testStorage56: 'test56 = &mut testArena56 in {
1198
        let mut a = testResolver(testStorage56);
1199
        let program = "let xs: [u8; 2] = [1, 2]; xs[..];";
1200
        let result = try resolveProgramStr(&mut a, program);
1201
        try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
1202
    }
1203
}
1204
1205
@test unsafe fn testResolveSliceResliceRequiresAddressOf() throws (testing::TestError) {
1206
    let mut testArena57 = testArena();
1207
    let testStorage57: 'test57 = &mut testArena57 in {
1208
        let mut a = testResolver(testStorage57);
1209
        let program = "fn f(s: *[u8]) -> *[u8] { return s[..]; }";
1210
        let result = try resolveProgramStr(&mut a, program);
1211
        try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
1212
    }
1213
}
1214
1215
@test unsafe fn testResolveSliceRangeOutOfBounds() throws (testing::TestError) {
1216
    {
1217
        let mut testArena58 = testArena();
1218
        let testStorage58: 'test58 = &mut testArena58 in {
1219
            let mut a = testResolver(testStorage58);
1220
            let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[..3];";
1221
            let result = try resolveProgramStr(&mut a, program);
1222
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1223
        }
1224
    } {
1225
        let mut testArena59 = testArena();
1226
        let testStorage59: 'test59 = &mut testArena59 in {
1227
            let mut a = testResolver(testStorage59);
1228
            let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[3..];";
1229
            let result = try resolveProgramStr(&mut a, program);
1230
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1231
        }
1232
    } {
1233
        let mut testArena60 = testArena();
1234
        let testStorage60: 'test60 = &mut testArena60 in {
1235
            let mut a = testResolver(testStorage60);
1236
            let program = "let xs: [u8; 4] = [1, 2, 3, 4]; let slice = &xs[3..2];";
1237
            let result = try resolveProgramStr(&mut a, program);
1238
            try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
1239
        }
1240
    }
1241
}
1242
1243
@test unsafe fn testResolveArrayLenConstValue() throws (testing::TestError) {
1244
    let mut testArena61 = testArena();
1245
    let testStorage61: 'test61 = &mut testArena61 in {
1246
        let mut a = testResolver(testStorage61);
1247
        let program = "let xs: [i32; 3] = [1, 2, 3]; constant LEN: u32 = xs.len;";
1248
        let result = try resolveBlockStr(&mut a, program);
1249
        try expectNoErrors(&result);
1250
1251
        let constStmt = try getBlockStmt(result.root, 1);
1252
        let case ast::NodeValue::ConstDecl(decl) = constStmt.value
1253
            else throw testing::TestError::Failed;
1254
        let valueConst = super::constValueEntry(&a, decl.value)
1255
            else throw testing::TestError::Failed;
1256
        let case super::ConstValue::Int(lenVal) = valueConst
1257
            else throw testing::TestError::Failed;
1258
        try testing::expect(lenVal.magnitude == 3);
1259
        try testing::expect(not lenVal.negative);
1260
    }
1261
}
1262
1263
@test unsafe fn testResolveIndexNonIndexable() throws (testing::TestError) {
1264
    let mut testArena62 = testArena();
1265
    let testStorage62: 'test62 = &mut testArena62 in {
1266
        let mut a = testResolver(testStorage62);
1267
        let program = "let flag: bool = true; flag[0];";
1268
        let result = try resolveProgramStr(&mut a, program);
1269
        try expectErrorKind(&result, super::ErrorKind::ExpectedIndexable);
1270
    }
1271
}
1272
1273
@test unsafe fn testResolveSliceFieldUnknown() throws (testing::TestError) {
1274
    let mut testArena63 = testArena();
1275
    let testStorage63: 'test63 = &mut testArena63 in {
1276
        let mut a = testResolver(testStorage63);
1277
        let program = "let xs: [i32; 2] = [1, 2]; (&xs[0..]).unknown;";
1278
        let result = try resolveProgramStr(&mut a, program);
1279
        try expectErrorKind(&result, super::ErrorKind::SliceFieldUnknown("unknown"));
1280
    }
1281
}
1282
1283
@test unsafe fn testResolveArrayFieldUnknown() throws (testing::TestError) {
1284
    let mut testArena64 = testArena();
1285
    let testStorage64: 'test64 = &mut testArena64 in {
1286
        let mut a = testResolver(testStorage64);
1287
        let program = "let xs: [i32; 2] = [1, 2]; xs.field;";
1288
        let result = try resolveProgramStr(&mut a, program);
1289
        try expectErrorKind(&result, super::ErrorKind::ArrayFieldUnknown("field"));
1290
    }
1291
}
1292
1293
@test unsafe fn testResolveIfConditionRequiresBool() throws (testing::TestError) {
1294
    {
1295
        let mut testArena65 = testArena();
1296
        let testStorage65: 'test65 = &mut testArena65 in {
1297
            let mut a = testResolver(testStorage65);
1298
            let result = try resolveProgramStr(&mut a, "if 42 {}");
1299
            let err = try expectError(&result);
1300
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1301
        }
1302
    } {
1303
        let mut testArena66 = testArena();
1304
        let testStorage66: 'test66 = &mut testArena66 in {
1305
            let mut a = testResolver(testStorage66);
1306
            let result = try resolveProgramStr(&mut a, "if true {}");
1307
            try expectNoErrors(&result);
1308
        }
1309
    }
1310
}
1311
1312
@test unsafe fn testResolveIfLetScopeBinding() throws (testing::TestError) {
1313
    let mut testArena67 = testArena();
1314
    let testStorage67: 'test67 = &mut testArena67 in {
1315
        let mut a = testResolver(testStorage67);
1316
        let result = try resolveProgramStr(&mut a, "let opt: ?i32 = 42; if let x = opt { x }");
1317
        try expectNoErrors(&result);
1318
1319
        // Get the if-let statement and verify `x` has type `i32`.
1320
        let ifLetStmt = try parser::tests::getBlockLastStmt(result.root);
1321
        let case ast::NodeValue::IfLet(ifLet) = ifLetStmt.value
1322
            else throw testing::TestError::Failed;
1323
1324
        let thenStmt = try parser::tests::getBlockLastStmt(ifLet.thenBranch);
1325
        let case ast::NodeValue::ExprStmt(xExpr) = thenStmt.value
1326
            else throw testing::TestError::Failed;
1327
1328
        try expectType(&a, xExpr, super::Type::I32);
1329
1330
        let scope = super::scopeFor(&a, ifLetStmt)
1331
            else throw testing::TestError::Failed;
1332
        let xSym = super::findSymbolInScope(scope, "x")
1333
            else throw testing::TestError::Failed;
1334
        let case super::SymbolData::Value { type: valType, .. } = xSym.data
1335
            else throw testing::TestError::Failed;
1336
1337
        try testing::expect(valType == super::Type::I32);
1338
    }
1339
}
1340
1341
@test unsafe fn testResolveIfLetScopeBindingError() throws (testing::TestError) {
1342
    let mut testArena68 = testArena();
1343
    let testStorage68: 'test68 = &mut testArena68 in {
1344
        let mut a = testResolver(testStorage68);
1345
        let result = try resolveProgramStr(&mut a, "let opt: ?i32 = 42; if let x = opt { x } else { x }");
1346
        let err = try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1347
1348
        // Verify the error comes from the else branch (offset 48).
1349
        let errNode = err.node
1350
            else throw testing::TestError::Failed;
1351
        try testing::expect(errNode.span.offset == 48);
1352
    }
1353
}
1354
1355
/// Tests that `if let` with a condition expression binds the variable in scope.
1356
@test unsafe fn testResolveIfLetConditionBindsVariable() throws (testing::TestError) {
1357
    let mut testArena69 = testArena();
1358
    let testStorage69: 'test69 = &mut testArena69 in {
1359
        let mut a = testResolver(testStorage69);
1360
        let program = "let opt: ?i32 = 42; if let x = opt; x == 1 { x }";
1361
        let result = try resolveProgramStr(&mut a, program);
1362
        try expectNoErrors(&result);
1363
    }
1364
}
1365
1366
@test unsafe fn testResolveWhileConditionRequiresBool() throws (testing::TestError) {
1367
    {
1368
        let mut testArena70 = testArena();
1369
        let testStorage70: 'test70 = &mut testArena70 in {
1370
            let mut a = testResolver(testStorage70);
1371
            let result = try resolveProgramStr(&mut a, "while 1 {}");
1372
            let err = try expectError(&result);
1373
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1374
        }
1375
    } {
1376
        let mut testArena71 = testArena();
1377
        let testStorage71: 'test71 = &mut testArena71 in {
1378
            let mut a = testResolver(testStorage71);
1379
            let result = try resolveProgramStr(&mut a, "while true {}");
1380
            try expectNoErrors(&result);
1381
        }
1382
    }
1383
}
1384
1385
@test unsafe fn testResolveWhileLetBindingScope() throws (testing::TestError) {
1386
    {
1387
        let mut testArena72 = testArena();
1388
        let testStorage72: 'test72 = &mut testArena72 in {
1389
            let mut a = testResolver(testStorage72);
1390
            let program = "let mut opt: ?i32 = 42; while let x = opt; x > 0 { x; opt; }";
1391
            let result = try resolveProgramStr(&mut a, program);
1392
            try expectNoErrors(&result);
1393
1394
            let whileStmt = try parser::tests::getBlockLastStmt(result.root);
1395
            let case ast::NodeValue::WhileLet(loopNode) = whileStmt.value
1396
                else throw testing::TestError::Failed;
1397
1398
            let bodyStmt = try parser::tests::getBlockFirstStmt(loopNode.body);
1399
            try expectExprStmtType(&a, bodyStmt, super::Type::I32);
1400
1401
            let scope = super::scopeFor(&a, whileStmt)
1402
                else throw testing::TestError::Failed;
1403
            let xSym = super::findSymbolInScope(scope, "x")
1404
                else throw testing::TestError::Failed;
1405
            let case super::SymbolData::Value { type: valType, .. } = xSym.data
1406
                else throw testing::TestError::Failed;
1407
            try testing::expect(valType == super::Type::I32);
1408
        }
1409
    } {
1410
        let mut testArena73 = testArena();
1411
        let testStorage73: 'test73 = &mut testArena73 in {
1412
            let mut a = testResolver(testStorage73);
1413
            let program = "let opt: ?i32 = nil; while let x = opt; true { break } else { x }";
1414
            let result = try resolveProgramStr(&mut a, program);
1415
            try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1416
        }
1417
    }
1418
}
1419
1420
@test unsafe fn testResolveForArrayBindsElementType() throws (testing::TestError) {
1421
    let mut testArena74 = testArena();
1422
    let testStorage74: 'test74 = &mut testArena74 in {
1423
        let mut a = testResolver(testStorage74);
1424
        let program = "let xs: [i32; 2] = [1, 2]; for x in xs { x; }";
1425
        let result = try resolveProgramStr(&mut a, program);
1426
        try expectNoErrors(&result);
1427
1428
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1429
        let case ast::NodeValue::For(loopNode) = forStmt.value
1430
            else throw testing::TestError::Failed;
1431
1432
        let scope = super::scopeFor(&a, forStmt)
1433
            else throw testing::TestError::Failed;
1434
        let sym = super::findSymbolInScope(scope, "x")
1435
            else throw testing::TestError::Failed;
1436
        let case super::SymbolData::Value { type: valType, .. } = sym.data
1437
            else throw testing::TestError::Failed;
1438
        try testing::expect(valType == super::Type::I32);
1439
1440
        let bindingTy = super::typeFor(&a, loopNode.binding)
1441
            else throw testing::TestError::Failed;
1442
        try testing::expect(bindingTy == super::Type::I32);
1443
    }
1444
}
1445
1446
@test unsafe fn testResolveForIndexedLoopBindsIndex() throws (testing::TestError) {
1447
    let mut testArena75 = testArena();
1448
    let testStorage75: 'test75 = &mut testArena75 in {
1449
        let mut a = testResolver(testStorage75);
1450
        let program = "let xs: [bool; 3] = [true; 3]; for value, idx in xs { value; idx; }";
1451
        let result = try resolveProgramStr(&mut a, program);
1452
        try expectNoErrors(&result);
1453
1454
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1455
        let case ast::NodeValue::For(loopNode) = forStmt.value
1456
            else throw testing::TestError::Failed;
1457
1458
        let scope = super::scopeFor(&a, forStmt)
1459
            else throw testing::TestError::Failed;
1460
        let valueSym = super::findSymbolInScope(scope, "value")
1461
            else throw testing::TestError::Failed;
1462
        let case super::SymbolData::Value { type: valueValType, .. } = valueSym.data
1463
            else throw testing::TestError::Failed;
1464
        try testing::expect(valueValType == super::Type::Bool);
1465
        let indexSym = super::findSymbolInScope(scope, "idx")
1466
            else throw testing::TestError::Failed;
1467
        let case super::SymbolData::Value { type: indexValType, .. } = indexSym.data
1468
            else throw testing::TestError::Failed;
1469
        try testing::expect(indexValType == super::Type::U32);
1470
1471
        let indexNode = loopNode.index
1472
            else throw testing::TestError::Failed;
1473
        let indexTy = super::typeFor(&a, indexNode)
1474
            else throw testing::TestError::Failed;
1475
        try testing::expect(indexTy == super::Type::U32);
1476
    }
1477
}
1478
1479
@test unsafe fn testResolveForSliceIterable() throws (testing::TestError) {
1480
    let mut testArena76 = testArena();
1481
    let testStorage76: 'test76 = &mut testArena76 in {
1482
        let mut a = testResolver(testStorage76);
1483
        let program = "let xs: [i32; 3] = [1, 2, 3]; for x in &xs[..] { x; }";
1484
        let result = try resolveProgramStr(&mut a, program);
1485
        try expectNoErrors(&result);
1486
1487
        let forStmt = try parser::tests::getBlockLastStmt(result.root);
1488
        let case ast::NodeValue::For(loopNode) = forStmt.value
1489
            else throw testing::TestError::Failed;
1490
1491
        let bindingTy = super::typeFor(&a, loopNode.binding)
1492
            else throw testing::TestError::Failed;
1493
        try testing::expect(bindingTy == super::Type::I32);
1494
    }
1495
}
1496
1497
@test unsafe fn testResolveForRequiresIterable() throws (testing::TestError) {
1498
    let mut testArena77 = testArena();
1499
    let testStorage77: 'test77 = &mut testArena77 in {
1500
        let mut a = testResolver(testStorage77);
1501
        let result = try resolveProgramStr(&mut a, "for x in true { x; }");
1502
        try expectErrorKind(&result, super::ErrorKind::ExpectedIterable);
1503
    }
1504
}
1505
1506
@test unsafe fn testResolveForRangeBoundsMustNumeric() throws (testing::TestError) {
1507
    let mut testArena78 = testArena();
1508
    let testStorage78: 'test78 = &mut testArena78 in {
1509
        let mut a = testResolver(testStorage78);
1510
        let result = try resolveBlockStr(&mut a, "for i in 0..true { i; }");
1511
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
1512
    }
1513
}
1514
1515
@test unsafe fn testResolveMatchPatternTypeMismatch() throws (testing::TestError) {
1516
    let mut testArena79 = testArena();
1517
    let testStorage79: 'test79 = &mut testArena79 in {
1518
        let mut a = testResolver(testStorage79);
1519
        let program = "let val: i32 = 0; match val { case true => {} }";
1520
        let result = try resolveProgramStr(&mut a, program);
1521
        let err = try expectError(&result);
1522
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
1523
    }
1524
}
1525
1526
@test unsafe fn testResolveMatchUnionVariantTypeMismatch() throws (testing::TestError) {
1527
    let mut testArena80 = testArena();
1528
    let testStorage80: 'test80 = &mut testArena80 in {
1529
        let mut a = testResolver(testStorage80);
1530
        let program = "union First { A }  union Second { B } fn run(val: First) { match val { case Second::B => {} } }";
1531
        let result = try resolveProgramStr(&mut a, program);
1532
        let err = try expectError(&result);
1533
1534
        let firstTy = try getTypeInScopeOf(&a, result.root, "First");
1535
        let secondTy = try getTypeInScopeOf(&a, result.root, "Second");
1536
        try expectTypeMismatch(err, super::Type::Nominal(firstTy), super::Type::Nominal(secondTy));
1537
    }
1538
}
1539
1540
@test unsafe fn testResolveMatchUnionPayloadMissing() throws (testing::TestError) {
1541
    let mut testArena81 = testArena();
1542
    let testStorage81: 'test81 = &mut testArena81 in {
1543
        let mut a = testResolver(testStorage81);
1544
        let program = "union Opt { Some(i32) } fn run(val: Opt) { match val { case Opt::Some => {} } }";
1545
        let result = try resolveProgramStr(&mut a, program);
1546
        try expectErrorKind(&result, super::ErrorKind::UnionVariantPayloadMissing("Some"));
1547
    }
1548
}
1549
1550
@test unsafe fn testResolveMatchUnionVoidVariantExplicitDiscriminant() throws (testing::TestError) {
1551
    let mut testArena82 = testArena();
1552
    let testStorage82: 'test82 = &mut testArena82 in {
1553
        let mut a = testResolver(testStorage82);
1554
        let program = "union Opt { Some = 5 } fn run(val: Opt) { match val { case Opt::Some => {} } }";
1555
        let result = try resolveProgramStr(&mut a, program);
1556
        try expectNoErrors(&result);
1557
    }
1558
}
1559
1560
@test unsafe fn testResolveMatchUnionPayloadUnexpected() throws (testing::TestError) {
1561
    let mut testArena83 = testArena();
1562
    let testStorage83: 'test83 = &mut testArena83 in {
1563
        let mut a = testResolver(testStorage83);
1564
        let program = "union Opt { None } fn run(val: Opt) { match val { case Opt::None(x) => {} } }";
1565
        let result = try resolveProgramStr(&mut a, program);
1566
        try expectErrorKind(&result, super::ErrorKind::UnionVariantPayloadUnexpected("None"));
1567
    }
1568
}
1569
1570
@test unsafe fn testResolveMatchUnionUnknownVariant() throws (testing::TestError) {
1571
    let mut testArena84 = testArena();
1572
    let testStorage84: 'test84 = &mut testArena84 in {
1573
        let mut a = testResolver(testStorage84);
1574
        let program = "union Opt { Some, None } fn run(value: Opt) { match value { case Opt::Unknown => {} } }";
1575
        let result = try resolveProgramStr(&mut a, program);
1576
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
1577
    }
1578
}
1579
1580
@test unsafe fn testResolveMatchUnionNonExhaustive() throws (testing::TestError) {
1581
    {
1582
        let mut testArena85 = testArena();
1583
        let testStorage85: 'test85 = &mut testArena85 in {
1584
            let mut a = testResolver(testStorage85);
1585
            let program = "union Opt { Some, None } fn run(value: Opt) { match value { case Opt::Some => {} } }";
1586
            let result = try resolveProgramStr(&mut a, program);
1587
            try expectErrorKind(&result, super::ErrorKind::UnionMatchNonExhaustive("None"));
1588
        }
1589
    } {
1590
        let mut testArena86 = testArena();
1591
        let testStorage86: 'test86 = &mut testArena86 in {
1592
            let mut a = testResolver(testStorage86);
1593
            let program = "union Opt { Some, None } fn run(value: Opt) { match value { else => {} } }";
1594
            let result = try resolveProgramStr(&mut a, program);
1595
            try expectNoErrors(&result);
1596
        }
1597
    }
1598
}
1599
1600
@test unsafe fn testResolveMatchUnionNonExhaustiveExplicitDiscriminants() throws (testing::TestError) {
1601
    let mut testArena87 = testArena();
1602
    let testStorage87: 'test87 = &mut testArena87 in {
1603
        let mut a = testResolver(testStorage87);
1604
        let program = "union U { A = 3, B = 9 } fn run(value: U) { match value { case U::A => {}, case U::B => {} } }";
1605
        let result = try resolveProgramStr(&mut a, program);
1606
        try expectNoErrors(&result);
1607
    }
1608
}
1609
1610
@test unsafe fn testResolveMatchUnionBindingScope() throws (testing::TestError) {
1611
    let mut testArena88 = testArena();
1612
    let testStorage88: 'test88 = &mut testArena88 in {
1613
        let mut a = testResolver(testStorage88);
1614
        let program = "union Opt { Some(i32), None } fn f(value: Opt) { match value { case Opt::Some(x) if x > 0 => { x; } else => {} } }";
1615
        let result = try resolveProgramStr(&mut a, program);
1616
        try expectNoErrors(&result);
1617
1618
        let fnBlock = try getFnBody(&a, result.root, "f");
1619
        try testing::expect(fnBlock.statements.len > 0);
1620
1621
        let matchNode = fnBlock.statements[0];
1622
        let case ast::NodeValue::Match(sw) = matchNode.value
1623
            else throw testing::TestError::Failed;
1624
        let caseNode = sw.prongs[0];
1625
1626
        let scope = super::scopeFor(&a, caseNode)
1627
            else throw testing::TestError::Failed;
1628
        let payloadSym = super::findSymbolInScope(scope, "x")
1629
            else throw testing::TestError::Failed;
1630
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
1631
            else throw testing::TestError::Failed;
1632
        try testing::expect(payloadValType == super::Type::I32);
1633
    }
1634
}
1635
1636
@test unsafe fn testResolveMatchUnionPatternNonUnionType() throws (testing::TestError) {
1637
    let mut testArena89 = testArena();
1638
    let testStorage89: 'test89 = &mut testArena89 in {
1639
        let mut a = testResolver(testStorage89);
1640
        let program = "union Opt { Some, None } fn f(value: Opt) { match value { case true => {} } }";
1641
        let result = try resolveProgramStr(&mut a, program);
1642
        let err = try expectError(&result);
1643
        let optionTy = try getTypeInScopeOf(&a, result.root, "Opt");
1644
        try expectTypeMismatch(err, super::Type::Nominal(optionTy), super::Type::Bool);
1645
    }
1646
}
1647
1648
@test unsafe fn testResolveMatchGuardForms() throws (testing::TestError) {
1649
    let mut testArena90 = testArena();
1650
    let testStorage90: 'test90 = &mut testArena90 in {
1651
        let mut a = testResolver(testStorage90);
1652
        let program = "fn first(value: i32) { match value { case _ if true => {}, else => {} } }";
1653
        let result = try resolveProgramStr(&mut a, program);
1654
        try expectNoErrors(&result);
1655
    }
1656
}
1657
1658
/// Test that a binding prong binds the subject to the identifier.
1659
@test unsafe fn testResolveMatchBindingProng() throws (testing::TestError) {
1660
    let mut testArena91 = testArena();
1661
    let testStorage91: 'test91 = &mut testArena91 in {
1662
        let mut a = testResolver(testStorage91);
1663
        let program = "fn f(value: i32) -> i32 { match value { x => return x } }";
1664
        let result = try resolveProgramStr(&mut a, program);
1665
        try expectNoErrors(&result);
1666
    }
1667
}
1668
1669
/// Test that a binding prong with guard can use the bound variable.
1670
@test unsafe fn testResolveMatchBindingProngGuard() throws (testing::TestError) {
1671
    let mut testArena92 = testArena();
1672
    let testStorage92: 'test92 = &mut testArena92 in {
1673
        let mut a = testResolver(testStorage92);
1674
        let program = "fn f(value: i32) -> i32 { match value { x if x > 0 => return x, _ => return 0 } }";
1675
        let result = try resolveProgramStr(&mut a, program);
1676
        try expectNoErrors(&result);
1677
    }
1678
}
1679
1680
/// Test that a binding prong covers all union variants for exhaustiveness.
1681
@test unsafe fn testResolveMatchBindingProngExhaustive() throws (testing::TestError) {
1682
    let mut testArena93 = testArena();
1683
    let testStorage93: 'test93 = &mut testArena93 in {
1684
        let mut a = testResolver(testStorage93);
1685
        let program = "union U { A, B, C } fn f(u: U) -> i32 { match u { x => return 0 } }";
1686
        let result = try resolveProgramStr(&mut a, program);
1687
        try expectNoErrors(&result);
1688
    }
1689
}
1690
1691
/// Test that `case x =>` fails if `x` is not in scope, since bare identifiers
1692
/// in case patterns are values to compare against, not bindings.
1693
@test unsafe fn testResolveMatchCaseUndefinedIdent() throws (testing::TestError) {
1694
    let mut testArena94 = testArena();
1695
    let testStorage94: 'test94 = &mut testArena94 in {
1696
        let mut a = testResolver(testStorage94);
1697
        let program = "fn f(n: i32) -> i32 { match n { case x => return 0 } }";
1698
        let result = try resolveProgramStr(&mut a, program);
1699
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1700
    }
1701
}
1702
1703
/// Test matching on optionals: exhaustiveness and type unwrapping.
1704
@test unsafe fn testResolveMatchOptional() throws (testing::TestError) {
1705
    {
1706
        // Exhaustive: binding + nil case.
1707
        let mut testArena95 = testArena();
1708
        let testStorage95: 'test95 = &mut testArena95 in {
1709
            let mut a = testResolver(testStorage95);
1710
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {} } }";
1711
            let result = try resolveProgramStr(&mut a, program);
1712
            try expectNoErrors(&result);
1713
        }
1714
    } {
1715
        // Missing nil case.
1716
        let mut testArena96 = testArena();
1717
        let testStorage96: 'test96 = &mut testArena96 in {
1718
            let mut a = testResolver(testStorage96);
1719
            let program = "fn f(opt: ?i32) { match opt { v => {} } }";
1720
            let result = try resolveProgramStr(&mut a, program);
1721
            try expectErrorKind(&result, super::ErrorKind::OptionalMatchMissingNil);
1722
        }
1723
    } {
1724
        // Missing value case.
1725
        let mut testArena97 = testArena();
1726
        let testStorage97: 'test97 = &mut testArena97 in {
1727
            let mut a = testResolver(testStorage97);
1728
            let program = "fn f(opt: ?i32) { match opt { case nil => {} } }";
1729
            let result = try resolveProgramStr(&mut a, program);
1730
            try expectErrorKind(&result, super::ErrorKind::OptionalMatchMissingValue);
1731
        }
1732
    } {
1733
        // Else covers both cases.
1734
        let mut testArena98 = testArena();
1735
        let testStorage98: 'test98 = &mut testArena98 in {
1736
            let mut a = testResolver(testStorage98);
1737
            let program = "fn f(opt: ?i32) { match opt { else => {} } }";
1738
            let result = try resolveProgramStr(&mut a, program);
1739
            try expectNoErrors(&result);
1740
        }
1741
    } {
1742
        // Binding unwraps the inner type.
1743
        let mut testArena99 = testArena();
1744
        let testStorage99: 'test99 = &mut testArena99 in {
1745
            let mut a = testResolver(testStorage99);
1746
            let program = "fn f(opt: ?i32) -> i32 { match opt { v => return v + 1, case nil => return 0 } }";
1747
            let result = try resolveProgramStr(&mut a, program);
1748
            try expectNoErrors(&result);
1749
        }
1750
    }
1751
}
1752
1753
/// Test that match on non-union types requires exhaustiveness.
1754
@test unsafe fn testResolveMatchGenericExhaustive() throws (testing::TestError) {
1755
    {
1756
        // Match on i32 without catch-all should error.
1757
        let mut testArena100 = testArena();
1758
        let testStorage100: 'test100 = &mut testArena100 in {
1759
            let mut a = testResolver(testStorage100);
1760
            let program = "fn f(x: i32) { match x { case 1 => {} } }";
1761
            let result = try resolveProgramStr(&mut a, program);
1762
            try expectErrorKind(&result, super::ErrorKind::MatchNonExhaustive);
1763
        }
1764
    } {
1765
        // Match on i32 with else is fine.
1766
        let mut testArena101 = testArena();
1767
        let testStorage101: 'test101 = &mut testArena101 in {
1768
            let mut a = testResolver(testStorage101);
1769
            let program = "fn f(x: i32) { match x { case 1 => {}, else => {} } }";
1770
            let result = try resolveProgramStr(&mut a, program);
1771
            try expectNoErrors(&result);
1772
        }
1773
    } {
1774
        // Match on i32 with binding catch-all is fine.
1775
        let mut testArena102 = testArena();
1776
        let testStorage102: 'test102 = &mut testArena102 in {
1777
            let mut a = testResolver(testStorage102);
1778
            let program = "fn f(x: i32) { match x { y => {} } }";
1779
            let result = try resolveProgramStr(&mut a, program);
1780
            try expectNoErrors(&result);
1781
        }
1782
    } {
1783
        // Match on i32 with wildcard catch-all is fine.
1784
        let mut testArena103 = testArena();
1785
        let testStorage103: 'test103 = &mut testArena103 in {
1786
            let mut a = testResolver(testStorage103);
1787
            let program = "fn f(x: i32) { match x { case _ => {} } }";
1788
            let result = try resolveProgramStr(&mut a, program);
1789
            try expectNoErrors(&result);
1790
        }
1791
    }
1792
}
1793
1794
/// Test that match on bool requires both true and false cases.
1795
@test unsafe fn testResolveMatchBoolExhaustive() throws (testing::TestError) {
1796
    {
1797
        // Match on bool with both cases is fine.
1798
        let mut testArena104 = testArena();
1799
        let testStorage104: 'test104 = &mut testArena104 in {
1800
            let mut a = testResolver(testStorage104);
1801
            let program = "fn f(x: bool) { match x { case true => {}, case false => {} } }";
1802
            let result = try resolveProgramStr(&mut a, program);
1803
            try expectNoErrors(&result);
1804
        }
1805
    } {
1806
        // Match on bool missing true should error.
1807
        let mut testArena105 = testArena();
1808
        let testStorage105: 'test105 = &mut testArena105 in {
1809
            let mut a = testResolver(testStorage105);
1810
            let program = "fn f(x: bool) { match x { case false => {} } }";
1811
            let result = try resolveProgramStr(&mut a, program);
1812
            try expectErrorKind(&result, super::ErrorKind::BoolMatchMissing(true));
1813
        }
1814
    } {
1815
        // Match on bool missing false should error.
1816
        let mut testArena106 = testArena();
1817
        let testStorage106: 'test106 = &mut testArena106 in {
1818
            let mut a = testResolver(testStorage106);
1819
            let program = "fn f(x: bool) { match x { case true => {} } }";
1820
            let result = try resolveProgramStr(&mut a, program);
1821
            try expectErrorKind(&result, super::ErrorKind::BoolMatchMissing(false));
1822
        }
1823
    } {
1824
        // Match on bool with else is fine.
1825
        let mut testArena107 = testArena();
1826
        let testStorage107: 'test107 = &mut testArena107 in {
1827
            let mut a = testResolver(testStorage107);
1828
            let program = "fn f(x: bool) { match x { else => {} } }";
1829
            let result = try resolveProgramStr(&mut a, program);
1830
            try expectNoErrors(&result);
1831
        }
1832
    } {
1833
        // Match on bool with binding catch-all is fine.
1834
        let mut testArena108 = testArena();
1835
        let testStorage108: 'test108 = &mut testArena108 in {
1836
            let mut a = testResolver(testStorage108);
1837
            let program = "fn f(x: bool) { match x { b => {} } }";
1838
            let result = try resolveProgramStr(&mut a, program);
1839
            try expectNoErrors(&result);
1840
        }
1841
    }
1842
}
1843
1844
@test unsafe fn testResolveBreakRequiresLoop() throws (testing::TestError) {
1845
    {
1846
        let mut testArena109 = testArena();
1847
        let testStorage109: 'test109 = &mut testArena109 in {
1848
            let mut a = testResolver(testStorage109);
1849
            let result = try resolveProgramStr(&mut a, "break;");
1850
            try expectErrorKind(&result, super::ErrorKind::InvalidLoopControl);
1851
        }
1852
    } {
1853
        let mut testArena110 = testArena();
1854
        let testStorage110: 'test110 = &mut testArena110 in {
1855
            let mut a = testResolver(testStorage110);
1856
            let result = try resolveProgramStr(&mut a, "loop { break }");
1857
            try expectNoErrors(&result);
1858
        }
1859
    }
1860
}
1861
1862
@test unsafe fn testResolveContinueRequiresLoop() throws (testing::TestError) {
1863
    {
1864
        let mut testArena111 = testArena();
1865
        let testStorage111: 'test111 = &mut testArena111 in {
1866
            let mut a = testResolver(testStorage111);
1867
            let result = try resolveProgramStr(&mut a, "continue;");
1868
            try expectErrorKind(&result, super::ErrorKind::InvalidLoopControl);
1869
        }
1870
    } {
1871
        let mut testArena112 = testArena();
1872
        let testStorage112: 'test112 = &mut testArena112 in {
1873
            let mut a = testResolver(testStorage112);
1874
            let result = try resolveProgramStr(&mut a, "while true { continue }");
1875
            try expectNoErrors(&result);
1876
        }
1877
    }
1878
}
1879
1880
@test unsafe fn testResolveFnTypeVoidNoParams() throws (testing::TestError) {
1881
    let mut testArena113 = testArena();
1882
    let testStorage113: 'test113 = &mut testArena113 in {
1883
        let mut a = testResolver(testStorage113);
1884
        let result = try resolveProgramStr(&mut a, "fn f() {} f();");
1885
        try expectNoErrors(&result);
1886
1887
        let blockNode = result.root;
1888
        let case ast::NodeValue::Block(block) = blockNode.value
1889
            else throw testing::TestError::Failed;
1890
        let fnNode = try getBlockStmt(blockNode, 0);
1891
        let callStmt = try getBlockStmt(blockNode, 1);
1892
1893
        { // Verify the function symbol captures an empty parameter list and void return.
1894
            let sym = super::symbolFor(&a, fnNode)
1895
                else throw testing::TestError::Failed;
1896
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
1897
                else throw testing::TestError::Failed;
1898
            try testing::expect(fnTy.paramTypes.len == 0);
1899
            try testing::expect(*fnTy.returnType == super::Type::Void);
1900
        }
1901
        { // Checking that the type of the call matches the function return type.
1902
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
1903
1904
            let fnSym = super::symbolFor(&a, fnNode)
1905
                else throw testing::TestError::Failed;
1906
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
1907
                else throw testing::TestError::Failed;
1908
            try expectType(&a, callExpr, *fnTy.returnType);
1909
        }
1910
    }
1911
}
1912
1913
@test unsafe fn testResolveFnTypeReturnsValue() throws (testing::TestError) {
1914
    let mut testArena114 = testArena();
1915
    let testStorage114: 'test114 = &mut testArena114 in {
1916
        let mut a = testResolver(testStorage114);
1917
        let program = "fn f() -> i32 { return 1; } f();";
1918
        let result = try resolveProgramStr(&mut a, program);
1919
        try expectNoErrors(&result);
1920
1921
        let blockNode = result.root;
1922
        let case ast::NodeValue::Block(block) = blockNode.value
1923
            else throw testing::TestError::Failed;
1924
        let fnNode = try getBlockStmt(blockNode, 0);
1925
        let callStmt = try getBlockStmt(blockNode, 1);
1926
1927
        { // Function returns i32 with no parameters.
1928
            let sym = super::symbolFor(&a, fnNode)
1929
                else throw testing::TestError::Failed;
1930
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
1931
                else throw testing::TestError::Failed;
1932
            try testing::expect(fnTy.paramTypes.len == 0);
1933
            try testing::expect(*fnTy.returnType == super::Type::I32);
1934
        }
1935
        { // Call expression should inherit the function's return type.
1936
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::I32);
1937
1938
            let fnSym = super::symbolFor(&a, fnNode)
1939
                else throw testing::TestError::Failed;
1940
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
1941
                else throw testing::TestError::Failed;
1942
            try expectType(&a, callExpr, *fnTy.returnType);
1943
        }
1944
    }
1945
}
1946
1947
@test unsafe fn testResolveFnTypeSingleParam() throws (testing::TestError) {
1948
    let mut testArena115 = testArena();
1949
    let testStorage115: 'test115 = &mut testArena115 in {
1950
        let mut a = testResolver(testStorage115);
1951
        let program = "fn f(x: i8) {} let x: i8 = 1; f(x);";
1952
        let result = try resolveProgramStr(&mut a, program);
1953
        try expectNoErrors(&result);
1954
1955
        let blockNode = result.root;
1956
        let case ast::NodeValue::Block(block) = blockNode.value
1957
            else throw testing::TestError::Failed;
1958
        let fnNode = try getBlockStmt(blockNode, 0);
1959
        let callStmt = try getBlockStmt(blockNode, 2);
1960
1961
        { // Single parameter propagates nominal type onto the symbol and parameter node.
1962
            let sym = super::symbolFor(&a, fnNode)
1963
                else throw testing::TestError::Failed;
1964
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
1965
                else throw testing::TestError::Failed;
1966
            try testing::expect(fnTy.paramTypes.len == 1);
1967
            try testing::expect(*fnTy.paramTypes[0] == super::Type::I8);
1968
            try testing::expect(*fnTy.returnType == super::Type::Void);
1969
1970
            let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
1971
                else throw testing::TestError::Failed;
1972
            try testing::expect(fnDecl.sig.params.len == 1);
1973
1974
            let paramNode = fnDecl.sig.params[0];
1975
            try expectType(&a, paramNode, super::Type::I8);
1976
        }
1977
        { // Call should resolve to void, matching the function's return type.
1978
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
1979
            let fnSym = super::symbolFor(&a, fnNode)
1980
                else throw testing::TestError::Failed;
1981
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
1982
                else throw testing::TestError::Failed;
1983
            try expectType(&a, callExpr, *fnTy.returnType);
1984
        }
1985
    }
1986
}
1987
1988
@test unsafe fn testResolveFnTypeMultipleParams() throws (testing::TestError) {
1989
    let mut testArena116 = testArena();
1990
    let testStorage116: 'test116 = &mut testArena116 in {
1991
        let mut a = testResolver(testStorage116);
1992
        let program = "fn f(x: i8, y: i32) {} let x: i8 = 1; let y: i32 = 2; f(x, y);";
1993
        let result = try resolveProgramStr(&mut a, program);
1994
        try expectNoErrors(&result);
1995
1996
        let blockNode = result.root;
1997
        let case ast::NodeValue::Block(block) = blockNode.value
1998
            else throw testing::TestError::Failed;
1999
        let fnNode = try getBlockStmt(blockNode, 0);
2000
        let callStmt = try getBlockStmt(blockNode, 3);
2001
2002
        { // Ensure multi-parameter signatures record both argument types.
2003
            let sym = super::symbolFor(&a, fnNode)
2004
                else throw testing::TestError::Failed;
2005
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2006
                else throw testing::TestError::Failed;
2007
            try testing::expect(fnTy.paramTypes.len == 2);
2008
            try testing::expect(*fnTy.paramTypes[0] == super::Type::I8);
2009
            try testing::expect(*fnTy.paramTypes[1] == super::Type::I32);
2010
            try testing::expect(*fnTy.returnType == super::Type::Void);
2011
2012
            let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
2013
                else throw testing::TestError::Failed;
2014
            try testing::expect(fnDecl.sig.params.len == 2);
2015
2016
            let firstParam = fnDecl.sig.params[0];
2017
            let secondParam = fnDecl.sig.params[1];
2018
            try expectType(&a, firstParam, super::Type::I8);
2019
            try expectType(&a, secondParam, super::Type::I32);
2020
        }
2021
        { // Call expression should again mirror the function return type.
2022
            let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
2023
            let fnSym = super::symbolFor(&a, fnNode)
2024
                else throw testing::TestError::Failed;
2025
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
2026
                else throw testing::TestError::Failed;
2027
            try expectType(&a, callExpr, *fnTy.returnType);
2028
        }
2029
    }
2030
}
2031
2032
@test unsafe fn testResolveFnRecursiveCall() throws (testing::TestError) {
2033
    let mut testArena117 = testArena();
2034
    let testStorage117: 'test117 = &mut testArena117 in {
2035
        let mut a = testResolver(testStorage117);
2036
        let program = "fn flip(b: bool) -> bool { if b { return false; } return flip(false); }";
2037
        let result = try resolveProgramStr(&mut a, program);
2038
        try expectNoErrors(&result);
2039
2040
        let blockNode = result.root;
2041
        let case ast::NodeValue::Block(block) = blockNode.value
2042
            else throw testing::TestError::Failed;
2043
        let fnNode = try getBlockStmt(blockNode, 0);
2044
2045
        { // Function symbol should be visible for recursive calls within its own body.
2046
            let sym = super::symbolFor(&a, fnNode)
2047
                else throw testing::TestError::Failed;
2048
            let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
2049
                else throw testing::TestError::Failed;
2050
            try testing::expect(fnTy.paramTypes.len == 1);
2051
            try testing::expect(*fnTy.paramTypes[0] == super::Type::Bool);
2052
            try testing::expect(*fnTy.returnType == super::Type::Bool);
2053
        }
2054
    }
2055
}
2056
2057
@test unsafe fn testResolveFnCallMissingArgument() throws (testing::TestError) {
2058
    let mut testArena118 = testArena();
2059
    let testStorage118: 'test118 = &mut testArena118 in {
2060
        let mut a = testResolver(testStorage118);
2061
        let program = "fn f(x: i8) {} f();";
2062
        let result = try resolveProgramStr(&mut a, program);
2063
        // Expect an error when a required parameter is omitted.
2064
        try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
2065
            expected: 1,
2066
            actual: 0,
2067
        }));
2068
    }
2069
}
2070
2071
@test unsafe fn testResolveFnCallExtraArgument() throws (testing::TestError) {
2072
    let mut testArena119 = testArena();
2073
    let testStorage119: 'test119 = &mut testArena119 in {
2074
        let mut a = testResolver(testStorage119);
2075
        let program = "fn f() {} f(1);";
2076
        let result = try resolveProgramStr(&mut a, program);
2077
        // Passing more arguments than declared should fail.
2078
        try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
2079
            expected: 0,
2080
            actual: 1,
2081
        }));
2082
    }
2083
}
2084
2085
@test unsafe fn testResolveFnCallArgumentTypeMismatch() throws (testing::TestError) {
2086
    let mut testArena120 = testArena();
2087
    let testStorage120: 'test120 = &mut testArena120 in {
2088
        let mut a = testResolver(testStorage120);
2089
        let program = "fn f(x: i8) {} f(true);";
2090
        let result = try resolveProgramStr(&mut a, program);
2091
        let err = try expectError(&result);
2092
        // The argument type (bool) should not match the parameter type (i8).
2093
        try expectTypeMismatch(err, super::Type::I8, super::Type::Bool);
2094
    }
2095
}
2096
2097
@test unsafe fn testResolveFnReturnTypeMismatch() throws (testing::TestError) {
2098
    let mut testArena121 = testArena();
2099
    let testStorage121: 'test121 = &mut testArena121 in {
2100
        let mut a = testResolver(testStorage121);
2101
        let program = "fn f() -> i32 { return true; }";
2102
        let result = try resolveProgramStr(&mut a, program);
2103
        let err = try expectError(&result);
2104
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
2105
    }
2106
}
2107
2108
@test unsafe fn testResolveFnReturnVoid() throws (testing::TestError) {
2109
    {
2110
        let mut testArena122 = testArena();
2111
        let testStorage122: 'test122 = &mut testArena122 in {
2112
            let mut a = testResolver(testStorage122);
2113
            let result = try resolveProgramStr(&mut a, "fn f() { return; }");
2114
            try expectNoErrors(&result);
2115
        }
2116
    } {
2117
        let mut testArena123 = testArena();
2118
        let testStorage123: 'test123 = &mut testArena123 in {
2119
            let mut a = testResolver(testStorage123);
2120
            let result = try resolveProgramStr(&mut a, "fn g() -> i32 { return; }");
2121
            let err = try expectError(&result);
2122
            try expectTypeMismatch(err, super::Type::I32, super::Type::Void);
2123
        }
2124
    }
2125
}
2126
2127
@test unsafe fn testResolveFnMissingReturn() throws (testing::TestError) {
2128
    {
2129
        let mut testArena124 = testArena();
2130
        let testStorage124: 'test124 = &mut testArena124 in {
2131
            let mut a = testResolver(testStorage124);
2132
            let result = try resolveProgramStr(&mut a, "fn f() -> i32 {}");
2133
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2134
        }
2135
    } {
2136
        let mut testArena125 = testArena();
2137
        let testStorage125: 'test125 = &mut testArena125 in {
2138
            let mut a = testResolver(testStorage125);
2139
            let program = "fn g(flag: bool) -> i32 { if flag { return 1; } 2; }";
2140
            let result = try resolveProgramStr(&mut a, program);
2141
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2142
        }
2143
    }
2144
}
2145
2146
/// Never-returning functions require divergence on every path.
2147
@test unsafe fn testResolveNeverReturn() throws (testing::TestError) {
2148
    for program in &[
2149
        "fn stop() -> ! { panic; } fn f() -> i32 { stop(); }",
2150
        "fn stop() -> ! { panic; } fn f() -> ! { return stop(); }",
2151
        "fn f(callback: fn() -> !) -> ! { callback(); }",
2152
        "fn stop() -> ! { panic; } fn f() -> ! { let _ = stop(); }",
2153
        "fn stop() -> ! { panic; } fn f() -> i32 { let value: i32 = stop(); }",
2154
        "union Token: Once { Held(u32) } fn stop() -> ! { panic; } fn f(token: Token) -> ! { stop(); }",
2155
        "union Token: Once { Held(u32) } fn stop() -> ! { panic; } fn f(token: Token) -> ! { return stop(); }",
2156
        "union Token: Once { Held(u32) } fn stop() -> ! throws (i32) { throw 1; } fn f(token: Token) -> ! { try! stop(); }",
2157
        "fn f() -> ! { while true {} }",
2158
        "fn f(flag: bool) -> ! { if flag { panic; } else { while true {} } }",
2159
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! throws (i32) { try f(); }",
2160
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> i32 { try f() catch { return 2; }; }",
2161
    ] {
2162
        let mut testArena126 = testArena();
2163
        let testStorage126: 'test126 = &mut testArena126 in {
2164
            let mut a = testResolver(testStorage126);
2165
            let result = try resolveProgramStr(&mut a, program);
2166
            try expectNoErrors(&result);
2167
        }
2168
    }
2169
}
2170
2171
/// A never-returning signature rejects any normal completion path.
2172
@test unsafe fn testResolveNeverFallthrough() throws (testing::TestError) {
2173
    for program in &[
2174
        "fn f() -> ! {}",
2175
        "fn f(flag: bool) -> ! { if flag { panic; } }",
2176
        "fn f() -> ! { while true { break; } }",
2177
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! { try f() catch {}; }",
2178
        "fn f() -> ! throws (i32) { throw 1; } fn g() -> ! { try f() catch e as i32 {}; }",
2179
    ] {
2180
        let mut testArena127 = testArena();
2181
        let testStorage127: 'test127 = &mut testArena127 in {
2182
            let mut a = testResolver(testStorage127);
2183
            let result = try resolveProgramStr(&mut a, program);
2184
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2185
        }
2186
    }
2187
}
2188
2189
/// No value, including undefined, can construct a never return value.
2190
@test unsafe fn testResolveNeverValue() throws (testing::TestError) {
2191
    for program in &[
2192
        "fn f() -> ! { return; }",
2193
        "fn f() -> ! { return 1; }",
2194
        "unsafe fn f() -> ! { return undefined; }",
2195
        "fn ordinary() {} fn f() { let callback: fn() -> ! = ordinary; }",
2196
    ] {
2197
        let mut testArena128 = testArena();
2198
        let testStorage128: 'test128 = &mut testArena128 in {
2199
            let mut a = testResolver(testStorage128);
2200
            let result = try resolveProgramStr(&mut a, program);
2201
            let error = try expectError(&result);
2202
        }
2203
    }
2204
}
2205
2206
/// Caught errors preserve the caller's exact-use ownership obligations.
2207
@test unsafe fn testResolveNeverCaughtOwnership() throws (testing::TestError) {
2208
    for program in &[
2209
        "union Token: Once { Held(u32) } fn fail() -> ! throws (i32) { throw 1; } fn f(token: Token) { try fail() catch {}; }",
2210
        "union Token: Once { Held(u32) } fn fail() -> ! throws (i32) { throw 1; } fn f(token: Token) { let absent = try? fail(); }",
2211
    ] {
2212
        let mut testArena129 = testArena();
2213
        let testStorage129: 'test129 = &mut testArena129 in {
2214
            let mut a = testResolver(testStorage129);
2215
            let result = try resolveProgramStr(&mut a, program);
2216
            let error = try expectError(&result);
2217
            let case super::ErrorKind::LinearNotConsumed(_) = error.kind
2218
                else throw testing::TestError::Failed;
2219
        }
2220
    }
2221
}
2222
2223
@test unsafe fn testResolveFnAllPathsReturn() throws (testing::TestError) {
2224
    let mut testArena130 = testArena();
2225
    let testStorage130: 'test130 = &mut testArena130 in {
2226
        let mut a = testResolver(testStorage130);
2227
        let program = "fn h(flag: bool) -> i32 { if flag { return 1; } else { return 2; } }";
2228
        let result = try resolveProgramStr(&mut a, program);
2229
        try expectNoErrors(&result);
2230
    }
2231
}
2232
2233
/// Test that match statements with returns in all branches don't require a
2234
/// return at the end of the function.
2235
@test unsafe fn testResolveFnMatchAllPathsReturn() throws (testing::TestError) {
2236
    {
2237
        // Union match with all variants returning.
2238
        let mut testArena131 = testArena();
2239
        let testStorage131: 'test131 = &mut testArena131 in {
2240
            let mut a = testResolver(testStorage131);
2241
            let program = "union E { A, B } fn f(e: E) -> i32 { match e { case E::A => return 1, case E::B => return 2 } }";
2242
            let result = try resolveProgramStr(&mut a, program);
2243
            try expectNoErrors(&result);
2244
        }
2245
    } {
2246
        // Match with default case where all branches return.
2247
        let mut testArena132 = testArena();
2248
        let testStorage132: 'test132 = &mut testArena132 in {
2249
            let mut a = testResolver(testStorage132);
2250
            let program = "fn f(x: i32) -> i32 { match x { case 1 => return 1, else => return 0, } }";
2251
            let result = try resolveProgramStr(&mut a, program);
2252
            try expectNoErrors(&result);
2253
        }
2254
    } {
2255
        // Match where not all branches return should error.
2256
        let mut testArena133 = testArena();
2257
        let testStorage133: 'test133 = &mut testArena133 in {
2258
            let mut a = testResolver(testStorage133);
2259
            let program = "union E { A, B } fn f(e: E) -> i32 { match e { case E::A => return 1, case E::B => {} } }";
2260
            let result = try resolveProgramStr(&mut a, program);
2261
            try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
2262
        }
2263
    }
2264
}
2265
2266
@test unsafe fn testResolveAssign() throws (testing::TestError) {
2267
    {
2268
        let mut testArena134 = testArena();
2269
        let testStorage134: 'test134 = &mut testArena134 in {
2270
            let mut a = testResolver(testStorage134);
2271
            let result = try resolveProgramStr(&mut a, "let mut x: i32 = 0; set x = 1;");
2272
            try expectNoErrors(&result);
2273
        }
2274
    } {
2275
        let mut testArena135 = testArena();
2276
        let testStorage135: 'test135 = &mut testArena135 in {
2277
            let mut a = testResolver(testStorage135);
2278
            let result = try resolveProgramStr(&mut a, "let x: i32 = 0; set x = 1;");
2279
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2280
        }
2281
    } {
2282
        let mut testArena136 = testArena();
2283
        let testStorage136: 'test136 = &mut testArena136 in {
2284
            let mut a = testResolver(testStorage136);
2285
            let result = try resolveProgramStr(&mut a, "let mut x: bool = false; set x = 1;");
2286
            let err = try expectError(&result);
2287
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
2288
        }
2289
    } {
2290
        let mut testArena137 = testArena();
2291
        let testStorage137: 'test137 = &mut testArena137 in {
2292
            let mut a = testResolver(testStorage137);
2293
            let result = try resolveProgramStr(&mut a, "set x = 1;");
2294
            try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
2295
        }
2296
    } {
2297
        let mut testArena138 = testArena();
2298
        let testStorage138: 'test138 = &mut testArena138 in {
2299
            let mut a = testResolver(testStorage138);
2300
            let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = 1;");
2301
            try expectNoErrors(&result);
2302
        }
2303
    } {
2304
        let mut testArena139 = testArena();
2305
        let testStorage139: 'test139 = &mut testArena139 in {
2306
            let mut a = testResolver(testStorage139);
2307
            let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = nil;");
2308
            try expectNoErrors(&result);
2309
        }
2310
    }
2311
}
2312
2313
@test unsafe fn testResolveAssignSubscript() throws (testing::TestError) {
2314
    {
2315
        let mut testArena140 = testArena();
2316
        let testStorage140: 'test140 = &mut testArena140 in {
2317
            let mut a = testResolver(testStorage140);
2318
            let program = "let mut xs: [u8; 2] = [0, 1]; set xs[0] = 9;";
2319
            let result = try resolveProgramStr(&mut a, program);
2320
            try expectNoErrors(&result);
2321
        }
2322
    }
2323
    {
2324
        let mut testArena141 = testArena();
2325
        let testStorage141: 'test141 = &mut testArena141 in {
2326
            let mut a = testResolver(testStorage141);
2327
            let program = "static xs: [u8; 2] = [0, 1]; let slice: *mut [u8] = &mut xs[..]; set slice[0] = 1;";
2328
            let result = try resolveProgramStr(&mut a, program);
2329
            try expectNoErrors(&result);
2330
        }
2331
    }
2332
    {
2333
        let mut testArena142 = testArena();
2334
        let testStorage142: 'test142 = &mut testArena142 in {
2335
            let mut a = testResolver(testStorage142);
2336
            let program = "static xs: [u8; 2] = [0, 1]; let mut slice: *[u8] = &xs[..]; set slice[0] = 1;";
2337
            let result = try resolveProgramStr(&mut a, program);
2338
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2339
        }
2340
    }
2341
    {
2342
        let mut testArena143 = testArena();
2343
        let testStorage143: 'test143 = &mut testArena143 in {
2344
            let mut a = testResolver(testStorage143);
2345
            let program = "let xs: [u8; 2] = [0, 1]; set xs[0] = 9;";
2346
            let result = try resolveProgramStr(&mut a, program);
2347
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2348
        }
2349
    }
2350
    {
2351
        let mut testArena144 = testArena();
2352
        let testStorage144: 'test144 = &mut testArena144 in {
2353
            let mut a = testResolver(testStorage144);
2354
            let program = "static xs: [u8; 2] = [0, 1]; let slice: *[u8] = &xs[..]; set slice[0] = 1;";
2355
            let result = try resolveProgramStr(&mut a, program);
2356
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2357
        }
2358
    }
2359
}
2360
2361
@test unsafe fn testResolveAssignIntegerLits() throws (testing::TestError) {
2362
    try expectAnalyzeOk("let x: i8 = 127;");
2363
    try expectAnalyzeOk("let x: i8 = 0x7F;");
2364
    try expectAnalyzeOk("let x: i8 = -128;");
2365
    try expectAnalyzeOk("let x: u8 = 255;");
2366
    try expectAnalyzeOk("let x: u8 = 0b11111111;");
2367
    try expectAnalyzeOk("let x: i16 = 0x7FFF;");
2368
    try expectAnalyzeOk("let x: i16 = -32768;");
2369
    try expectAnalyzeOk("let x: u16 = 0xFFFF;");
2370
    try expectAnalyzeOk("let x: i32 = 2147483647;");
2371
    try expectAnalyzeOk("let x: i32 = -2147483648;");
2372
    try expectAnalyzeOk("let x: u32 = 0xFFFFFFFF;");
2373
    try expectAnalyzeOk("let x: i64 = 9223372036854775807;");
2374
    try expectAnalyzeOk("let x: i64 = -9223372036854775808;");
2375
2376
    try expectAnalyzeOk("constant LIMIT: u8 = 0xFF;");
2377
2378
    try expectIntMismatch("let x: i8 = 128;", super::Type::I8);
2379
    try expectIntMismatch("let x: i8 = -129;", super::Type::I8);
2380
    try expectIntMismatch("let x: i8 = 0x80;", super::Type::I8);
2381
    try expectIntMismatch("let x: i8 = 0b10000000;", super::Type::I8);
2382
    try expectIntMismatch("let x: u8 = 256;", super::Type::U8);
2383
    try expectIntMismatch("let x: u8 = -1;", super::Type::U8);
2384
    try expectIntMismatch("let x: u8 = 0b100000000;", super::Type::U8);
2385
    try expectIntMismatch("let x: i16 = 32768;", super::Type::I16);
2386
    try expectIntMismatch("let x: i16 = -32769;", super::Type::I16);
2387
    try expectIntMismatch("let x: u16 = 65536;", super::Type::U16);
2388
    try expectIntMismatch("let x: u16 = -1;", super::Type::U16);
2389
    try expectIntMismatch("let x: i32 = 2147483648;", super::Type::I32);
2390
    try expectIntMismatch("let x: i32 = -2147483649;", super::Type::I32);
2391
    try expectIntMismatch("let x: i32 = 0xFFFFFFFF;", super::Type::I32);
2392
    try expectIntMismatch("let x: u32 = -1;", super::Type::U32);
2393
    try expectIntMismatch("let x: u32 = 0x100000000;", super::Type::U32);
2394
    try expectIntMismatch("let x: i64 = 9223372036854775808;", super::Type::I64);
2395
    try expectIntMismatch("let x: i64 = -9223372036854775809;", super::Type::I64);
2396
    try expectIntMismatch("constant LIMIT: u8 = 512;", super::Type::U8);
2397
    try expectIntMismatch("constant LIMIT: u8 = -5;", super::Type::U8);
2398
}
2399
2400
@test unsafe fn testNilCoercions() throws (testing::TestError) {
2401
    {
2402
        let mut testArena145 = testArena();
2403
        let testStorage145: 'test145 = &mut testArena145 in {
2404
            let mut a = testResolver(testStorage145);
2405
            let result = try resolveBlockStr(&mut a, "let opt: ?i32 = nil;");
2406
            try expectNoErrors(&result);
2407
        }
2408
    } {
2409
        let mut testArena146 = testArena();
2410
        let testStorage146: 'test146 = &mut testArena146 in {
2411
            let mut a = testResolver(testStorage146);
2412
            let program = "fn g(opt: ?i32) {} fn f() { g(nil); }";
2413
            let result = try resolveProgramStr(&mut a, program);
2414
            try expectNoErrors(&result);
2415
        }
2416
    } {
2417
        let mut testArena147 = testArena();
2418
        let testStorage147: 'test147 = &mut testArena147 in {
2419
            let mut a = testResolver(testStorage147);
2420
            let program = "fn make(flag: bool) -> ?i32 { if flag { return 1; } return nil; }";
2421
            let result = try resolveProgramStr(&mut a, program);
2422
            try expectNoErrors(&result);
2423
        }
2424
    }
2425
}
2426
2427
@test unsafe fn testOptionalComparedWithNil() throws (testing::TestError) {
2428
    let mut testArena148 = testArena();
2429
    let testStorage148: 'test148 = &mut testArena148 in {
2430
        let mut a = testResolver(testStorage148);
2431
        let program = "let opt: ?i32 = nil; opt == nil; nil == opt; opt == 1; 1 == opt; opt == opt; nil == nil;";
2432
        let result = try resolveBlockStr(&mut a, program);
2433
        try expectNoErrors(&result);
2434
2435
        for i in 1..7 {
2436
            let stmt = try getBlockStmt(result.root, i);
2437
            try expectExprStmtType(&a, stmt, super::Type::Bool);
2438
        }
2439
    }
2440
}
2441
2442
@test unsafe fn testResolveRecordLiteralAllFieldsSet() throws (testing::TestError) {
2443
    let mut testArena149 = testArena();
2444
    let testStorage149: 'test149 = &mut testArena149 in {
2445
        let mut a = testResolver(testStorage149);
2446
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1, y: 2 };";
2447
        let result = try resolveProgramStr(&mut a, program);
2448
        try expectNoErrors(&result);
2449
    }
2450
}
2451
2452
@test unsafe fn testResolveRecordLiteralMissingField() throws (testing::TestError) {
2453
    let mut testArena150 = testArena();
2454
    let testStorage150: 'test150 = &mut testArena150 in {
2455
        let mut a = testResolver(testStorage150);
2456
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1 };";
2457
        let result = try resolveProgramStr(&mut a, program);
2458
        try expectErrorKind(&result, super::ErrorKind::RecordFieldMissing("y"));
2459
    }
2460
}
2461
2462
@test unsafe fn testResolveRecordLiteralFieldTypeMismatch() throws (testing::TestError) {
2463
    let mut testArena151 = testArena();
2464
    let testStorage151: 'test151 = &mut testArena151 in {
2465
        let mut a = testResolver(testStorage151);
2466
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: true, y: 2 };";
2467
        let result = try resolveProgramStr(&mut a, program);
2468
        let err = try expectError(&result);
2469
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
2470
2471
        let errNode = err.node
2472
            else throw testing::TestError::Failed;
2473
        let case ast::NodeValue::Bool(_) = errNode.value
2474
            else throw testing::TestError::Failed;
2475
    }
2476
}
2477
2478
@test unsafe fn testResolveRecordLiteralExtraField() throws (testing::TestError) {
2479
    let mut testArena152 = testArena();
2480
    let testStorage152: 'test152 = &mut testArena152 in {
2481
        let mut a = testResolver(testStorage152);
2482
        let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1, z: 3, y: 2 };";
2483
        let result = try resolveProgramStr(&mut a, program);
2484
        let err = try expectError(&result);
2485
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
2486
            else throw testing::TestError::Failed;
2487
    }
2488
}
2489
2490
/// Test that anonymous record literals with labels can be passed to functions expecting named records.
2491
@test unsafe fn testResolveAnonRecordLabeledToNamedRecord() throws (testing::TestError) {
2492
    let mut testArena153 = testArena();
2493
    let testStorage153: 'test153 = &mut testArena153 in {
2494
        let mut a = testResolver(testStorage153);
2495
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) -> i32 { return p.x; } foo({ x: 1, y: 2 });";
2496
        let result = try resolveProgramStr(&mut a, program);
2497
        try expectNoErrors(&result);
2498
    }
2499
}
2500
2501
/// Test that anonymous record with wrong field name causes out of order error.
2502
@test unsafe fn testResolveAnonRecordWrongFieldName() throws (testing::TestError) {
2503
    let mut testArena154 = testArena();
2504
    let testStorage154: 'test154 = &mut testArena154 in {
2505
        let mut a = testResolver(testStorage154);
2506
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1, z: 2 });";
2507
        let result = try resolveProgramStr(&mut a, program);
2508
        let err = try expectError(&result);
2509
        let case super::ErrorKind::RecordFieldOutOfOrder { field: _, prev: _ } = err.kind
2510
            else throw testing::TestError::Failed;
2511
    }
2512
}
2513
2514
/// Test that anonymous record with wrong field type causes type mismatch.
2515
@test unsafe fn testResolveAnonRecordWrongFieldType() throws (testing::TestError) {
2516
    let mut testArena155 = testArena();
2517
    let testStorage155: 'test155 = &mut testArena155 in {
2518
        let mut a = testResolver(testStorage155);
2519
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: true, y: 2 });";
2520
        let result = try resolveProgramStr(&mut a, program);
2521
        let err = try expectError(&result);
2522
        let case super::ErrorKind::TypeMismatch(_) = err.kind
2523
            else throw testing::TestError::Failed;
2524
    }
2525
}
2526
2527
/// Test that anonymous record with missing field causes a missing field error.
2528
@test unsafe fn testResolveAnonRecordMissingField() throws (testing::TestError) {
2529
    let mut testArena156 = testArena();
2530
    let testStorage156: 'test156 = &mut testArena156 in {
2531
        let mut a = testResolver(testStorage156);
2532
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1 });";
2533
        let result = try resolveProgramStr(&mut a, program);
2534
        try expectErrorKind(&result, super::ErrorKind::RecordFieldMissing("y"));
2535
    }
2536
}
2537
2538
/// Test that anonymous record with extra field causes a count mismatch error.
2539
@test unsafe fn testResolveAnonRecordExtraField() throws (testing::TestError) {
2540
    let mut testArena157 = testArena();
2541
    let testStorage157: 'test157 = &mut testArena157 in {
2542
        let mut a = testResolver(testStorage157);
2543
        let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1, y: 2, z: 3 });";
2544
        let result = try resolveProgramStr(&mut a, program);
2545
        let err = try expectError(&result);
2546
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
2547
            else throw testing::TestError::Failed;
2548
    }
2549
}
2550
2551
/// Test that anonymous record fields can be coerced (e.g., i32 to optional).
2552
@test unsafe fn testResolveAnonRecordFieldCoercion() throws (testing::TestError) {
2553
    let mut testArena158 = testArena();
2554
    let testStorage158: 'test158 = &mut testArena158 in {
2555
        let mut a = testResolver(testStorage158);
2556
        let program = "record Opt { x: ?i32 } fn foo(p: Opt) {} foo({ x: 42 });";
2557
        let result = try resolveProgramStr(&mut a, program);
2558
        try expectNoErrors(&result);
2559
    }
2560
}
2561
2562
/// Test that arrays of anonymous records with labeled fields are allowed.
2563
@test unsafe fn testResolveAnonRecordArray() throws (testing::TestError) {
2564
    let mut testArena159 = testArena();
2565
    let testStorage159: 'test159 = &mut testArena159 in {
2566
        let mut a = testResolver(testStorage159);
2567
        let program = "record Pt { x: i32, y: i32 } constant ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4 }];";
2568
        let result = try resolveProgramStr(&mut a, program);
2569
        try expectNoErrors(&result);
2570
    }
2571
}
2572
2573
/// Test that arrays of anonymous records with extra fields cause count mismatch.
2574
@test unsafe fn testResolveAnonRecordArrayMismatch() throws (testing::TestError) {
2575
    let mut testArena160 = testArena();
2576
    let testStorage160: 'test160 = &mut testArena160 in {
2577
        let mut a = testResolver(testStorage160);
2578
        let program = "record Pt { x: i32, y: i32 } constant ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4, z: 5 }];";
2579
        let result = try resolveProgramStr(&mut a, program);
2580
        let err = try expectError(&result);
2581
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
2582
            else throw testing::TestError::Failed;
2583
    }
2584
}
2585
2586
/// Test that unlabeled record declarations are analyzed correctly.
2587
@test unsafe fn testResolveUnlabeledRecordDecl() throws (testing::TestError) {
2588
    let mut testArena161 = testArena();
2589
    let testStorage161: 'test161 = &mut testArena161 in {
2590
        let mut a = testResolver(testStorage161);
2591
        let program = "record R(i32, bool);";
2592
        let result = try resolveProgramStr(&mut a, program);
2593
        try expectNoErrors(&result);
2594
2595
        // Verify the type symbol was created with labeled=false.
2596
        let nominalTy = try getTypeInScopeOf(&a, result.root, "R");
2597
        let case super::NominalType::Record(recordType) = *nominalTy
2598
            else throw testing::TestError::Failed;
2599
        try testing::expect(not recordType.labeled);
2600
        try testing::expect(recordType.fields.len == 2);
2601
        try testing::expect(recordType.fields[0].name == nil);
2602
        try testing::expect(recordType.fields[1].name == nil);
2603
    }
2604
}
2605
2606
@test unsafe fn testResolveLabeledRecordDecl() throws (testing::TestError) {
2607
    let mut testArena162 = testArena();
2608
    let testStorage162: 'test162 = &mut testArena162 in {
2609
        let mut a = testResolver(testStorage162);
2610
        let program = "record R { x: i32, y: i32 }";
2611
        let result = try resolveProgramStr(&mut a, program);
2612
        try expectNoErrors(&result);
2613
2614
        let nominalTy = try getTypeInScopeOf(&a, result.root, "R");
2615
        let case super::NominalType::Record(recordType) = *nominalTy
2616
            else throw testing::TestError::Failed;
2617
        try testing::expect(recordType.labeled);
2618
        try testing::expect(recordType.fields.len == 2);
2619
        try testing::expect(recordType.fields[0].name <> nil);
2620
        try testing::expect(recordType.fields[1].name <> nil);
2621
    }
2622
}
2623
2624
@test unsafe fn testResolveRecordFieldAccessValid() throws (testing::TestError) {
2625
    let mut testArena163 = testArena();
2626
    let testStorage163: 'test163 = &mut testArena163 in {
2627
        let mut a = testResolver(testStorage163);
2628
        let program = "record Pt { x: i32, y: u8 } let p = Pt { x: 1, y: 2 }; p.y;";
2629
        let result = try resolveProgramStr(&mut a, program);
2630
        try expectNoErrors(&result);
2631
2632
        let fieldStmt = try getBlockStmt(result.root, 2);
2633
        try expectExprStmtType(&a, fieldStmt, super::Type::U8);
2634
    }
2635
}
2636
2637
@test unsafe fn testResolveRecordFieldAccessUnknownField() throws (testing::TestError) {
2638
    let mut testArena164 = testArena();
2639
    let testStorage164: 'test164 = &mut testArena164 in {
2640
        let mut a = testResolver(testStorage164);
2641
        let program = "record Pt { x: i32 } let p = Pt { x: 1 }; p.y;";
2642
        let result = try resolveProgramStr(&mut a, program);
2643
        try expectErrorKind(&result, super::ErrorKind::RecordFieldUnknown("y"));
2644
    }
2645
}
2646
2647
@test unsafe fn testResolveRecordFieldAccessOnFunctionReturn() throws (testing::TestError) {
2648
    let mut testArena165 = testArena();
2649
    let testStorage165: 'test165 = &mut testArena165 in {
2650
        let mut a = testResolver(testStorage165);
2651
        let program = "record Pt { x: i32, y: i32 } fn make() -> Pt { return Pt { x: 5, y: 10 }; } make().x;";
2652
        let result = try resolveProgramStr(&mut a, program);
2653
        try expectNoErrors(&result);
2654
2655
        let stmt = try getBlockStmt(result.root, 2);
2656
        try expectExprStmtType(&a, stmt, super::Type::I32);
2657
    }
2658
}
2659
2660
@test unsafe fn testResolveRecordFieldAccessChained() throws (testing::TestError) {
2661
    let mut testArena166 = testArena();
2662
    let testStorage166: 'test166 = &mut testArena166 in {
2663
        let mut a = testResolver(testStorage166);
2664
        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;";
2665
        let result = try resolveProgramStr(&mut a, program);
2666
        try expectNoErrors(&result);
2667
2668
        let stmt = try getBlockStmt(result.root, 4);
2669
        try expectExprStmtType(&a, stmt, super::Type::I32);
2670
    }
2671
}
2672
2673
@test unsafe fn testResolveRecordFieldAccessOnInteger() throws (testing::TestError) {
2674
    let mut testArena167 = testArena();
2675
    let testStorage167: 'test167 = &mut testArena167 in {
2676
        let mut a = testResolver(testStorage167);
2677
        let program = "let x: i32 = 42; x.field;";
2678
        let result = try resolveBlockStr(&mut a, program);
2679
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
2680
    }
2681
}
2682
2683
@test unsafe fn testResolveRecordFieldAccessOnArray() throws (testing::TestError) {
2684
    let mut testArena168 = testArena();
2685
    let testStorage168: 'test168 = &mut testArena168 in {
2686
        let mut a = testResolver(testStorage168);
2687
        let program = "let arr: [i32; 3] = [1, 2, 3]; arr.field;";
2688
        let result = try resolveProgramStr(&mut a, program);
2689
        try expectErrorKind(&result, super::ErrorKind::ArrayFieldUnknown("field"));
2690
    }
2691
}
2692
2693
@test unsafe fn testResolveRecordFieldAccessOnBool() throws (testing::TestError) {
2694
    let mut testArena169 = testArena();
2695
    let testStorage169: 'test169 = &mut testArena169 in {
2696
        let mut a = testResolver(testStorage169);
2697
        let program = "let b: bool = true; b.field;";
2698
        let result = try resolveProgramStr(&mut a, program);
2699
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
2700
    }
2701
}
2702
2703
@test unsafe fn testResolveRecordFieldAccessOnOptional() throws (testing::TestError) {
2704
    let mut testArena170 = testArena();
2705
    let testStorage170: 'test170 = &mut testArena170 in {
2706
        let mut a = testResolver(testStorage170);
2707
        let program = "record Pt { x: i32 } let opt: ?Pt = Pt { x: 5 }; opt.x;";
2708
        let result = try resolveProgramStr(&mut a, program);
2709
        try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
2710
    }
2711
}
2712
2713
/// Records may reference themselves through pointers without causing resolution errors.
2714
@test unsafe fn testResolveRecordSelfReferentialPointer() throws (testing::TestError) {
2715
    let mut testArena171 = testArena();
2716
    let testStorage171: 'test171 = &mut testArena171 in {
2717
        let mut a = testResolver(testStorage171);
2718
        let program = "record A { next: *A }";
2719
        let result = try resolveProgramStr(&mut a, program);
2720
        try expectNoErrors(&result);
2721
    }
2722
}
2723
2724
/// Mutually recursive records should resolve without infinite loops.
2725
@test unsafe fn testResolveRecordMutuallyRecursive() throws (testing::TestError) {
2726
    let mut testArena172 = testArena();
2727
    let testStorage172: 'test172 = &mut testArena172 in {
2728
        let mut a = testResolver(testStorage172);
2729
        let program = "record A { b: *B } record B { a: *A }";
2730
        let result = try resolveProgramStr(&mut a, program);
2731
        try expectNoErrors(&result);
2732
    }
2733
}
2734
2735
/// Unions may reference themselves through pointers without causing resolution errors.
2736
@test unsafe fn testResolveUnionSelfReferentialPointerAllowed() throws (testing::TestError) {
2737
    let mut testArena173 = testArena();
2738
    let testStorage173: 'test173 = &mut testArena173 in {
2739
        let mut a = testResolver(testStorage173);
2740
        let program = "union List { Cons(*List), Nil }";
2741
        let result = try resolveProgramStr(&mut a, program);
2742
        try expectNoErrors(&result);
2743
    }
2744
}
2745
2746
/// Mutually recursive unions should resolve without infinite loops.
2747
@test unsafe fn testResolveUnionMutuallyRecursive() throws (testing::TestError) {
2748
    let mut testArena174 = testArena();
2749
    let testStorage174: 'test174 = &mut testArena174 in {
2750
        let mut a = testResolver(testStorage174);
2751
        let program = "union A { HasB(*B), None } union B { HasA(*A), None }";
2752
        let result = try resolveProgramStr(&mut a, program);
2753
        try expectNoErrors(&result);
2754
    }
2755
}
2756
2757
/// Unions with record payloads containing slice references to self should resolve.
2758
/// This matches the pattern in sexpr.rad: `List { tail: *[Expr] }`.
2759
@test unsafe fn testResolveUnionRecordPayloadWithSliceSelfRef() throws (testing::TestError) {
2760
    let mut testArena175 = testArena();
2761
    let testStorage175: 'test175 = &mut testArena175 in {
2762
        let mut a = testResolver(testStorage175);
2763
        let program = "union Expr { Null, List { head: *[u8], tail: *[Expr] } }";
2764
        let result = try resolveProgramStr(&mut a, program);
2765
        try expectNoErrors(&result);
2766
    }
2767
}
2768
2769
@test unsafe fn testUndefinedCoercions() throws (testing::TestError) {
2770
    {
2771
        let mut testArena176 = testArena();
2772
        let testStorage176: 'test176 = &mut testArena176 in {
2773
            let mut a = testResolver(testStorage176);
2774
            let result = try resolveBlockStr(&mut a, "unsafe { let count: i32 = undefined; }");
2775
            try expectNoErrors(&result);
2776
        }
2777
    } {
2778
        let mut testArena177 = testArena();
2779
        let testStorage177: 'test177 = &mut testArena177 in {
2780
            let mut a = testResolver(testStorage177);
2781
            let program = "unsafe { let mut value: i32 = 0; set value = undefined; }";
2782
            let result = try resolveProgramStr(&mut a, program);
2783
            try expectNoErrors(&result);
2784
        }
2785
    } {
2786
        let mut testArena178 = testArena();
2787
        let testStorage178: 'test178 = &mut testArena178 in {
2788
            let mut a = testResolver(testStorage178);
2789
            let program = "fn f(x: i32) {} unsafe fn g() { f(undefined); }";
2790
            let result = try resolveProgramStr(&mut a, program);
2791
            try expectNoErrors(&result);
2792
        }
2793
    } {
2794
        let mut testArena179 = testArena();
2795
        let testStorage179: 'test179 = &mut testArena179 in {
2796
            let mut a = testResolver(testStorage179);
2797
            let program = "unsafe fn fetch() -> i32 { return undefined; }";
2798
            let result = try resolveProgramStr(&mut a, program);
2799
            try expectNoErrors(&result);
2800
        }
2801
    }
2802
}
2803
2804
@test unsafe fn testResolveBlockVoid() throws (testing::TestError) {
2805
    let mut testArena180 = testArena();
2806
    let testStorage180: 'test180 = &mut testArena180 in {
2807
        let mut a = testResolver(testStorage180);
2808
        let result = try resolveProgramStr(&mut a, "{ 42; }");
2809
        try expectNoErrors(&result);
2810
2811
        let block = try getBlockStmt(result.root, 0);
2812
        try expectType(&a, block, super::Type::Void);
2813
    }
2814
}
2815
2816
@test unsafe fn testResolveBlockNever() throws (testing::TestError) {
2817
    let mut testArena181 = testArena();
2818
    let testStorage181: 'test181 = &mut testArena181 in {
2819
        let mut a = testResolver(testStorage181);
2820
        let result = try resolveProgramStr(&mut a, "{ panic; }");
2821
        try expectNoErrors(&result);
2822
2823
        let block = try getBlockStmt(result.root, 0);
2824
        try expectType(&a, block, super::Type::Never);
2825
    }
2826
}
2827
2828
@test unsafe fn testResolveIfAllBranchesNever() throws (testing::TestError) {
2829
    let mut testArena182 = testArena();
2830
    let testStorage182: 'test182 = &mut testArena182 in {
2831
        let mut a = testResolver(testStorage182);
2832
        let program = "if true { panic; } else { panic; }";
2833
        let result = try resolveProgramStr(&mut a, program);
2834
        try expectNoErrors(&result);
2835
2836
        let stmt = try getBlockStmt(result.root, 0);
2837
        try expectType(&a, stmt, super::Type::Never);
2838
    }
2839
}
2840
2841
@test unsafe fn testResolveIfMixedBranchesNotNever() throws (testing::TestError) {
2842
    let mut testArena183 = testArena();
2843
    let testStorage183: 'test183 = &mut testArena183 in {
2844
        let mut a = testResolver(testStorage183);
2845
        let program = "if true { panic; } else {}";
2846
        let result = try resolveProgramStr(&mut a, program);
2847
        try expectNoErrors(&result);
2848
2849
        let stmt = try getBlockStmt(result.root, 0);
2850
        try expectType(&a, stmt, super::Type::Void);
2851
    }
2852
}
2853
2854
@test unsafe fn testResolveLetElse() throws (testing::TestError) {
2855
    let mut testArena184 = testArena();
2856
    let testStorage184: 'test184 = &mut testArena184 in {
2857
        let mut a = testResolver(testStorage184);
2858
        let program = "let opt: ?i32 = 42; let value = opt else panic; value;";
2859
        let result = try resolveProgramStr(&mut a, program);
2860
        try expectNoErrors(&result);
2861
2862
        let blockNode = result.root;
2863
        let case ast::NodeValue::Block(block) = blockNode.value
2864
            else throw testing::TestError::Failed;
2865
        let letElseNode = try getBlockStmt(blockNode, 1);
2866
        let valueStmt = try getBlockStmt(blockNode, 2);
2867
2868
        { // Ensure the bound identifier receives the inner optional type.
2869
            let valueExpr = try expectExprStmtType(&a, valueStmt, super::Type::I32);
2870
2871
            let sym = super::symbolFor(&a, valueExpr)
2872
                else throw testing::TestError::Failed;
2873
            let case super::SymbolData::Value { type: valType, .. } = sym.data
2874
                else throw testing::TestError::Failed;
2875
            try testing::expect(valType == super::Type::I32);
2876
        }
2877
        // The let-else statement itself should be typed as void.
2878
        try expectType(&a, letElseNode, super::Type::Void);
2879
    }
2880
}
2881
2882
@test unsafe fn testResolveLetElseDefaultValue() throws (testing::TestError) {
2883
    let mut testArena185 = testArena();
2884
    let testStorage185: 'test185 = &mut testArena185 in {
2885
        let mut a = testResolver(testStorage185);
2886
        let program = "let opt: ?i32 = nil; let value = opt else 42; value;";
2887
        let result = try resolveProgramStr(&mut a, program);
2888
        try expectNoErrors(&result);
2889
    }
2890
}
2891
2892
@test unsafe fn testResolveLetElseRequiresDivergentElse() throws (testing::TestError) {
2893
    let mut testArena186 = testArena();
2894
    let testStorage186: 'test186 = &mut testArena186 in {
2895
        let mut a = testResolver(testStorage186);
2896
        let program = "let opt: ?i32 = nil; let value = opt else {}; value;";
2897
        let result = try resolveProgramStr(&mut a, program);
2898
        let err = try expectError(&result);
2899
        try expectTypeMismatch(err, super::Type::I32, super::Type::Void);
2900
    }
2901
}
2902
2903
@test unsafe fn testResolveLetElseRequiresOptional() throws (testing::TestError) {
2904
    let mut testArena187 = testArena();
2905
    let testStorage187: 'test187 = &mut testArena187 in {
2906
        let mut a = testResolver(testStorage187);
2907
        let program = "let x: i32 = 42; let value = x else panic;";
2908
        let result = try resolveProgramStr(&mut a, program);
2909
        try expectErrorKind(&result, super::ErrorKind::ExpectedOptional);
2910
    }
2911
}
2912
2913
/// Test that `if let mut` produces a mutable binding.
2914
@test unsafe fn testResolveIfLetMut() throws (testing::TestError) {
2915
    let mut testArena188 = testArena();
2916
    let testStorage188: 'test188 = &mut testArena188 in {
2917
        let mut a = testResolver(testStorage188);
2918
        let program = "let opt: ?i32 = 42; if let mut v = opt { set v = v + 1; }";
2919
        let result = try resolveProgramStr(&mut a, program);
2920
        try expectNoErrors(&result);
2921
    }
2922
}
2923
2924
/// Test that `if let` (without mut) rejects assignment.
2925
@test unsafe fn testResolveIfLetImmutable() throws (testing::TestError) {
2926
    let mut testArena189 = testArena();
2927
    let testStorage189: 'test189 = &mut testArena189 in {
2928
        let mut a = testResolver(testStorage189);
2929
        let program = "let opt: ?i32 = 42; if let v = opt { set v = 1; }";
2930
        let result = try resolveProgramStr(&mut a, program);
2931
        let err = try expectError(&result);
2932
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2933
    }
2934
}
2935
2936
/// Test that `let mut ... else` produces a mutable binding.
2937
@test unsafe fn testResolveLetMutElse() throws (testing::TestError) {
2938
    let mut testArena190 = testArena();
2939
    let testStorage190: 'test190 = &mut testArena190 in {
2940
        let mut a = testResolver(testStorage190);
2941
        let program = "let opt: ?i32 = 42; let mut v = opt else panic; set v = v + 1;";
2942
        let result = try resolveProgramStr(&mut a, program);
2943
        try expectNoErrors(&result);
2944
    }
2945
}
2946
2947
/// Test that `let ... else` (without mut) rejects assignment.
2948
@test unsafe fn testResolveLetElseImmutable() throws (testing::TestError) {
2949
    let mut testArena191 = testArena();
2950
    let testStorage191: 'test191 = &mut testArena191 in {
2951
        let mut a = testResolver(testStorage191);
2952
        let program = "let opt: ?i32 = 42; let v = opt else panic; set v = 1;";
2953
        let result = try resolveProgramStr(&mut a, program);
2954
        let err = try expectError(&result);
2955
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2956
    }
2957
}
2958
2959
@test unsafe fn testResolveLetCaseElse() throws (testing::TestError) {
2960
    {
2961
        let mut testArena192 = testArena();
2962
        let testStorage192: 'test192 = &mut testArena192 in {
2963
            let mut a = testResolver(testStorage192);
2964
            let program = "let case _ = 1 else panic;";
2965
            let result = try resolveProgramStr(&mut a, program);
2966
            try expectNoErrors(&result);
2967
        }
2968
    } {
2969
        let mut testArena193 = testArena();
2970
        let testStorage193: 'test193 = &mut testArena193 in {
2971
            let mut a = testResolver(testStorage193);
2972
            let program = "let case _ = true else false;";
2973
            let result = try resolveProgramStr(&mut a, program);
2974
            try expectNoErrors(&result);
2975
        }
2976
    }
2977
}
2978
2979
@test unsafe fn testResolveLetCaseElseRequiresDivergentElse() throws (testing::TestError) {
2980
    let mut testArena194 = testArena();
2981
    let testStorage194: 'test194 = &mut testArena194 in {
2982
        let mut a = testResolver(testStorage194);
2983
        let program = "let case _ = 1 else {};";
2984
        let result = try resolveProgramStr(&mut a, program);
2985
        let err = try expectError(&result);
2986
        try expectTypeMismatch(err, super::Type::Int, super::Type::Void);
2987
    }
2988
}
2989
2990
@test unsafe fn testResolveTryValidPropagation() throws (testing::TestError) {
2991
    let mut testArena195 = testArena();
2992
    let testStorage195: 'test195 = &mut testArena195 in {
2993
        let mut a = testResolver(testStorage195);
2994
        let program = "fn fallible() throws (i32) {} fn caller() throws (i32) { try fallible() }";
2995
        let result = try resolveProgramStr(&mut a, program);
2996
        try expectNoErrors(&result);
2997
    }
2998
}
2999
3000
@test unsafe fn testResolveTryRequiresThrowsClause() throws (testing::TestError) {
3001
    let mut testArena196 = testArena();
3002
    let testStorage196: 'test196 = &mut testArena196 in {
3003
        let mut a = testResolver(testStorage196);
3004
        let program = "fn fallible() throws (i32) {} fn caller() { try fallible() }";
3005
        let result = try resolveProgramStr(&mut a, program);
3006
        try expectErrorKind(&result, super::ErrorKind::TryRequiresThrows);
3007
    }
3008
}
3009
3010
@test unsafe fn testResolveTryIncompatibleError() throws (testing::TestError) {
3011
    let mut testArena197 = testArena();
3012
    let testStorage197: 'test197 = &mut testArena197 in {
3013
        let mut a = testResolver(testStorage197);
3014
        let program = "fn fallible() throws (i32) {} fn caller() throws (i8) { try fallible() }";
3015
        let result = try resolveProgramStr(&mut a, program);
3016
        try expectErrorKind(&result, super::ErrorKind::TryIncompatibleError);
3017
    }
3018
}
3019
3020
@test unsafe fn testResolveTryNonThrowing() throws (testing::TestError) {
3021
    let mut testArena198 = testArena();
3022
    let testStorage198: 'test198 = &mut testArena198 in {
3023
        let mut a = testResolver(testStorage198);
3024
        let program = "fn safe() {} fn caller() throws (i32) { try safe() }";
3025
        let result = try resolveProgramStr(&mut a, program);
3026
        try expectErrorKind(&result, super::ErrorKind::TryNonThrowing);
3027
    }
3028
}
3029
3030
@test unsafe fn testResolveTryCatchBlockMatchesResult() throws (testing::TestError) {
3031
    let mut testArena199 = testArena();
3032
    let testStorage199: 'test199 = &mut testArena199 in {
3033
        let mut a = testResolver(testStorage199);
3034
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { return 42; }; }";
3035
        let result = try resolveProgramStr(&mut a, program);
3036
        try expectNoErrors(&result);
3037
    }
3038
}
3039
3040
@test unsafe fn testResolveTryCatchBlockDiverges() throws (testing::TestError) {
3041
    let mut testArena200 = testArena();
3042
    let testStorage200: 'test200 = &mut testArena200 in {
3043
        let mut a = testResolver(testStorage200);
3044
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { return 7; }; }";
3045
        let result = try resolveProgramStr(&mut a, program);
3046
        try expectNoErrors(&result);
3047
    }
3048
}
3049
3050
@test unsafe fn testResolveTryCatchBlockMustDiverge() throws (testing::TestError) {
3051
    let mut testArena201 = testArena();
3052
    let testStorage201: 'test201 = &mut testArena201 in {
3053
        let mut a = testResolver(testStorage201);
3054
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { 7; }; }";
3055
        let result = try resolveProgramStr(&mut a, program);
3056
        let err = try expectError(&result);
3057
        try expectTypeMismatch(err, super::Type::U32, super::Type::Void);
3058
    }
3059
}
3060
3061
@test unsafe fn testResolveCallMissingTry() throws (testing::TestError) {
3062
    let mut testArena202 = testArena();
3063
    let testStorage202: 'test202 = &mut testArena202 in {
3064
        let mut a = testResolver(testStorage202);
3065
        let program = "fn fallible() throws (i32) {} fn caller() { fallible() }";
3066
        let result = try resolveProgramStr(&mut a, program);
3067
        try expectErrorKind(&result, super::ErrorKind::MissingTry);
3068
    }
3069
}
3070
3071
/// Test that `try?` converts errors to optionals without requiring caller to throw.
3072
@test unsafe fn testResolveTryOptionalConvertsToOptional() throws (testing::TestError) {
3073
    // `try?` should wrap the return type in optional and not require caller to throw.
3074
    {
3075
        let mut testArena203 = testArena();
3076
        let testStorage203: 'test203 = &mut testArena203 in {
3077
            let mut a = testResolver(testStorage203);
3078
            let program = "record S {} fn fallible() -> *S throws (i32) { panic; } fn caller() -> ?*S { return try? fallible(); }";
3079
            let result = try resolveProgramStr(&mut a, program);
3080
            try expectNoErrors(&result);
3081
        }
3082
    }
3083
    // `try?` works in non-throwing function.
3084
    {
3085
        let mut testArena204 = testArena();
3086
        let testStorage204: 'test204 = &mut testArena204 in {
3087
            let mut a = testResolver(testStorage204);
3088
            let program = "fn fallible() -> i32 throws (i32) { panic; } fn caller() -> ?i32 { return try? fallible(); }";
3089
            let result = try resolveProgramStr(&mut a, program);
3090
            try expectNoErrors(&result);
3091
        }
3092
    }
3093
    // `try?` can be used in if-let patterns.
3094
    {
3095
        let mut testArena205 = testArena();
3096
        let testStorage205: 'test205 = &mut testArena205 in {
3097
            let mut a = testResolver(testStorage205);
3098
            let program = "fn fallible() -> i32 throws (i32) { panic; } fn caller() -> i32 { if let x = try? fallible() { return x; } return 0; }";
3099
            let result = try resolveProgramStr(&mut a, program);
3100
            try expectNoErrors(&result);
3101
        }
3102
    }
3103
}
3104
3105
@test unsafe fn testResolveThrowValid() throws (testing::TestError) {
3106
    let mut testArena206 = testArena();
3107
    let testStorage206: 'test206 = &mut testArena206 in {
3108
        let mut a = testResolver(testStorage206);
3109
        let program = "fn fail() throws (i32) { throw 1; }";
3110
        let result = try resolveProgramStr(&mut a, program);
3111
        try expectNoErrors(&result);
3112
    }
3113
}
3114
3115
@test unsafe fn testResolveThrowRequiresThrowsClause() throws (testing::TestError) {
3116
    let mut testArena207 = testArena();
3117
    let testStorage207: 'test207 = &mut testArena207 in {
3118
        let mut a = testResolver(testStorage207);
3119
        let program = "fn fail() { throw 1; }";
3120
        let result = try resolveProgramStr(&mut a, program);
3121
        try expectErrorKind(&result, super::ErrorKind::ThrowRequiresThrows);
3122
    }
3123
}
3124
3125
@test unsafe fn testResolveThrowIncompatibleError() throws (testing::TestError) {
3126
    let mut testArena208 = testArena();
3127
    let testStorage208: 'test208 = &mut testArena208 in {
3128
        let mut a = testResolver(testStorage208);
3129
        let program = "fn fail() throws (i32) { throw true; }";
3130
        let result = try resolveProgramStr(&mut a, program);
3131
        try expectErrorKind(&result, super::ErrorKind::ThrowIncompatibleError);
3132
    }
3133
}
3134
3135
// Binary operation tests //////////////////////////////////////////////////////
3136
3137
@test unsafe fn testResolveBinaryOpArithmetic() throws (testing::TestError) {
3138
    {
3139
        let mut testArena209 = testArena();
3140
        let testStorage209: 'test209 = &mut testArena209 in {
3141
            let mut a = testResolver(testStorage209);
3142
            let result = try resolveExprStr(&mut a, "4 + 4");
3143
            try expectNoErrors(&result);
3144
            try expectType(&a, result.root, super::Type::Int);
3145
        }
3146
    } {
3147
        let mut testArena210 = testArena();
3148
        let testStorage210: 'test210 = &mut testArena210 in {
3149
            let mut a = testResolver(testStorage210);
3150
            let result = try resolveExprStr(&mut a, "10 - 3");
3151
            try expectNoErrors(&result);
3152
            try expectType(&a, result.root, super::Type::Int);
3153
        }
3154
    } {
3155
        let mut testArena211 = testArena();
3156
        let testStorage211: 'test211 = &mut testArena211 in {
3157
            let mut a = testResolver(testStorage211);
3158
            let result = try resolveExprStr(&mut a, "5 * 6");
3159
            try expectNoErrors(&result);
3160
            try expectType(&a, result.root, super::Type::Int);
3161
        }
3162
    } {
3163
        let mut testArena212 = testArena();
3164
        let testStorage212: 'test212 = &mut testArena212 in {
3165
            let mut a = testResolver(testStorage212);
3166
            let result = try resolveExprStr(&mut a, "20 / 4");
3167
            try expectNoErrors(&result);
3168
            try expectType(&a, result.root, super::Type::Int);
3169
        }
3170
    } {
3171
        let mut testArena213 = testArena();
3172
        let testStorage213: 'test213 = &mut testArena213 in {
3173
            let mut a = testResolver(testStorage213);
3174
            let result = try resolveExprStr(&mut a, "17 % 5");
3175
            try expectNoErrors(&result);
3176
            try expectType(&a, result.root, super::Type::Int);
3177
        }
3178
    } {
3179
        let mut testArena214 = testArena();
3180
        let testStorage214: 'test214 = &mut testArena214 in {
3181
            let mut a = testResolver(testStorage214);
3182
            let result = try resolveBlockStr(&mut a, "let x: i32 = 4; let y: i32 = 5; x + y;");
3183
            try expectNoErrors(&result);
3184
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3185
            try expectExprStmtType(&a, stmt, super::Type::I32);
3186
        }
3187
    } {
3188
        let mut testArena215 = testArena();
3189
        let testStorage215: 'test215 = &mut testArena215 in {
3190
            let mut a = testResolver(testStorage215);
3191
            let result = try resolveExprStr(&mut a, "1 + (2 * 3) - 4");
3192
            try expectNoErrors(&result);
3193
            try expectType(&a, result.root, super::Type::Int);
3194
        }
3195
    } {
3196
        let mut testArena216 = testArena();
3197
        let testStorage216: 'test216 = &mut testArena216 in {
3198
            let mut a = testResolver(testStorage216);
3199
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n * 2;");
3200
            try expectNoErrors(&result);
3201
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3202
            try expectExprStmtType(&a, stmt, super::Type::I32);
3203
        }
3204
    } {
3205
        let mut testArena217 = testArena();
3206
        let testStorage217: 'test217 = &mut testArena217 in {
3207
            let mut a = testResolver(testStorage217);
3208
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; 2 * n;");
3209
            try expectNoErrors(&result);
3210
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3211
            try expectExprStmtType(&a, stmt, super::Type::I32);
3212
        }
3213
    } {
3214
        let mut testArena218 = testArena();
3215
        let testStorage218: 'test218 = &mut testArena218 in {
3216
            let mut a = testResolver(testStorage218);
3217
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n - 1;");
3218
            try expectNoErrors(&result);
3219
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3220
            try expectExprStmtType(&a, stmt, super::Type::I32);
3221
        }
3222
    }
3223
}
3224
3225
@test unsafe fn testResolveBinaryOpComparison() throws (testing::TestError) {
3226
    {
3227
        let mut testArena219 = testArena();
3228
        let testStorage219: 'test219 = &mut testArena219 in {
3229
            let mut a = testResolver(testStorage219);
3230
            let result = try resolveExprStr(&mut a, "5 == 5");
3231
            try expectNoErrors(&result);
3232
            try expectType(&a, result.root, super::Type::Bool);
3233
        }
3234
    } {
3235
        let mut testArena220 = testArena();
3236
        let testStorage220: 'test220 = &mut testArena220 in {
3237
            let mut a = testResolver(testStorage220);
3238
            let result = try resolveExprStr(&mut a, "5 <> 10");
3239
            try expectNoErrors(&result);
3240
            try expectType(&a, result.root, super::Type::Bool);
3241
        }
3242
    } {
3243
        let mut testArena221 = testArena();
3244
        let testStorage221: 'test221 = &mut testArena221 in {
3245
            let mut a = testResolver(testStorage221);
3246
            let result = try resolveExprStr(&mut a, "5 < 10");
3247
            try expectNoErrors(&result);
3248
            try expectType(&a, result.root, super::Type::Bool);
3249
        }
3250
    } {
3251
        let mut testArena222 = testArena();
3252
        let testStorage222: 'test222 = &mut testArena222 in {
3253
            let mut a = testResolver(testStorage222);
3254
            let result = try resolveExprStr(&mut a, "10 > 5");
3255
            try expectNoErrors(&result);
3256
            try expectType(&a, result.root, super::Type::Bool);
3257
        }
3258
    } {
3259
        let mut testArena223 = testArena();
3260
        let testStorage223: 'test223 = &mut testArena223 in {
3261
            let mut a = testResolver(testStorage223);
3262
            let result = try resolveExprStr(&mut a, "5 <= 5");
3263
            try expectNoErrors(&result);
3264
            try expectType(&a, result.root, super::Type::Bool);
3265
        }
3266
    } {
3267
        let mut testArena224 = testArena();
3268
        let testStorage224: 'test224 = &mut testArena224 in {
3269
            let mut a = testResolver(testStorage224);
3270
            let result = try resolveExprStr(&mut a, "10 >= 5");
3271
            try expectNoErrors(&result);
3272
            try expectType(&a, result.root, super::Type::Bool);
3273
        }
3274
    } {
3275
        let mut testArena225 = testArena();
3276
        let testStorage225: 'test225 = &mut testArena225 in {
3277
            let mut a = testResolver(testStorage225);
3278
            let result = try resolveExprStr(&mut a, "true == false");
3279
            try expectNoErrors(&result);
3280
            try expectType(&a, result.root, super::Type::Bool);
3281
        }
3282
    } {
3283
        let mut testArena226 = testArena();
3284
        let testStorage226: 'test226 = &mut testArena226 in {
3285
            let mut a = testResolver(testStorage226);
3286
            let result = try resolveExprStr(&mut a, "5 + 3 > 10 - 4");
3287
            try expectNoErrors(&result);
3288
            try expectType(&a, result.root, super::Type::Bool);
3289
        }
3290
    } {
3291
        let mut testArena227 = testArena();
3292
        let testStorage227: 'test227 = &mut testArena227 in {
3293
            let mut a = testResolver(testStorage227);
3294
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n == 1;");
3295
            try expectNoErrors(&result);
3296
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3297
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3298
        }
3299
    } {
3300
        let mut testArena228 = testArena();
3301
        let testStorage228: 'test228 = &mut testArena228 in {
3302
            let mut a = testResolver(testStorage228);
3303
            let result = try resolveBlockStr(&mut a, "let n: i32 = 5; 1 == n;");
3304
            try expectNoErrors(&result);
3305
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3306
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3307
        }
3308
    }
3309
}
3310
3311
@test unsafe fn testResolveBinaryOpLogical() throws (testing::TestError) {
3312
    {
3313
        let mut testArena229 = testArena();
3314
        let testStorage229: 'test229 = &mut testArena229 in {
3315
            let mut a = testResolver(testStorage229);
3316
            let result = try resolveBlockStr(&mut a, "let x: bool = true; let y: bool = false; x and y;");
3317
            try expectNoErrors(&result);
3318
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3319
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3320
        }
3321
    } {
3322
        let mut testArena230 = testArena();
3323
        let testStorage230: 'test230 = &mut testArena230 in {
3324
            let mut a = testResolver(testStorage230);
3325
            let result = try resolveBlockStr(&mut a, "let x: bool = true; let y: bool = false; x or y;");
3326
            try expectNoErrors(&result);
3327
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3328
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3329
        }
3330
    } {
3331
        let mut testArena231 = testArena();
3332
        let testStorage231: 'test231 = &mut testArena231 in {
3333
            let mut a = testResolver(testStorage231);
3334
            let result = try resolveExprStr(&mut a, "true and false");
3335
            try expectNoErrors(&result);
3336
            try expectType(&a, result.root, super::Type::Bool);
3337
        }
3338
    }
3339
}
3340
3341
@test unsafe fn testResolveBinaryOpArithmeticTypeMismatch() throws (testing::TestError) {
3342
    {
3343
        let mut testArena232 = testArena();
3344
        let testStorage232: 'test232 = &mut testArena232 in {
3345
            let mut a = testResolver(testStorage232);
3346
            let result = try resolveProgramStr(&mut a, "4 + true");
3347
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3348
        }
3349
    } {
3350
        let mut testArena233 = testArena();
3351
        let testStorage233: 'test233 = &mut testArena233 in {
3352
            let mut a = testResolver(testStorage233);
3353
            let result = try resolveBlockStr(&mut a, "let x: i32 = 4; let y: bool = false; x + y;");
3354
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3355
        }
3356
    } {
3357
        let mut testArena234 = testArena();
3358
        let testStorage234: 'test234 = &mut testArena234 in {
3359
            let mut a = testResolver(testStorage234);
3360
            let result = try resolveProgramStr(&mut a, "10 - false");
3361
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3362
        }
3363
    } {
3364
        let mut testArena235 = testArena();
3365
        let testStorage235: 'test235 = &mut testArena235 in {
3366
            let mut a = testResolver(testStorage235);
3367
            let result = try resolveProgramStr(&mut a, "5 * true");
3368
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3369
        }
3370
    } {
3371
        let mut testArena236 = testArena();
3372
        let testStorage236: 'test236 = &mut testArena236 in {
3373
            let mut a = testResolver(testStorage236);
3374
            let result = try resolveProgramStr(&mut a, "20 / false");
3375
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3376
        }
3377
    } {
3378
        let mut testArena237 = testArena();
3379
        let testStorage237: 'test237 = &mut testArena237 in {
3380
            let mut a = testResolver(testStorage237);
3381
            let result = try resolveProgramStr(&mut a, "17 % true");
3382
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3383
        }
3384
    } {
3385
        let mut testArena238 = testArena();
3386
        let testStorage238: 'test238 = &mut testArena238 in {
3387
            let mut a = testResolver(testStorage238);
3388
            let result = try resolveProgramStr(&mut a, "1 + (true * 3)");
3389
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3390
        }
3391
    }
3392
}
3393
3394
@test unsafe fn testResolveBinaryOpLogicalTypeMismatch() throws (testing::TestError) {
3395
    {
3396
        let mut testArena239 = testArena();
3397
        let testStorage239: 'test239 = &mut testArena239 in {
3398
            let mut a = testResolver(testStorage239);
3399
            let result = try resolveProgramStr(&mut a, "42 and true");
3400
            let err = try expectError(&result);
3401
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3402
        }
3403
    } {
3404
        let mut testArena240 = testArena();
3405
        let testStorage240: 'test240 = &mut testArena240 in {
3406
            let mut a = testResolver(testStorage240);
3407
            let result = try resolveProgramStr(&mut a, "true or 5");
3408
            let err = try expectError(&result);
3409
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3410
        }
3411
    } {
3412
        let mut testArena241 = testArena();
3413
        let testStorage241: 'test241 = &mut testArena241 in {
3414
            let mut a = testResolver(testStorage241);
3415
            let result = try resolveProgramStr(&mut a, "1 and 2");
3416
            let err = try expectError(&result);
3417
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3418
        }
3419
    }
3420
}
3421
3422
@test unsafe fn testResolveBinaryOpComparisonTypeMismatch() throws (testing::TestError) {
3423
    let mut testArena242 = testArena();
3424
    let testStorage242: 'test242 = &mut testArena242 in {
3425
        let mut a = testResolver(testStorage242);
3426
        let result = try resolveProgramStr(&mut a, "true < false");
3427
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3428
    }
3429
}
3430
3431
// Unary operation tests ///////////////////////////////////////////////////////
3432
3433
@test unsafe fn testResolveUnaryOpNot() throws (testing::TestError) {
3434
    {
3435
        let mut testArena243 = testArena();
3436
        let testStorage243: 'test243 = &mut testArena243 in {
3437
            let mut a = testResolver(testStorage243);
3438
            let result = try resolveExprStr(&mut a, "not true");
3439
            try expectNoErrors(&result);
3440
            try expectType(&a, result.root, super::Type::Bool);
3441
        }
3442
    } {
3443
        let mut testArena244 = testArena();
3444
        let testStorage244: 'test244 = &mut testArena244 in {
3445
            let mut a = testResolver(testStorage244);
3446
            let result = try resolveBlockStr(&mut a, "let x: bool = true; not x;");
3447
            try expectNoErrors(&result);
3448
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3449
            try expectExprStmtType(&a, stmt, super::Type::Bool);
3450
        }
3451
    } {
3452
        let mut testArena245 = testArena();
3453
        let testStorage245: 'test245 = &mut testArena245 in {
3454
            let mut a = testResolver(testStorage245);
3455
            let result = try resolveExprStr(&mut a, "not (true and false)");
3456
            try expectNoErrors(&result);
3457
            try expectType(&a, result.root, super::Type::Bool);
3458
        }
3459
    } {
3460
        let mut testArena246 = testArena();
3461
        let testStorage246: 'test246 = &mut testArena246 in {
3462
            let mut a = testResolver(testStorage246);
3463
            let result = try resolveProgramStr(&mut a, "not 42");
3464
            let err = try expectError(&result);
3465
            try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
3466
        }
3467
    } {
3468
        let mut testArena247 = testArena();
3469
        let testStorage247: 'test247 = &mut testArena247 in {
3470
            let mut a = testResolver(testStorage247);
3471
            let result = try resolveBlockStr(&mut a, "let x: i32 = 5; not x;");
3472
            let err = try expectError(&result);
3473
            try expectTypeMismatch(err, super::Type::Bool, super::Type::I32);
3474
        }
3475
    }
3476
}
3477
3478
@test unsafe fn testResolveUnaryOpNeg() throws (testing::TestError) {
3479
    {
3480
        let mut testArena248 = testArena();
3481
        let testStorage248: 'test248 = &mut testArena248 in {
3482
            let mut a = testResolver(testStorage248);
3483
            let result = try resolveExprStr(&mut a, "-42");
3484
            try expectNoErrors(&result);
3485
            try expectType(&a, result.root, super::Type::Int);
3486
        }
3487
    } {
3488
        let mut testArena249 = testArena();
3489
        let testStorage249: 'test249 = &mut testArena249 in {
3490
            let mut a = testResolver(testStorage249);
3491
            let result = try resolveBlockStr(&mut a, "let x: i32 = 10; -x;");
3492
            try expectNoErrors(&result);
3493
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3494
            try expectExprStmtType(&a, stmt, super::Type::I32);
3495
        }
3496
    } {
3497
        let mut testArena250 = testArena();
3498
        let testStorage250: 'test250 = &mut testArena250 in {
3499
            let mut a = testResolver(testStorage250);
3500
            let result = try resolveExprStr(&mut a, "-(5 + 3)");
3501
            try expectNoErrors(&result);
3502
            try expectType(&a, result.root, super::Type::Int);
3503
        }
3504
    } {
3505
        let mut testArena251 = testArena();
3506
        let testStorage251: 'test251 = &mut testArena251 in {
3507
            let mut a = testResolver(testStorage251);
3508
            let result = try resolveBlockStr(&mut a, "let x: i8 = 5; -x;");
3509
            try expectNoErrors(&result);
3510
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3511
            try expectExprStmtType(&a, stmt, super::Type::I8);
3512
        }
3513
    } {
3514
        let mut testArena252 = testArena();
3515
        let testStorage252: 'test252 = &mut testArena252 in {
3516
            let mut a = testResolver(testStorage252);
3517
            let result = try resolveProgramStr(&mut a, "-true");
3518
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3519
        }
3520
    } {
3521
        let mut testArena253 = testArena();
3522
        let testStorage253: 'test253 = &mut testArena253 in {
3523
            let mut a = testResolver(testStorage253);
3524
            let result = try resolveBlockStr(&mut a, "let x: bool = false; -x;");
3525
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3526
        }
3527
    }
3528
}
3529
3530
@test unsafe fn testResolveUnaryOpBitNot() throws (testing::TestError) {
3531
    {
3532
        let mut testArena254 = testArena();
3533
        let testStorage254: 'test254 = &mut testArena254 in {
3534
            let mut a = testResolver(testStorage254);
3535
            let result = try resolveExprStr(&mut a, "~42");
3536
            try expectNoErrors(&result);
3537
            try expectType(&a, result.root, super::Type::Int);
3538
        }
3539
    } {
3540
        let mut testArena255 = testArena();
3541
        let testStorage255: 'test255 = &mut testArena255 in {
3542
            let mut a = testResolver(testStorage255);
3543
            let result = try resolveBlockStr(&mut a, "let x: u32 = 255; ~x;");
3544
            try expectNoErrors(&result);
3545
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3546
            try expectExprStmtType(&a, stmt, super::Type::U32);
3547
        }
3548
    } {
3549
        let mut testArena256 = testArena();
3550
        let testStorage256: 'test256 = &mut testArena256 in {
3551
            let mut a = testResolver(testStorage256);
3552
            let result = try resolveExprStr(&mut a, "~(0xFF)");
3553
            try expectNoErrors(&result);
3554
            try expectType(&a, result.root, super::Type::Int);
3555
        }
3556
    } {
3557
        let mut testArena257 = testArena();
3558
        let testStorage257: 'test257 = &mut testArena257 in {
3559
            let mut a = testResolver(testStorage257);
3560
            let result = try resolveBlockStr(&mut a, "let x: i8 = 5; ~x;");
3561
            try expectNoErrors(&result);
3562
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3563
            try expectExprStmtType(&a, stmt, super::Type::I8);
3564
        }
3565
    } {
3566
        let mut testArena258 = testArena();
3567
        let testStorage258: 'test258 = &mut testArena258 in {
3568
            let mut a = testResolver(testStorage258);
3569
            let result = try resolveProgramStr(&mut a, "~true");
3570
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3571
        }
3572
    } {
3573
        let mut testArena259 = testArena();
3574
        let testStorage259: 'test259 = &mut testArena259 in {
3575
            let mut a = testResolver(testStorage259);
3576
            let result = try resolveBlockStr(&mut a, "let x: bool = false; ~x;");
3577
            try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
3578
        }
3579
    }
3580
}
3581
3582
@test unsafe fn testResolveUnaryOpNested() throws (testing::TestError) {
3583
    {
3584
        let mut testArena260 = testArena();
3585
        let testStorage260: 'test260 = &mut testArena260 in {
3586
            let mut a = testResolver(testStorage260);
3587
            let result = try resolveExprStr(&mut a, "not not true");
3588
            try expectNoErrors(&result);
3589
            try expectType(&a, result.root, super::Type::Bool);
3590
        }
3591
    } {
3592
        let mut testArena261 = testArena();
3593
        let testStorage261: 'test261 = &mut testArena261 in {
3594
            let mut a = testResolver(testStorage261);
3595
            let result = try resolveExprStr(&mut a, "--42");
3596
            try expectNoErrors(&result);
3597
            try expectType(&a, result.root, super::Type::Int);
3598
        }
3599
    } {
3600
        let mut testArena262 = testArena();
3601
        let testStorage262: 'test262 = &mut testArena262 in {
3602
            let mut a = testResolver(testStorage262);
3603
            let result = try resolveExprStr(&mut a, "~~0xFF");
3604
            try expectNoErrors(&result);
3605
            try expectType(&a, result.root, super::Type::Int);
3606
        }
3607
    } {
3608
        let mut testArena263 = testArena();
3609
        let testStorage263: 'test263 = &mut testArena263 in {
3610
            let mut a = testResolver(testStorage263);
3611
            let result = try resolveExprStr(&mut a, "-(~42)");
3612
            try expectNoErrors(&result);
3613
            try expectType(&a, result.root, super::Type::Int);
3614
        }
3615
    }
3616
}
3617
3618
// test fn testNormalPointerArithmetic() throws (testing::TestError) {
3619
//     mut a = testResolver();
3620
//     let result = try resolveProgramStr(&mut a, "fn test() { let ptr: *i32 = undefined; let x = ptr + 1; }");
3621
//     try expectNoErrors(&result);
3622
// }
3623
3624
// Dereference tests //////////////////////////////////////////////////////////
3625
3626
@test unsafe fn testResolveDeref() throws (testing::TestError) {
3627
    {
3628
        let mut testArena264 = testArena();
3629
        let testStorage264: 'test264 = &mut testArena264 in {
3630
            let mut a = testResolver(testStorage264);
3631
            let result = try resolveBlockStr(&mut a, "static x: i32 = 42; let ptr: *i32 = &x; *ptr;");
3632
            try expectNoErrors(&result);
3633
            let stmt = try parser::tests::getBlockLastStmt(result.root);
3634
            try expectExprStmtType(&a, stmt, super::Type::I32);
3635
        }
3636
    } {
3637
        let mut testArena265 = testArena();
3638
        let testStorage265: 'test265 = &mut testArena265 in {
3639
            let mut a = testResolver(testStorage265);
3640
            let result = try resolveExprStr(&mut a, "*42");
3641
            try expectErrorKind(&result, super::ErrorKind::ExpectedPointer);
3642
        }
3643
    } {
3644
        let mut testArena266 = testArena();
3645
        let testStorage266: 'test266 = &mut testArena266 in {
3646
            let mut a = testResolver(testStorage266);
3647
            let result = try resolveBlockStr(&mut a, "let x: i32 = 5; *x;");
3648
            try expectErrorKind(&result, super::ErrorKind::ExpectedPointer);
3649
        }
3650
    }
3651
}
3652
3653
@test unsafe fn testResolveAssignDeref() throws (testing::TestError) {
3654
    {
3655
        let mut testArena267 = testArena();
3656
        let testStorage267: 'test267 = &mut testArena267 in {
3657
            let mut a = testResolver(testStorage267);
3658
            let program = "static x: i32 = 0; let ptr: *mut i32 = &mut x; set *ptr = 42;";
3659
            let result = try resolveProgramStr(&mut a, program);
3660
            try expectNoErrors(&result);
3661
        }
3662
    } {
3663
        let mut testArena268 = testArena();
3664
        let testStorage268: 'test268 = &mut testArena268 in {
3665
            let mut a = testResolver(testStorage268);
3666
            let program = "static x: i32 = 0; let ptr: *i32 = &x; set *ptr = 42;";
3667
            let result = try resolveProgramStr(&mut a, program);
3668
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3669
        }
3670
    } {
3671
        let mut testArena269 = testArena();
3672
        let testStorage269: 'test269 = &mut testArena269 in {
3673
            let mut a = testResolver(testStorage269);
3674
            let program = "static x: i32 = 0; let mut ptr: *i32 = &x; set *ptr = 42;";
3675
            let result = try resolveProgramStr(&mut a, program);
3676
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3677
        }
3678
    } {
3679
        let mut testArena270 = testArena();
3680
        let testStorage270: 'test270 = &mut testArena270 in {
3681
            let mut a = testResolver(testStorage270);
3682
            let program = "static x: u8 = 0; let mut ptr: *mut u8 = &mut x; set *ptr = 255;";
3683
            let result = try resolveProgramStr(&mut a, program);
3684
            try expectNoErrors(&result);
3685
        }
3686
    }
3687
}
3688
3689
// Type inference tests ///////////////////////////////////////////////////////
3690
3691
@test unsafe fn testResolveBasicTypeInference() throws (testing::TestError) {
3692
    {
3693
        // Boolean literals are unambiguous.
3694
        let mut testArena271 = testArena();
3695
        let testStorage271: 'test271 = &mut testArena271 in {
3696
            let mut a = testResolver(testStorage271);
3697
            let result = try resolveProgramStr(&mut a, "let x = true; x;");
3698
            try expectNoErrors(&result);
3699
3700
            let xStmt = try parser::tests::getBlockLastStmt(result.root);
3701
            try expectExprStmtType(&a, xStmt, super::Type::Bool);
3702
        }
3703
    } {
3704
        // Integer literals are ambiguous.
3705
        let mut testArena272 = testArena();
3706
        let testStorage272: 'test272 = &mut testArena272 in {
3707
            let mut a = testResolver(testStorage272);
3708
            let result = try resolveProgramStr(&mut a, "let x = 34;");
3709
            try expectErrorKind(&result, super::ErrorKind::CannotInferType);
3710
        }
3711
    }
3712
}
3713
3714
// Union tests /////////////////////////////////////////////////////////////////
3715
3716
@test unsafe fn testResolveUnionVariantWithoutPayload() throws (testing::TestError) {
3717
    let mut testArena273 = testArena();
3718
    let testStorage273: 'test273 = &mut testArena273 in {
3719
        let mut a = testResolver(testStorage273);
3720
        let program = "union Status { Ok, Error } Status::Ok;";
3721
        let result = try resolveProgramStr(&mut a, program);
3722
3723
        let ty = try getTypeInScopeOf(&a, result.root, "Status");
3724
        let case super::NominalType::Union(unionType) = *ty
3725
            else throw testing::TestError::Failed;
3726
        try testing::expect(unionType.variants.len == 2);
3727
        try testing::expect(mem::eq(unionType.variants[0].name, "Ok"));
3728
        try testing::expect(mem::eq(unionType.variants[1].name, "Error"));
3729
        if getUnionVariantPayload(ty, "Ok") <> super::Type::Void {
3730
            throw testing::TestError::Failed;
3731
        }
3732
        let stmt = try getBlockStmt(result.root, 1);
3733
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
3734
        try expectNoErrors(&result);
3735
    }
3736
}
3737
3738
@test unsafe fn testResolveUnionVariantWithPayload() throws (testing::TestError) {
3739
    let mut testArena274 = testArena();
3740
    let testStorage274: 'test274 = &mut testArena274 in {
3741
        let mut a = testResolver(testStorage274);
3742
        let program = "union R { Ok(i32), Err(bool) } R::Ok(42);";
3743
        let result = try resolveProgramStr(&mut a, program);
3744
        try expectNoErrors(&result);
3745
3746
        let ty = try getTypeInScopeOf(&a, result.root, "R");
3747
3748
        let okPayload = getUnionVariantPayload(ty, "Ok");
3749
        try testing::expect(okPayload == super::Type::I32);
3750
3751
        let errPayload = getUnionVariantPayload(ty, "Err");
3752
        try testing::expect(errPayload == super::Type::Bool);
3753
3754
        let stmt = try getBlockStmt(result.root, 1);
3755
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
3756
3757
        // TODO: Test payload type.
3758
    }
3759
}
3760
3761
@test unsafe fn testResolveUnionVariantWithoutPayloadExplicitDiscriminant() throws (testing::TestError) {
3762
    let mut testArena275 = testArena();
3763
    let testStorage275: 'test275 = &mut testArena275 in {
3764
        let mut a = testResolver(testStorage275);
3765
        let program = "union R { Ok = 7, Err = 11 } R::Ok;";
3766
        let result = try resolveProgramStr(&mut a, program);
3767
        try expectNoErrors(&result);
3768
3769
        let ty = try getTypeInScopeOf(&a, result.root, "R");
3770
        let stmt = try getBlockStmt(result.root, 1);
3771
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
3772
    }
3773
}
3774
3775
@test unsafe fn testResolveUnionVariantPayloadTypeMismatch() throws (testing::TestError) {
3776
    let mut testArena276 = testArena();
3777
    let testStorage276: 'test276 = &mut testArena276 in {
3778
        let mut a = testResolver(testStorage276);
3779
        let program = "union R { Ok(i32), Error(bool) } R::Ok(true);";
3780
        let result = try resolveProgramStr(&mut a, program);
3781
        let err = try expectError(&result);
3782
        try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
3783
3784
        let ty = try getTypeInScopeOf(&a, result.root, "R");
3785
        let payload = getUnionVariantPayload(ty, "Ok");
3786
        try testing::expect(payload == super::Type::I32);
3787
3788
        let errNode = err.node
3789
            else throw testing::TestError::Failed;
3790
        let case ast::NodeValue::Bool(_) = errNode.value
3791
            else throw testing::TestError::Failed;
3792
    }
3793
}
3794
3795
@test unsafe fn testResolveUnionVariantUnexpectedPayload() throws (testing::TestError) {
3796
    let mut testArena277 = testArena();
3797
    let testStorage277: 'test277 = &mut testArena277 in {
3798
        let mut a = testResolver(testStorage277);
3799
        let program = "union Status { Ok, Error } Status::Ok(42);";
3800
        let result = try resolveProgramStr(&mut a, program);
3801
        let err = try expectError(&result);
3802
3803
        let case super::ErrorKind::UnionVariantPayloadUnexpected(_) = err.kind
3804
            else throw testing::TestError::Failed;
3805
        let node = err.node
3806
            else throw testing::TestError::Failed;
3807
        let case ast::NodeValue::Call(_) = node.value
3808
            else throw testing::TestError::Failed;
3809
    }
3810
}
3811
3812
@test unsafe fn testResolveUnionVariantUnknown() throws (testing::TestError) {
3813
    let mut testArena278 = testArena();
3814
    let testStorage278: 'test278 = &mut testArena278 in {
3815
        let mut a = testResolver(testStorage278);
3816
        let program = "union Status { Ok, Error } Status::Unknown;";
3817
        let result = try resolveProgramStr(&mut a, program);
3818
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
3819
    }
3820
}
3821
3822
@test unsafe fn testResolveScopeAccessUndefinedType() throws (testing::TestError) {
3823
    let mut testArena279 = testArena();
3824
    let testStorage279: 'test279 = &mut testArena279 in {
3825
        let mut a = testResolver(testStorage279);
3826
        let result = try resolveProgramStr(&mut a, "Unknown::X;");
3827
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
3828
    }
3829
}
3830
3831
@test unsafe fn testResolveUnionVariantVoidPayload() throws (testing::TestError) {
3832
    let mut testArena280 = testArena();
3833
    let testStorage280: 'test280 = &mut testArena280 in {
3834
        let mut a = testResolver(testStorage280);
3835
        let program = "union R { Success(i32), Pending } R::Pending;";
3836
        let result = try resolveProgramStr(&mut a, program);
3837
        try expectNoErrors(&result);
3838
3839
        let ty = try getTypeInScopeOf(&a, result.root, "R");
3840
        let payload = getUnionVariantPayload(ty, "Pending");
3841
        try testing::expect(payload == super::Type::Void);
3842
3843
        let stmt = try getBlockStmt(result.root, 1);
3844
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
3845
    }
3846
}
3847
3848
@test unsafe fn testResolveUnionVariantRecordPayload() throws (testing::TestError) {
3849
    let mut testArena281 = testArena();
3850
    let testStorage281: 'test281 = &mut testArena281 in {
3851
        let mut a = testResolver(testStorage281);
3852
        let program = "record P { x: i32, y: i32 } union S { Point(P), Num(u32) } S::Point(P { x: 10, y: 20 });";
3853
        let result = try resolveProgramStr(&mut a, program);
3854
        try expectNoErrors(&result);
3855
3856
        let ty = try getTypeInScopeOf(&a, result.root, "S");
3857
        let stmt = try getBlockStmt(result.root, 2);
3858
        try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
3859
    }
3860
}
3861
3862
@test unsafe fn testResolveBuiltinSizeOf() throws (testing::TestError) {
3863
    try resolveAndExpectConstExpr("@sizeOf(u8)", 1);
3864
    try resolveAndExpectConstExpr("@sizeOf(u16)", 2);
3865
    try resolveAndExpectConstExpr("@sizeOf(u32)", 4);
3866
    try resolveAndExpectConstExpr("@sizeOf(i32)", 4);
3867
    try resolveAndExpectConstExpr("@sizeOf(bool)", 1);
3868
    try resolveAndExpectConstExpr("@sizeOf(*u32)", 8);
3869
    try resolveAndExpectConstExpr("@sizeOf([u8; 10])", 10);
3870
    try resolveAndExpectConstExpr("@sizeOf(*[u32])", 16);
3871
    try resolveAndExpectConstExpr("@sizeOf(?u8)", 2);
3872
    try resolveAndExpectConstExpr("@sizeOf(?u16)", 4);
3873
    try resolveAndExpectConstExpr("@sizeOf(?u32)", 8);
3874
    try resolveAndExpectConstExpr("@sizeOf(*opaque)", 8);
3875
    try resolveAndExpectConstStmt("record T { x: u8 } @sizeOf(T);", 1);
3876
    try resolveAndExpectConstStmt("record T { x: i32 } @sizeOf(T);", 4);
3877
    try resolveAndExpectConstStmt("record T { x: i32, y: i8 } @sizeOf(T);", 8);
3878
    try resolveAndExpectConstStmt("record T { x: i8, y: i32 } @sizeOf(T);", 8);
3879
    try resolveAndExpectConstStmt("record T { x: i8, y: i32 } @sizeOf(T);", 8);
3880
    try resolveAndExpectConstStmt("record T { x: u32, y: u8, z: u8 }; @sizeOf(T);", 8);
3881
    try resolveAndExpectConstStmt("record T { x: u8, y: u32, z: u8 }; @sizeOf(T);", 12);
3882
    try resolveAndExpectConstStmt("union T { A, B, C }; @sizeOf(T);", 1);
3883
    try resolveAndExpectConstStmt("union T { A, B(u32), C }; @sizeOf(T);", 8);
3884
    try resolveAndExpectConstStmt("union T { A, B(u16), C }; @sizeOf(T);", 4);
3885
    try resolveAndExpectConstStmt("union T { A(u32), B(u16), C(u16) }; @sizeOf(T);", 8);
3886
    try resolveAndExpectConstStmt("union T { A(u32), B(u16), C([u8; 16]) }; @sizeOf(T);", 20);
3887
}
3888
3889
@test unsafe fn testResolveBuiltinAlignOf() throws (testing::TestError) {
3890
    try resolveAndExpectConstExpr("@alignOf(u8)", 1);
3891
    try resolveAndExpectConstExpr("@alignOf(u16)", 2);
3892
    try resolveAndExpectConstExpr("@alignOf(u32)", 4);
3893
    try resolveAndExpectConstExpr("@alignOf(i32)", 4);
3894
    try resolveAndExpectConstExpr("@alignOf(bool)", 1);
3895
    try resolveAndExpectConstExpr("@alignOf(*u8)", 8);
3896
    try resolveAndExpectConstExpr("@alignOf(*u16)", 8);
3897
    try resolveAndExpectConstExpr("@alignOf(*u32)", 8);
3898
    try resolveAndExpectConstExpr("@alignOf(*opaque)", 8);
3899
    try resolveAndExpectConstExpr("@alignOf([u8; 8])", 1);
3900
    try resolveAndExpectConstExpr("@alignOf([u16; 8])", 2);
3901
    try resolveAndExpectConstExpr("@alignOf([u32; 8])", 4);
3902
    try resolveAndExpectConstExpr("@alignOf(*[u32])", 8);
3903
    try resolveAndExpectConstExpr("@alignOf(?u8)", 1);
3904
    try resolveAndExpectConstExpr("@alignOf(?u16)", 2);
3905
    try resolveAndExpectConstExpr("@alignOf(?u32)", 4);
3906
    try resolveAndExpectConstStmt("record T { x: u8, y: u16 }; @alignOf(T);", 2);
3907
    try resolveAndExpectConstStmt("record T { x: u8, y: u32, z: u8 }; @alignOf(T);", 4);
3908
    try resolveAndExpectConstStmt("record T { x: u32, y: u8, z: u8 }; @alignOf(T);", 4);
3909
    try resolveAndExpectConstStmt("union T { A, B, C }; @alignOf(T);", 1);
3910
    try resolveAndExpectConstStmt("union T { A, B(u32), C }; @alignOf(T);", 4);
3911
}
3912
3913
@test unsafe fn testResolveBuiltinSizeOfRecord() throws (testing::TestError) {
3914
    let mut testArena282 = testArena();
3915
    let testStorage282: 'test282 = &mut testArena282 in {
3916
        let mut a = testResolver(testStorage282);
3917
        let program = "record T { x: u8, y: u32 } @sizeOf(T);";
3918
        let result = try resolveProgramStr(&mut a, program);
3919
        try expectNoErrors(&result);
3920
3921
        let stmt = try getBlockStmt(result.root, 1);
3922
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
3923
        try expectConstInt(&a, expr, 8);
3924
    }
3925
}
3926
3927
@test unsafe fn testResolveBuiltinSizeOfUnion() throws (testing::TestError) {
3928
    let mut testArena283 = testArena();
3929
    let testStorage283: 'test283 = &mut testArena283 in {
3930
        let mut a = testResolver(testStorage283);
3931
        let program = "union Result { Ok(u32), Err(u8) } @sizeOf(Result);";
3932
        let result = try resolveProgramStr(&mut a, program);
3933
        try expectNoErrors(&result);
3934
3935
        let stmt = try getBlockStmt(result.root, 1);
3936
        let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
3937
        try expectConstInt(&a, expr, 8);
3938
    }
3939
}
3940
3941
@test unsafe fn testResolveAlignAnnotation() throws (testing::TestError) {
3942
    {
3943
        let mut testArena284 = testArena();
3944
        let testStorage284: 'test284 = &mut testArena284 in {
3945
            let mut a = testResolver(testStorage284);
3946
            let result = try resolveBlockStr(&mut a, "let x: u8 align(8) = 0;");
3947
            try expectNoErrors(&result);
3948
3949
            let stmt = try getBlockStmt(result.root, 0);
3950
            let sym = super::symbolFor(&a, stmt)
3951
                else throw testing::TestError::Failed;
3952
            let case super::SymbolData::Value { type: valType, .. } = sym.data
3953
                else throw testing::TestError::Failed;
3954
            let layout = super::getLayout(&a, sym.node, valType);
3955
            try testing::expect(layout.alignment == 8);
3956
        }
3957
    } {
3958
        let mut testArena285 = testArena();
3959
        let testStorage285: 'test285 = &mut testArena285 in {
3960
            let mut a = testResolver(testStorage285);
3961
            let result = try resolveProgramStr(&mut a, "let x: u32 align(3) = 0;");
3962
            let err = try expectError(&result);
3963
            let case super::ErrorKind::InvalidAlignmentValue(val) = err.kind
3964
                else throw testing::TestError::Failed;
3965
            try testing::expect(val == 3);
3966
        }
3967
    } {
3968
        let mut testArena286 = testArena();
3969
        let testStorage286: 'test286 = &mut testArena286 in {
3970
            let mut a = testResolver(testStorage286);
3971
            let result = try resolveProgramStr(&mut a, "let x: u32 align(7) = 0;");
3972
            let err = try expectError(&result);
3973
            let case super::ErrorKind::InvalidAlignmentValue(val) = err.kind
3974
                else throw testing::TestError::Failed;
3975
            try testing::expect(val == 7);
3976
        }
3977
    }
3978
}
3979
3980
@test unsafe fn testResolveVoidAssignmentError() throws (testing::TestError) {
3981
    {
3982
        let mut testArena287 = testArena();
3983
        let testStorage287: 'test287 = &mut testArena287 in {
3984
            let mut a = testResolver(testStorage287);
3985
            let program = "fn voidFn() {} let _ = voidFn();";
3986
            let result = try resolveProgramStr(&mut a, program);
3987
            try expectErrorKind(&result, super::ErrorKind::CannotAssignVoid);
3988
        }
3989
    } {
3990
        let mut testArena288 = testArena();
3991
        let testStorage288: 'test288 = &mut testArena288 in {
3992
            let mut a = testResolver(testStorage288);
3993
            let program = "fn voidFn() {} let x = voidFn();";
3994
            let result = try resolveProgramStr(&mut a, program);
3995
            try expectErrorKind(&result, super::ErrorKind::CannotAssignVoid);
3996
        }
3997
    }
3998
}
3999
4000
//
4001
// Module Declaration Tests
4002
//
4003
4004
@test unsafe fn testResolveEmptyMod() throws (testing::TestError) {
4005
    let mut testArena289 = testArena();
4006
    let testStorage289: 'test289 = &mut testArena289 in {
4007
        let mut a = testResolver(testStorage289);
4008
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4009
        let mut graph = &mut MODULE_GRAPH;
4010
4011
        let rootId = try registerModule(graph, nil, "root", "mod child;", &mut arena);
4012
        let childId = try registerModule(graph, rootId, "child", "{}", &mut arena);
4013
        let result = try resolveModuleTree(&mut a, rootId);
4014
        try expectNoErrors(&result);
4015
    }
4016
}
4017
4018
@test unsafe fn testResolveModuleCannotAccessParentScope() throws (testing::TestError) {
4019
    let mut testArena290 = testArena();
4020
    let testStorage290: 'test290 = &mut testArena290 in {
4021
        let mut a = testResolver(testStorage290);
4022
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4023
4024
        // Register root and util modules.
4025
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod util; export fn helper() {}", &mut arena);
4026
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "fn main() { helper(); }", &mut arena);
4027
4028
        // Resolve should fail: the parent module is not in scope.
4029
        let result = try resolveModuleTree(&mut a, rootId);
4030
        let err = try expectError(&result);
4031
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4032
            else throw testing::TestError::Failed;
4033
        try testing::expect(mem::eq(name, "helper"));
4034
    }
4035
}
4036
4037
@test unsafe fn testResolveModuleAccessPrivateSubModule() throws (testing::TestError) {
4038
    let mut testArena291 = testArena();
4039
    let testStorage291: 'test291 = &mut testArena291 in {
4040
        let mut a = testResolver(testStorage291);
4041
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4042
4043
        // Register root and util modules.
4044
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod util; fn main() { util::helper(); }", &mut arena);
4045
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "export fn helper() {}", &mut arena);
4046
4047
        // Resolve should succeed: parent can access child.
4048
        let result = try resolveModuleTree(&mut a, rootId);
4049
        try expectNoErrors(&result);
4050
    }
4051
}
4052
4053
@test unsafe fn testResolveSiblingModulesCannotAccessDirectly() throws (testing::TestError) {
4054
    let mut testArena292 = testArena();
4055
    let testStorage292: 'test292 = &mut testArena292 in {
4056
        let mut a = testResolver(testStorage292);
4057
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4058
4059
        // Register root with two sibling modules.
4060
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod paul; export mod patrick;", &mut arena);
4061
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "paul", "fn main() { patrick::helper(); }", &mut arena);
4062
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "patrick", "export fn helper() -> i32 { return 42; }", &mut arena);
4063
4064
        // Resolve should fail: siblings can't access each other directly.
4065
        let result = try resolveModuleTree(&mut a, rootId);
4066
        let err = try expectError(&result);
4067
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4068
            else throw testing::TestError::Failed;
4069
        try testing::expect(mem::eq(name, "patrick"));
4070
    }
4071
}
4072
4073
@test unsafe fn testResolveSiblingModulesViaRoot() throws (testing::TestError) {
4074
    let mut testArena293 = testArena();
4075
    let testStorage293: 'test293 = &mut testArena293 in {
4076
        let mut a = testResolver(testStorage293);
4077
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4078
4079
        // Register root with two sibling modules.
4080
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod paul; export mod patrick;", &mut arena);
4081
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "paul", "use root::patrick; fn main() -> i32 { return patrick::helper(); }", &mut arena);
4082
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "patrick", "export fn helper() -> i32 { return 42; }", &mut arena);
4083
4084
        // Resolve should succeed: siblings can access each other via root.
4085
        let result = try resolveModuleTree(&mut a, rootId);
4086
        try expectNoErrors(&result);
4087
    }
4088
}
4089
4090
@test unsafe fn testResolveModuleMutualRecursion() throws (testing::TestError) {
4091
    let mut testArena294 = testArena();
4092
    let testStorage294: 'test294 = &mut testArena294 in {
4093
        let mut a = testResolver(testStorage294);
4094
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4095
4096
        // Register root with two sibling modules that call each other.
4097
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod left; export mod right;", &mut arena);
4098
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "left", "use root::right; export fn leftHelper() -> i32 { return right::rightHelper(); }", &mut arena);
4099
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "right", "use root::left; export fn rightHelper() -> i32 { return left::leftHelper(); }", &mut arena);
4100
4101
        // Resolve should succeed: cyclic use is allowed.
4102
        let result = try resolveModuleTree(&mut a, rootId);
4103
        try expectNoErrors(&result);
4104
    }
4105
}
4106
4107
@test unsafe fn testResolveAccessModuleType() throws (testing::TestError) {
4108
    let mut testArena295 = testArena();
4109
    let testStorage295: 'test295 = &mut testArena295 in {
4110
        let mut a = testResolver(testStorage295);
4111
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4112
4113
        // Register root with types module containing a record.
4114
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4115
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Point { x: i32, y: i32 }", &mut arena);
4116
        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);
4117
4118
        // Resolve should succeed: types can be accessed.
4119
        let result = try resolveModuleTree(&mut a, rootId);
4120
        try expectNoErrors(&result);
4121
    }
4122
}
4123
4124
@test unsafe fn testResolveAccessModuleConstant() throws (testing::TestError) {
4125
    let mut testArena296 = testArena();
4126
    let testStorage296: 'test296 = &mut testArena296 in {
4127
        let mut a = testResolver(testStorage296);
4128
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4129
4130
        // Register root with constants module.
4131
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
4132
        let constantsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant MAX_SIZE: i32 = 100;", &mut arena);
4133
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() -> i32 { return consts::MAX_SIZE; }", &mut arena);
4134
4135
        // Resolve should succeed: constants can be accessed.
4136
        let result = try resolveModuleTree(&mut a, rootId);
4137
        try expectNoErrors(&result);
4138
    }
4139
}
4140
4141
@test unsafe fn testResolveRootSymbolMustBeImported() throws (testing::TestError) {
4142
    let mut testArena297 = testArena();
4143
    let testStorage297: 'test297 = &mut testArena297 in {
4144
        let mut a = testResolver(testStorage297);
4145
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4146
4147
        // Register deeply nested modules: `root::app::services::auth`.
4148
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; export fn helper() -> i32 { return 42; }", &mut arena);
4149
        let mainId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "fn run() -> i32 { return root::helper(); }", &mut arena);
4150
4151
        // Resolve should fail: the `root` module must be imported.
4152
        let result = try resolveModuleTree(&mut a, rootId);
4153
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("root"));
4154
    }
4155
}
4156
4157
@test unsafe fn testResolveUseImportsNestedSymbol() throws (testing::TestError) {
4158
    let mut testArena298 = testArena();
4159
    let testStorage298: 'test298 = &mut testArena298 in {
4160
        let mut a = testResolver(testStorage298);
4161
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4162
4163
        // Register deeply nested modules: `root::app::services::auth`.
4164
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod app; mod main;", &mut arena);
4165
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "export mod services;", &mut arena);
4166
        let servicesId = try registerModule(&mut MODULE_GRAPH, appId, "services", "export mod auth;", &mut arena);
4167
        let authId = try registerModule(&mut MODULE_GRAPH, servicesId, "auth", "export fn login() -> i32 { return 1; }", &mut arena);
4168
        let mainId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::app::services::auth; fn run() -> i32 { return auth::login(); }", &mut arena);
4169
        let otherId = try registerModule(&mut MODULE_GRAPH, rootId, "other", "use root; fn run() -> i32 { return root::app::services::auth::login(); }", &mut arena);
4170
4171
        // Resolve should succeed: use imports the module symbol.
4172
        let result = try resolveModuleTree(&mut a, rootId);
4173
        try expectNoErrors(&result);
4174
    }
4175
}
4176
4177
@test unsafe fn testResolveUseNonExistentModule() throws (testing::TestError) {
4178
    let mut testArena299 = testArena();
4179
    let testStorage299: 'test299 = &mut testArena299 in {
4180
        let mut a = testResolver(testStorage299);
4181
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4182
4183
        // Register root with app trying to use a non-existent module.
4184
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod app;", &mut arena);
4185
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::unknown;", &mut arena);
4186
4187
        // Resolve should fail: module doesn't exist.
4188
        let result = try resolveModuleTree(&mut a, rootId);
4189
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("unknown"));
4190
    }
4191
}
4192
4193
@test unsafe fn testResolveUsePrivateFn() throws (testing::TestError) {
4194
    let mut testArena300 = testArena();
4195
    let testStorage300: 'test300 = &mut testArena300 in {
4196
        let mut a = testResolver(testStorage300);
4197
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4198
4199
        // Register root with util module containing a private function.
4200
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod util; mod app;", &mut arena);
4201
        let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "fn private() -> i32 { return 42; }", &mut arena);
4202
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::util; fn main() -> i32 { return util::private(); }", &mut arena);
4203
4204
        // Resolve should fail: function is not public.
4205
        let result = try resolveModuleTree(&mut a, rootId);
4206
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
4207
    }
4208
}
4209
4210
@test unsafe fn testResolveUsePrivateMod() throws (testing::TestError) {
4211
    let mut testArena301 = testArena();
4212
    let testStorage301: 'test301 = &mut testArena301 in {
4213
        let mut a = testResolver(testStorage301);
4214
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4215
4216
        // Register root with public and private child modules.
4217
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; mod private;", &mut arena);
4218
        let privateId = try registerModule(&mut MODULE_GRAPH, rootId, "private", "{}", &mut arena);
4219
        let publicId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::private;", &mut arena);
4220
4221
        // Resolve should fail: module is not public.
4222
        let result = try resolveModuleTree(&mut a, rootId);
4223
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
4224
    }
4225
}
4226
4227
@test unsafe fn testResolveUsePublicMod() throws (testing::TestError) {
4228
    let mut testArena302 = testArena();
4229
    let testStorage302: 'test302 = &mut testArena302 in {
4230
        let mut a = testResolver(testStorage302);
4231
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4232
4233
        // Register root with public and private child modules.
4234
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; export mod public;", &mut arena);
4235
        let privateId = try registerModule(&mut MODULE_GRAPH, rootId, "public", "{}", &mut arena);
4236
        let publicId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::public;", &mut arena);
4237
4238
        // Resolve should succeed: module is public.
4239
        let result = try resolveModuleTree(&mut a, rootId);
4240
        try expectNoErrors(&result);
4241
    }
4242
}
4243
4244
@test unsafe fn testResolveUseNonPublicType() throws (testing::TestError) {
4245
    let mut testArena303 = testArena();
4246
    let testStorage303: 'test303 = &mut testArena303 in {
4247
        let mut a = testResolver(testStorage303);
4248
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4249
4250
        // Register root with types module containing a private record.
4251
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4252
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "record Priv { x: i32 }", &mut arena);
4253
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> types::Priv { return types::Priv { x: 1 }; }", &mut arena);
4254
4255
        // Resolve should fail: record is not public.
4256
        let result = try resolveModuleTree(&mut a, rootId);
4257
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Priv"));
4258
    }
4259
}
4260
4261
@test unsafe fn testResolveImportPublicType() throws (testing::TestError) {
4262
    let mut testArena304 = testArena();
4263
    let testStorage304: 'test304 = &mut testArena304 in {
4264
        let mut a = testResolver(testStorage304);
4265
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4266
4267
        // Register root with types module containing a public record.
4268
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod app;", &mut arena);
4269
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Pub { x: i32 }", &mut arena);
4270
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> types::Pub { return types::Pub { x: 1 }; }", &mut arena);
4271
4272
        // Resolve should succeed: record is public.
4273
        let result = try resolveModuleTree(&mut a, rootId);
4274
        try expectNoErrors(&result);
4275
    }
4276
}
4277
4278
@test unsafe fn testResolveUseNonPublicStatic() throws (testing::TestError) {
4279
    let mut testArena305 = testArena();
4280
    let testStorage305: 'test305 = &mut testArena305 in {
4281
        let mut a = testResolver(testStorage305);
4282
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4283
4284
        // Register root with statics module containing a private static.
4285
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
4286
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "static PRIVATE: i32 = 42;", &mut arena);
4287
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() -> i32 { return statics::PRIVATE; }", &mut arena);
4288
4289
        // Resolve should fail: static is not public.
4290
        let result = try resolveModuleTree(&mut a, rootId);
4291
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("PRIVATE"));
4292
    }
4293
}
4294
4295
@test unsafe fn testResolveImportPublicStatic() throws (testing::TestError) {
4296
    let mut testArena306 = testArena();
4297
    let testStorage306: 'test306 = &mut testArena306 in {
4298
        let mut a = testResolver(testStorage306);
4299
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4300
4301
        // Register root with statics module containing a public static.
4302
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
4303
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "export static PUBLIC: i32 = 42;", &mut arena);
4304
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() -> i32 { return statics::PUBLIC; }", &mut arena);
4305
4306
        // Resolve should succeed: static is public.
4307
        let result = try resolveModuleTree(&mut a, rootId);
4308
        try expectNoErrors(&result);
4309
    }
4310
}
4311
4312
@test unsafe fn testResolveAccessSuper() throws (testing::TestError) {
4313
    {
4314
        let mut testArena307 = testArena();
4315
        let testStorage307: 'test307 = &mut testArena307 in {
4316
            let mut a = testResolver(testStorage307);
4317
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4318
4319
            // Test function access.
4320
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; export fn parentFn() -> i32 { return 42; }", &mut arena);
4321
            let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "fn main() -> i32 { return super::parentFn(); }", &mut arena);
4322
            let result = try resolveModuleTree(&mut a, rootId);
4323
            try expectNoErrors(&result);
4324
        }
4325
    } {
4326
        let mut testArena308 = testArena();
4327
        let testStorage308: 'test308 = &mut testArena308 in {
4328
            let mut a = testResolver(testStorage308);
4329
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4330
4331
            // Test type access.
4332
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; export record Point { x: i32, y: i32 }", &mut arena);
4333
            let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "fn make() -> super::Point { return super::Point { x: 1, y: 2 }; }", &mut arena);
4334
            let result = try resolveModuleTree(&mut a, rootId);
4335
            try expectNoErrors(&result);
4336
        }
4337
    }
4338
}
4339
4340
/// Test nested super access to union variants (e.g. `super::E::A`).
4341
@test unsafe fn testResolveSuperUnionVariant() throws (testing::TestError) {
4342
    let mut testArena309 = testArena();
4343
    let testStorage309: 'test309 = &mut testArena309 in {
4344
        let mut a = testResolver(testStorage309);
4345
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4346
4347
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod c; export union E { A, B }", &mut arena);
4348
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "c",
4349
            "fn f(x: super::E) { match x { case super::E::A => {}, case super::E::B => {} } }",
4350
            &mut arena);
4351
        let result = try resolveModuleTree(&mut a, rootId);
4352
        try expectNoErrors(&result);
4353
    }
4354
}
4355
4356
@test unsafe fn testResolveUseSuper() throws (testing::TestError) {
4357
    let mut testArena310 = testArena();
4358
    let testStorage310: 'test310 = &mut testArena310 in {
4359
        let mut a = testResolver(testStorage310);
4360
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4361
4362
        // Register root with a function, and a child module that uses super to access it.
4363
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod joe; export mod kate;", &mut arena);
4364
        let kateId = try registerModule(&mut MODULE_GRAPH, rootId, "kate", "export fn run() {}", &mut arena);
4365
        let joeId = try registerModule(&mut MODULE_GRAPH, rootId, "joe", "use super::kate; fn main() { kate::run(); }", &mut arena);
4366
4367
        // Resolve should succeed - super allows accessing parent module.
4368
        let result = try resolveModuleTree(&mut a, rootId);
4369
        try expectNoErrors(&result);
4370
    }
4371
}
4372
4373
@test unsafe fn testResolveModNotFound() throws (testing::TestError) {
4374
    let mut testArena311 = testArena();
4375
    let testStorage311: 'test311 = &mut testArena311 in {
4376
        let mut a = testResolver(testStorage311);
4377
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4378
4379
        // Register root that declares a module that doesn't exist.
4380
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod unknown;", &mut arena);
4381
4382
        // Resolve should fail: module doesn't exist.
4383
        let result = try resolveModuleTree(&mut a, rootId);
4384
        let err = try expectError(&result);
4385
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
4386
            else throw testing::TestError::Failed;
4387
        try testing::expect(mem::eq(name, "unknown"));
4388
    }
4389
}
4390
4391
@test unsafe fn testResolveDuplicateSubModule() throws (testing::TestError) {
4392
    let mut testArena312 = testArena();
4393
    let testStorage312: 'test312 = &mut testArena312 in {
4394
        let mut a = testResolver(testStorage312);
4395
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4396
4397
        // Register root that declares a module twice.
4398
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; mod child;", &mut arena);
4399
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "{}", &mut arena);
4400
4401
        // Resolve should fail: can't declare the same module twice.
4402
        let result = try resolveModuleTree(&mut a, rootId);
4403
        let err = try expectError(&result);
4404
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("child"));
4405
    }
4406
}
4407
4408
@test unsafe fn testResolveUseSubModule() throws (testing::TestError) {
4409
    let mut testArena313 = testArena();
4410
    let testStorage313: 'test313 = &mut testArena313 in {
4411
        let mut a = testResolver(testStorage313);
4412
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4413
4414
        // Register root that declares and imports the same module.
4415
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; use child;", &mut arena);
4416
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "{}", &mut arena);
4417
4418
        // Resolve should fail: Both `mod` and `use` are trying to create the same binding.
4419
        let result = try resolveModuleTree(&mut a, rootId);
4420
        let err = try expectError(&result);
4421
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("child"));
4422
    }
4423
}
4424
4425
@test unsafe fn testResolveDuplicateUse() throws (testing::TestError) {
4426
    let mut testArena314 = testArena();
4427
    let testStorage314: 'test314 = &mut testArena314 in {
4428
        let mut a = testResolver(testStorage314);
4429
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4430
4431
        // Register a module that imports the same module twice.
4432
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child", &mut arena);
4433
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "use root; use root;", &mut arena);
4434
4435
        // Resolve should fail.
4436
        let result = try resolveModuleTree(&mut a, rootId);
4437
        let err = try expectError(&result);
4438
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("root"));
4439
    }
4440
}
4441
4442
/// Test that opaque pointers are allowed in record fields.
4443
@test unsafe fn testOpaquePointerInRecordField() throws (testing::TestError) {
4444
    let mut testArena315 = testArena();
4445
    let testStorage315: 'test315 = &mut testArena315 in {
4446
        let mut a = testResolver(testStorage315);
4447
        let result = try resolveProgramStr(&mut a, "record T { x: *opaque }");
4448
        try expectNoErrors(&result);
4449
    }
4450
}
4451
4452
/// You cannot use `@sizeOf` or `@alignOf` on opaque type.
4453
@test unsafe fn testOpaqueTypeNoSizeOfAlignOf() throws (testing::TestError) {
4454
    let mut testArena316 = testArena();
4455
    let testStorage316: 'test316 = &mut testArena316 in {
4456
        let mut a = testResolver(testStorage316);
4457
4458
        let result1 = try resolveExprStr(&mut a, "@sizeOf(opaque)");
4459
        let err1 = try expectError(&result1);
4460
        try expectErrorKind(&result1, super::ErrorKind::OpaqueTypeNotAllowed);
4461
4462
        let result2 = try resolveExprStr(&mut a, "@alignOf(opaque)");
4463
        let err2 = try expectError(&result2);
4464
        try expectErrorKind(&result2, super::ErrorKind::OpaqueTypeNotAllowed);
4465
    }
4466
}
4467
4468
/// Test that immutable slice/pointer parameters cannot be borrowed mutably.
4469
@test unsafe fn testMutableBorrowFromImmutablePointer() throws (testing::TestError) {
4470
    let mut testArena317 = testArena();
4471
    let testStorage317: 'test317 = &mut testArena317 in {
4472
        let mut a = testResolver(testStorage317);
4473
        let program = "fn f(p: *i32) { let x = &mut *p; }";
4474
        let result = try resolveProgramStr(&mut a, program);
4475
        let err = try expectError(&result);
4476
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4477
    }
4478
}
4479
4480
/// Test that immutable slice parameters cannot be borrowed mutably.
4481
@test unsafe fn testMutableBorrowFromImmutableSlice() throws (testing::TestError) {
4482
    let mut testArena318 = testArena();
4483
    let testStorage318: 'test318 = &mut testArena318 in {
4484
        let mut a = testResolver(testStorage318);
4485
        let program = "fn f(s: *[i32]) { let x: *mut i32 = &mut s[0]; }";
4486
        let result = try resolveProgramStr(&mut a, program);
4487
        let err = try expectError(&result);
4488
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4489
    }
4490
}
4491
4492
/// Test that mutable pointer parameters can be borrowed mutably.
4493
@test unsafe fn testMutableBorrowFromMutablePointer() throws (testing::TestError) {
4494
    let mut testArena319 = testArena();
4495
    let testStorage319: 'test319 = &mut testArena319 in {
4496
        let mut a = testResolver(testStorage319);
4497
        let program = "fn f(p: *mut i32) { let x: *mut i32 = &mut *p; }";
4498
        let result = try resolveProgramStr(&mut a, program);
4499
        try expectNoErrors(&result);
4500
    }
4501
}
4502
4503
/// Test that mutable slice parameters can be borrowed mutably.
4504
@test unsafe fn testMutableBorrowFromMutableSlice() throws (testing::TestError) {
4505
    let mut testArena320 = testArena();
4506
    let testStorage320: 'test320 = &mut testArena320 in {
4507
        let mut a = testResolver(testStorage320);
4508
        let program = "fn f(s: *mut [i32]) { let x: *mut i32 = &mut s[0]; }";
4509
        let result = try resolveProgramStr(&mut a, program);
4510
        try expectNoErrors(&result);
4511
    }
4512
}
4513
4514
/// Test borrowing mutably from a field access on a call returning `*mut`.
4515
@test unsafe fn testMutableBorrowFromCallReturningMutablePointer() throws (testing::TestError) {
4516
    let mut testArena321 = testArena();
4517
    let testStorage321: 'test321 = &mut testArena321 in {
4518
        let mut a = testResolver(testStorage321);
4519
        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; }";
4520
        let result = try resolveProgramStr(&mut a, program);
4521
        try expectNoErrors(&result);
4522
    }
4523
}
4524
4525
/// Test that calls returning immutable pointers cannot be mutably borrowed.
4526
@test unsafe fn testMutableBorrowFromCallReturningImmutablePointer() throws (testing::TestError) {
4527
    let mut testArena322 = testArena();
4528
    let testStorage322: 'test322 = &mut testArena322 in {
4529
        let mut a = testResolver(testStorage322);
4530
        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; }";
4531
        let result = try resolveProgramStr(&mut a, program);
4532
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4533
    }
4534
}
4535
4536
/// Test borrowing mutably from a public static through scope access.
4537
@test unsafe fn testMutableBorrowFromScopeAccessStatic() throws (testing::TestError) {
4538
    let mut testArena323 = testArena();
4539
    let testStorage323: 'test323 = &mut testArena323 in {
4540
        let mut a = testResolver(testStorage323);
4541
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4542
4543
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
4544
        let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "export static COUNTER: i32 = 0;", &mut arena);
4545
        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);
4546
4547
        let result = try resolveModuleTree(&mut a, rootId);
4548
        try expectNoErrors(&result);
4549
    }
4550
}
4551
4552
/// Test that constants through scope access cannot be mutably borrowed.
4553
@test unsafe fn testMutableBorrowFromScopeAccessConstant() throws (testing::TestError) {
4554
    let mut testArena324 = testArena();
4555
    let testStorage324: 'test324 = &mut testArena324 in {
4556
        let mut a = testResolver(testStorage324);
4557
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4558
4559
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
4560
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant LIMIT: i32 = 7;", &mut arena);
4561
        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);
4562
4563
        let result = try resolveModuleTree(&mut a, rootId);
4564
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4565
    }
4566
}
4567
4568
/// Test that mutable bindings of immutable pointers cannot borrow mutably through the pointer.
4569
@test unsafe fn testMutableBorrowFromMutableBindingOfPointer() throws (testing::TestError) {
4570
    let mut testArena325 = testArena();
4571
    let testStorage325: 'test325 = &mut testArena325 in {
4572
        let mut a = testResolver(testStorage325);
4573
        let program = "fn f() { static x: i32 = 1; let p: *i32 = &x; let y = &mut *p; }";
4574
        let result = try resolveProgramStr(&mut a, program);
4575
        let err = try expectError(&result);
4576
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4577
    }
4578
}
4579
4580
/// Test that mutable pointer to immutable slice cannot be assigned through index.
4581
/// This tests the case where we have `*mut *[T]`; the outer pointer is mutable but
4582
/// the inner slice is immutable, so we shouldn't be able to mutate the elements.
4583
@test unsafe fn testAssignThroughMutablePointerToImmutableSlice() throws (testing::TestError) {
4584
    let mut testArena326 = testArena();
4585
    let testStorage326: 'test326 = &mut testArena326 in {
4586
        let mut a = testResolver(testStorage326);
4587
        let program = "fn f(slice: *[i32]) { let p: *mut *[i32] = &mut slice; set p[0] = 1; }";
4588
        let result = try resolveProgramStr(&mut a, program);
4589
4590
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4591
    }
4592
}
4593
4594
/// Test that mutable slice parameters can be assigned through index.
4595
@test unsafe fn testAssignThroughMutableSliceParam() throws (testing::TestError) {
4596
    {
4597
        // Mutable slice param: direct assignment should work
4598
        let mut testArena327 = testArena();
4599
        let testStorage327: 'test327 = &mut testArena327 in {
4600
            let mut a = testResolver(testStorage327);
4601
            let program = "fn f(slice: *mut [i32]) { set slice[0] = 1; }";
4602
            let result = try resolveProgramStr(&mut a, program);
4603
            try expectNoErrors(&result);
4604
        }
4605
    } {
4606
        // Immutable slice param: direct assignment should fail
4607
        let mut testArena328 = testArena();
4608
        let testStorage328: 'test328 = &mut testArena328 in {
4609
            let mut a = testResolver(testStorage328);
4610
            let program = "fn f(slice: *[i32]) { set slice[0] = 1; }";
4611
            let result = try resolveProgramStr(&mut a, program);
4612
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4613
        }
4614
    }
4615
}
4616
4617
/// Test range end type coercion with assignable types.
4618
@test unsafe fn testRangeEndTypeCoercion() throws (testing::TestError) {
4619
    {
4620
        let mut testArena329 = testArena();
4621
        let testStorage329: 'test329 = &mut testArena329 in {
4622
            let mut a = testResolver(testStorage329);
4623
            let program = "fn f(end: u32) { for i in 0..end {} }";
4624
            let result = try resolveProgramStr(&mut a, program);
4625
            try expectNoErrors(&result);
4626
        }
4627
    } {
4628
        let mut testArena330 = testArena();
4629
        let testStorage330: 'test330 = &mut testArena330 in {
4630
            let mut a = testResolver(testStorage330);
4631
            let program = "fn f(start: u32) { for i in start..9 {} }";
4632
            let result = try resolveProgramStr(&mut a, program);
4633
            try expectNoErrors(&result);
4634
        }
4635
    }
4636
}
4637
4638
/// Mixed-width range bounds require an explicit cast.
4639
@test unsafe fn testRangeEndTypeSubType() throws (testing::TestError) {
4640
    {
4641
        let mut testArena331 = testArena();
4642
        let testStorage331: 'test331 = &mut testArena331 in {
4643
            let mut a = testResolver(testStorage331);
4644
            let program = "fn f(start: i8, end: u32) { for i in start..end {} }";
4645
            let result = try resolveProgramStr(&mut a, program);
4646
            let err = try expectError(&result);
4647
            try expectTypeMismatch(err, super::Type::I8, super::Type::U32);
4648
        }
4649
    } {
4650
        let mut testArena332 = testArena();
4651
        let testStorage332: 'test332 = &mut testArena332 in {
4652
            let mut a = testResolver(testStorage332);
4653
            let program = "fn f(start: i8, end: u32) { for i in (start as u32)..end {} }";
4654
            let result = try resolveProgramStr(&mut a, program);
4655
            try expectNoErrors(&result);
4656
        }
4657
    }
4658
}
4659
4660
/// Test that try-catch expressions in statement context accept mismatched types.
4661
@test unsafe fn testTryCatchInStatementContextTypeMismatchOk() throws (testing::TestError) {
4662
    let mut testArena333 = testArena();
4663
    let testStorage333: 'test333 = &mut testArena333 in {
4664
        let mut a = testResolver(testStorage333);
4665
        let program = "fn f() { try g() catch {}; } fn g() -> bool throws (i32) { panic; }";
4666
        let result = try resolveProgramStr(&mut a, program);
4667
        try expectNoErrors(&result);
4668
    }
4669
}
4670
4671
/// Test that try-catch blocks in value context require divergence or void.
4672
@test unsafe fn testTryCatchInValueContextTypeMismatch() throws (testing::TestError) {
4673
    let mut testArena334 = testArena();
4674
    let testStorage334: 'test334 = &mut testArena334 in {
4675
        let mut a = testResolver(testStorage334);
4676
        let program = "fn f() -> bool { return try g() catch {}; } fn g() -> bool throws (i32) { panic; }";
4677
        let result = try resolveProgramStr(&mut a, program);
4678
        let err = try expectError(&result);
4679
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Void);
4680
    }
4681
}
4682
4683
/// Test that try-catch blocks in value context work when they diverge.
4684
@test unsafe fn testTryCatchInValueContextDiverges() throws (testing::TestError) {
4685
    let mut testArena335 = testArena();
4686
    let testStorage335: 'test335 = &mut testArena335 in {
4687
        let mut a = testResolver(testStorage335);
4688
        let program = "fn f() -> bool { return try g() catch { return false; }; } fn g() -> bool throws (i32) { panic; }";
4689
        let result = try resolveProgramStr(&mut a, program);
4690
        try expectNoErrors(&result);
4691
    }
4692
}
4693
4694
/// Test that `try?` lifts result type to optional.
4695
@test unsafe fn testTryOptionalLiftsToOptional() throws (testing::TestError) {
4696
    let mut testArena336 = testArena();
4697
    let testStorage336: 'test336 = &mut testArena336 in {
4698
        let mut a = testResolver(testStorage336);
4699
        let program = "record S {} fn f() -> ?*S { return try? g(); } fn g() -> *S throws (i32) { panic; }";
4700
        let result = try resolveProgramStr(&mut a, program);
4701
        try expectNoErrors(&result);
4702
    }
4703
}
4704
4705
/// Test that record fields can be assigned if the record binding is mutable.
4706
@test unsafe fn testMutableAssignToMutableRecordBinding() throws (testing::TestError) {
4707
    let mut testArena337 = testArena();
4708
    let testStorage337: 'test337 = &mut testArena337 in {
4709
        let mut a = testResolver(testStorage337);
4710
        let program = "record S { x: i32 } fn f() { let mut s = S { x: 1 }; set s.x = 2; }";
4711
        let result = try resolveProgramStr(&mut a, program);
4712
        try expectNoErrors(&result);
4713
    }
4714
}
4715
4716
/// Test that record fields cannot be assigned if the record binding is immutable.
4717
@test unsafe fn testMutableAssignToImmutableRecordBinding() throws (testing::TestError) {
4718
    let mut testArena338 = testArena();
4719
    let testStorage338: 'test338 = &mut testArena338 in {
4720
        let mut a = testResolver(testStorage338);
4721
        let program = "record S { x: i32 } fn f() { let s = S { x: 1 }; set s.x = 2; }";
4722
        let result = try resolveProgramStr(&mut a, program);
4723
        let err = try expectError(&result);
4724
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4725
    }
4726
}
4727
4728
/// Test that record fields can be assigned through a mutable pointer.
4729
@test unsafe fn testMutableAssignToMutablePointerToRecord() throws (testing::TestError) {
4730
    let mut testArena339 = testArena();
4731
    let testStorage339: 'test339 = &mut testArena339 in {
4732
        let mut a = testResolver(testStorage339);
4733
        let program = "record S { x: i32 } fn f(p: *mut S) { set p.x = 2; }";
4734
        let result = try resolveProgramStr(&mut a, program);
4735
        try expectNoErrors(&result);
4736
    }
4737
}
4738
4739
/// Test that record fields cannot be assigned through an immutable pointer.
4740
@test unsafe fn testMutableAssignToImmutablePointerToRecord() throws (testing::TestError) {
4741
    let mut testArena340 = testArena();
4742
    let testStorage340: 'test340 = &mut testArena340 in {
4743
        let mut a = testResolver(testStorage340);
4744
        let program = "record S { x: i32 } fn f(p: *S) { set p.x = 2; }";
4745
        let result = try resolveProgramStr(&mut a, program);
4746
        let err = try expectError(&result);
4747
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4748
    }
4749
}
4750
4751
// Opaque pointer tests.
4752
4753
/// You can assign any pointer (*T) to an opaque pointer (*opaque) without a cast.
4754
@test unsafe fn testOpaquePointerAutoCoercion() throws (testing::TestError) {
4755
    let mut testArena341 = testArena();
4756
    let testStorage341: 'test341 = &mut testArena341 in {
4757
        let mut a = testResolver(testStorage341);
4758
        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; }");
4759
        try expectNoErrors(&result);
4760
    }
4761
}
4762
4763
/// You cannot assign an opaque pointer to a non-opaque pointer without a cast.
4764
@test unsafe fn testOpaquePointerNoReverseCoercion() throws (testing::TestError) {
4765
    let mut testArena342 = testArena();
4766
    let testStorage342: 'test342 = &mut testArena342 in {
4767
        let mut a = testResolver(testStorage342);
4768
        let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let ptr: *i32 = o; }");
4769
        let err = try expectError(&result);
4770
        let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
4771
            else throw testing::TestError::Failed;
4772
        let case super::Type::Pointer { target: expectedTarget, .. } = mismatch.expected
4773
            else throw testing::TestError::Failed;
4774
        let case super::Type::Pointer { target: actualTarget, .. } = mismatch.actual
4775
            else throw testing::TestError::Failed;
4776
4777
        try testing::expect(*expectedTarget == super::Type::I32);
4778
        try testing::expect(*actualTarget == super::Type::Opaque);
4779
    }
4780
}
4781
4782
/// You cannot have a value of type `opaque` (function parameter).
4783
@test unsafe fn testOpaqueValue() throws (testing::TestError) {
4784
    {
4785
        let mut testArena343 = testArena();
4786
        let testStorage343: 'test343 = &mut testArena343 in {
4787
            let mut a = testResolver(testStorage343);
4788
            let result = try resolveProgramStr(&mut a, "fn f(x: opaque) {}");
4789
            let err = try expectError(&result);
4790
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
4791
        }
4792
    } {
4793
        let mut testArena344 = testArena();
4794
        let testStorage344: 'test344 = &mut testArena344 in {
4795
            let mut a = testResolver(testStorage344);
4796
            let result = try resolveProgramStr(&mut a, "unsafe fn f() { let x: opaque = undefined; }");
4797
            let err = try expectError(&result);
4798
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
4799
        }
4800
    } {
4801
        let mut testArena345 = testArena();
4802
        let testStorage345: 'test345 = &mut testArena345 in {
4803
            let mut a = testResolver(testStorage345);
4804
            let result = try resolveProgramStr(&mut a, "record R { x: opaque }");
4805
            let err = try expectError(&result);
4806
            try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
4807
        }
4808
    }
4809
}
4810
4811
/// You cannot dereference an opaque pointer, you have to cast it first.
4812
@test unsafe fn testOpaquePointerNoDereference() throws (testing::TestError) {
4813
    let mut testArena346 = testArena();
4814
    let testStorage346: 'test346 = &mut testArena346 in {
4815
        let mut a = testResolver(testStorage346);
4816
        let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = *o; }");
4817
        let err = try expectError(&result);
4818
        try expectErrorKind(&result, super::ErrorKind::OpaqueTypeDeref);
4819
    }
4820
}
4821
4822
/// Test that you can dereference after casting.
4823
@test unsafe fn testOpaquePointerDereferenceAfterCast() throws (testing::TestError) {
4824
    let mut testArena347 = testArena();
4825
    let testStorage347: 'test347 = &mut testArena347 in {
4826
        let mut a = testResolver(testStorage347);
4827
        let result = try resolveProgramStr(&mut a, "unsafe fn f() { let o: *opaque = undefined; let x = *(o as *i32); }");
4828
        try expectNoErrors(&result);
4829
    }
4830
}
4831
4832
/// You cannot do pointer arithmetic with an opaque pointer.
4833
@test unsafe fn testOpaquePointerNoArithmetic() throws (testing::TestError) {
4834
    {
4835
        let mut testArena348 = testArena();
4836
        let testStorage348: 'test348 = &mut testArena348 in {
4837
            let mut a = testResolver(testStorage348);
4838
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = o + 1; }");
4839
            let err = try expectError(&result);
4840
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
4841
        }
4842
    } {
4843
        let mut testArena349 = testArena();
4844
        let testStorage349: 'test349 = &mut testArena349 in {
4845
            let mut a = testResolver(testStorage349);
4846
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = 1 + o; }");
4847
            let err = try expectError(&result);
4848
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
4849
        }
4850
    } {
4851
        let mut testArena350 = testArena();
4852
        let testStorage350: 'test350 = &mut testArena350 in {
4853
            let mut a = testResolver(testStorage350);
4854
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = o - 1; }");
4855
            let err = try expectError(&result);
4856
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
4857
        }
4858
    } {
4859
        let mut testArena351 = testArena();
4860
        let testStorage351: 'test351 = &mut testArena351 in {
4861
            let mut a = testResolver(testStorage351);
4862
            let result = try resolveProgramStr(&mut a, "fn f(a: *i32) { let o: *opaque = a; let x = 1 - o; }");
4863
            let err = try expectError(&result);
4864
            try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
4865
        }
4866
    }
4867
}
4868
4869
// Wildcard import/reexport tests.
4870
4871
/// Test transitive re-export.
4872
@test unsafe fn testWildcardReexportTransitive() throws (testing::TestError) {
4873
    let mut testArena352 = testArena();
4874
    let testStorage352: 'test352 = &mut testArena352 in {
4875
        let mut a = testResolver(testStorage352);
4876
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4877
4878
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod a; export mod b;", &mut arena);
4879
        let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b; fn main() -> i32 { return b::helper() + b::MAX; }", &mut arena);
4880
        let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "mod c; export use c::*;", &mut arena);
4881
        let cId = try registerModule(&mut MODULE_GRAPH, bId, "c", "mod d; export use d::*; export fn helper() -> i32 { return 42; }", &mut arena);
4882
        let dId = try registerModule(&mut MODULE_GRAPH, cId, "d", "export constant MAX: i32 = 100;", &mut arena);
4883
4884
        let result = try resolveModuleTree(&mut a, rootId);
4885
        try expectNoErrors(&result);
4886
    }
4887
}
4888
4889
/// Test that wildcard import can access public symbols.
4890
@test unsafe fn testWildcardImportPublicOnly() throws (testing::TestError) {
4891
    let mut testArena353 = testArena();
4892
    let testStorage353: 'test353 = &mut testArena353 in {
4893
        let mut a = testResolver(testStorage353);
4894
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4895
4896
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod b; mod a;", &mut arena);
4897
        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);
4898
        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);
4899
4900
        let result = try resolveModuleTree(&mut a, rootId);
4901
        try expectNoErrors(&result);
4902
    }
4903
}
4904
4905
/// Test that wildcard import cannot access private symbols.
4906
@test unsafe fn testWildcardImportSkipsPrivate() throws (testing::TestError) {
4907
    let mut testArena354 = testArena();
4908
    let testStorage354: 'test354 = &mut testArena354 in {
4909
        let mut a = testResolver(testStorage354);
4910
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4911
4912
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod b; mod a;", &mut arena);
4913
        let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "export fn public() -> i32 { return 1; } fn private() -> i32 { return 2; }", &mut arena);
4914
        let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b::*; fn main() -> i32 { return private(); }", &mut arena);
4915
4916
        let result = try resolveModuleTree(&mut a, rootId);
4917
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
4918
    }
4919
}
4920
4921
/// Test that a constant array can use another constant as its length.
4922
@test unsafe fn testConstArrayWithConstLength() throws (testing::TestError) {
4923
    let mut testArena355 = testArena();
4924
    let testStorage355: 'test355 = &mut testArena355 in {
4925
        let mut a = testResolver(testStorage355);
4926
        let program = "constant LEN: u32 = 3; constant ARR: [i32; LEN] = [1, 2, 3];";
4927
        let result = try resolveProgramStr(&mut a, program);
4928
        try expectNoErrors(&result);
4929
4930
        // Verify the array constant has the correct type with length 3.
4931
        let arrStmt = try getBlockStmt(result.root, 1);
4932
        let sym = super::symbolFor(&a, arrStmt)
4933
            else throw testing::TestError::Failed;
4934
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
4935
            else throw testing::TestError::Failed;
4936
        try testing::expect(arrType.length == 3);
4937
    }
4938
}
4939
4940
/// Test that a record field can use a constant as its array length.
4941
@test unsafe fn testRecordFieldWithConstArrayLength() throws (testing::TestError) {
4942
    let mut testArena356 = testArena();
4943
    let testStorage356: 'test356 = &mut testArena356 in {
4944
        let mut a = testResolver(testStorage356);
4945
        let program = "constant SIZE: u32 = 4; record Buffer { data: [i32; SIZE], }";
4946
        let result = try resolveProgramStr(&mut a, program);
4947
        try expectNoErrors(&result);
4948
    }
4949
}
4950
4951
/// Test that a constant can have a record literal value (lazy record body resolution).
4952
@test unsafe fn testConstWithRecordLiteral() throws (testing::TestError) {
4953
    let mut testArena357 = testArena();
4954
    let testStorage357: 'test357 = &mut testArena357 in {
4955
        let mut a = testResolver(testStorage357);
4956
        let program = "record Point { x: i32, y: i32 } constant ORIGIN: Point = Point { x: 0, y: 0 };";
4957
        let result = try resolveProgramStr(&mut a, program);
4958
        try expectNoErrors(&result);
4959
    }
4960
}
4961
4962
/// Test that a constant can have a union variant value (lazy union body resolution).
4963
@test unsafe fn testConstWithUnionVariant() throws (testing::TestError) {
4964
    let mut testArena358 = testArena();
4965
    let testStorage358: 'test358 = &mut testArena358 in {
4966
        let mut a = testResolver(testStorage358);
4967
        let program = "union Color { Red, Green, Blue } constant DEFAULT: Color = Color::Red;";
4968
        let result = try resolveProgramStr(&mut a, program);
4969
        try expectNoErrors(&result);
4970
    }
4971
}
4972
4973
/// Test that record field types can reference imported types.
4974
///
4975
/// This tests that `use` statements are processed before record body resolution,
4976
/// allowing record fields to use types from imported modules.
4977
@test unsafe fn testRecordFieldUsesImportedType() throws (testing::TestError) {
4978
    let mut testArena359 = testArena();
4979
    let testStorage359: 'test359 = &mut testArena359 in {
4980
        let mut a = testResolver(testStorage359);
4981
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4982
4983
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod types; mod scanner;", &mut arena);
4984
        let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "export record Pool { count: u32 }", &mut arena);
4985
        let scannerId = try registerModule(&mut MODULE_GRAPH, rootId, "scanner", "use root::types; record Scanner { pool: *types::Pool }", &mut arena);
4986
4987
        let result = try resolveModuleTree(&mut a, rootId);
4988
        try expectNoErrors(&result);
4989
    }
4990
}
4991
4992
/// Test that imported constants can be used in array size expressions.
4993
///
4994
/// This tests that constant values are propagated through scope access expressions,
4995
/// enabling compile-time evaluation of array sizes using imported constants.
4996
@test unsafe fn testImportedConstantInArraySize() throws (testing::TestError) {
4997
    let mut testArena360 = testArena();
4998
    let testStorage360: 'test360 = &mut testArena360 in {
4999
        let mut a = testResolver(testStorage360);
5000
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
5001
5002
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
5003
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant SIZE: u32 = 8;", &mut arena);
5004
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; static BUFFER: [u8; consts::SIZE] = [0; consts::SIZE];", &mut arena);
5005
5006
        let result = try resolveModuleTree(&mut a, rootId);
5007
        try expectNoErrors(&result);
5008
    }
5009
}
5010
5011
/// Test that `if let case` binds payload variables in the then branch.
5012
///
5013
/// When using `if let case Union::Variant(x) = expr { ... }`, the variable `x` should
5014
/// be bound to the payload value within the then branch scope.
5015
@test unsafe fn testResolveIfCaseBindsPayload() throws (testing::TestError) {
5016
    let mut testArena361 = testArena();
5017
    let testStorage361: 'test361 = &mut testArena361 in {
5018
        let mut a = testResolver(testStorage361);
5019
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { if let case Opt::Some(x) = value { return x; } return 0; }";
5020
        let result = try resolveProgramStr(&mut a, program);
5021
        try expectNoErrors(&result);
5022
    }
5023
}
5024
5025
/// Test that `if let case` payload binding is scoped to the then branch.
5026
///
5027
/// The payload variable should not be accessible outside the then branch.
5028
@test unsafe fn testResolveIfCasePayloadScopeError() throws (testing::TestError) {
5029
    let mut testArena362 = testArena();
5030
    let testStorage362: 'test362 = &mut testArena362 in {
5031
        let mut a = testResolver(testStorage362);
5032
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { if let case Opt::Some(x) = value {} return x; }";
5033
        let result = try resolveProgramStr(&mut a, program);
5034
        let err = try expectError(&result);
5035
        let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
5036
            else throw testing::TestError::Failed;
5037
        try testing::expect(mem::eq(name, "x"));
5038
    }
5039
}
5040
5041
/// Test that `let case` binds payload variables in the current scope.
5042
///
5043
/// When using `let case Union::Variant(x) = expr else { ... }`, the variable `x`
5044
/// should be bound in the scope after the statement.
5045
@test unsafe fn testResolveLetCaseElseBindsPayload() throws (testing::TestError) {
5046
    let mut testArena363 = testArena();
5047
    let testStorage363: 'test363 = &mut testArena363 in {
5048
        let mut a = testResolver(testStorage363);
5049
        let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { let case Opt::Some(x) = value else panic; return x; }";
5050
        let result = try resolveProgramStr(&mut a, program);
5051
        try expectNoErrors(&result);
5052
    }
5053
}
5054
5055
/// Test that function pointers with identical signatures are assignable.
5056
///
5057
/// Two function types with the same parameters, return type, and throw list
5058
/// should be considered structurally equal, even if they are separate allocations.
5059
@test unsafe fn testFnPointerAssignability() throws (testing::TestError) {
5060
    let mut testArena364 = testArena();
5061
    let testStorage364: 'test364 = &mut testArena364 in {
5062
        let mut a = testResolver(testStorage364);
5063
        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);";
5064
        let result = try resolveProgramStr(&mut a, program);
5065
        try expectNoErrors(&result);
5066
    }
5067
}
5068
5069
/// Test that function pointers with different parameter types are not assignable.
5070
@test unsafe fn testFnPointerParamMismatch() throws (testing::TestError) {
5071
    let mut testArena365 = testArena();
5072
    let testStorage365: 'test365 = &mut testArena365 in {
5073
        let mut a = testResolver(testStorage365);
5074
        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);";
5075
        let result = try resolveProgramStr(&mut a, program);
5076
        let err = try expectError(&result);
5077
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5078
            else throw testing::TestError::Failed;
5079
    }
5080
}
5081
5082
/// Test that function pointers with different return types are not assignable.
5083
@test unsafe fn testFnPointerReturnMismatch() throws (testing::TestError) {
5084
    let mut testArena366 = testArena();
5085
    let testStorage366: 'test366 = &mut testArena366 in {
5086
        let mut a = testResolver(testStorage366);
5087
        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);";
5088
        let result = try resolveProgramStr(&mut a, program);
5089
        let err = try expectError(&result);
5090
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5091
            else throw testing::TestError::Failed;
5092
    }
5093
}
5094
5095
/// Test that named records use nominal typing, not structural.
5096
///
5097
/// Two different named record types with identical fields should NOT be
5098
/// assignable to each other, because they are distinct nominal types.
5099
@test unsafe fn testNamedRecordNominalTyping() throws (testing::TestError) {
5100
    let mut testArena367 = testArena();
5101
    let testStorage367: 'test367 = &mut testArena367 in {
5102
        let mut a = testResolver(testStorage367);
5103
        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);";
5104
        let result = try resolveProgramStr(&mut a, program);
5105
        let err = try expectError(&result);
5106
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5107
            else throw testing::TestError::Failed;
5108
    }
5109
}
5110
5111
/// Test that union variants with labeled record payloads can be constructed.
5112
@test unsafe fn testUnionVariantAnonRecordPayload() throws (testing::TestError) {
5113
    let mut testArena368 = testArena();
5114
    let testStorage368: 'test368 = &mut testArena368 in {
5115
        let mut a = testResolver(testStorage368);
5116
        let program = "union Event { Click { x: i32, y: i32 }, Key { code: u32 } } let e = Event::Click { x: 10, y: 20 };";
5117
        let result = try resolveProgramStr(&mut a, program);
5118
        try expectNoErrors(&result);
5119
    }
5120
}
5121
5122
/// Test that unlabeled record literals with positional fields work correctly.
5123
///
5124
/// When a record is declared with positional fields (e.g., `record R(i32, bool)`),
5125
/// the literal must use constructor call syntax with positional arguments.
5126
@test unsafe fn testResolveUnlabeledRecordLitValid() throws (testing::TestError) {
5127
    let mut testArena369 = testArena();
5128
    let testStorage369: 'test369 = &mut testArena369 in {
5129
        let mut a = testResolver(testStorage369);
5130
        let program = "record R(i32, bool); let r: R = R(1, true);";
5131
        let result = try resolveProgramStr(&mut a, program);
5132
        try expectNoErrors(&result);
5133
    }
5134
}
5135
5136
/// Test that using brace syntax for an unlabeled record causes an error.
5137
@test unsafe fn testResolveUnlabeledRecordLitStyleMismatch() throws (testing::TestError) {
5138
    let mut testArena370 = testArena();
5139
    let testStorage370: 'test370 = &mut testArena370 in {
5140
        let mut a = testResolver(testStorage370);
5141
        let program = "record R(i32); let r = R { x: 1 };";
5142
        let result = try resolveProgramStr(&mut a, program);
5143
        try expectErrorKind(&result, super::ErrorKind::RecordFieldStyleMismatch);
5144
    }
5145
}
5146
5147
/// Test that providing too many fields for an unlabeled record causes count mismatch.
5148
@test unsafe fn testResolveUnlabeledRecordLitTooManyFields() throws (testing::TestError) {
5149
    let mut testArena371 = testArena();
5150
    let testStorage371: 'test371 = &mut testArena371 in {
5151
        let mut a = testResolver(testStorage371);
5152
        let program = "record R(i32, bool); let r = R(1, true, 3);";
5153
        let result = try resolveProgramStr(&mut a, program);
5154
        let err = try expectError(&result);
5155
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5156
            else throw testing::TestError::Failed;
5157
    }
5158
}
5159
5160
/// Test that match pattern with wrong number of bindings causes count mismatch.
5161
@test unsafe fn testResolveMatchPatternWrongBindingCount() throws (testing::TestError) {
5162
    let mut testArena372 = testArena();
5163
    let testStorage372: 'test372 = &mut testArena372 in {
5164
        let mut a = testResolver(testStorage372);
5165
        let program = "union Event { Click { x: i32, y: i32 } } fn f(e: Event) { match e { case Event::Click(a) => {} } }";
5166
        let result = try resolveProgramStr(&mut a, program);
5167
        let err = try expectError(&result);
5168
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5169
            else throw testing::TestError::Failed;
5170
    }
5171
}
5172
5173
/// Test that shorthand field syntax works in record literals.
5174
/// `Point { x, y }` should be equivalent to `Point { x: x, y: y }`.
5175
@test unsafe fn testResolveRecordLiteralShorthand() throws (testing::TestError) {
5176
    let mut testArena373 = testArena();
5177
    let testStorage373: 'test373 = &mut testArena373 in {
5178
        let mut a = testResolver(testStorage373);
5179
        let program = "record Point { x: i32, y: i32 } fn f() { let x: i32 = 1; let y: i32 = 2; let p = Point { x, y }; }";
5180
        let result = try resolveProgramStr(&mut a, program);
5181
        try expectNoErrors(&result);
5182
    }
5183
}
5184
5185
/// Test shorthand field syntax with mixed explicit and shorthand fields.
5186
@test unsafe fn testResolveRecordLiteralMixedShorthand() throws (testing::TestError) {
5187
    let mut testArena374 = testArena();
5188
    let testStorage374: 'test374 = &mut testArena374 in {
5189
        let mut a = testResolver(testStorage374);
5190
        let program = "record Point { x: i32, y: i32 } fn f() { let x: i32 = 5; let p = Point { x, y: 10 }; }";
5191
        let result = try resolveProgramStr(&mut a, program);
5192
        try expectNoErrors(&result);
5193
    }
5194
}
5195
5196
/// Test record-style union variant patterns with shorthand syntax.
5197
@test unsafe fn testResolveMatchRecordPatternShorthand() throws (testing::TestError) {
5198
    let mut testArena375 = testArena();
5199
    let testStorage375: 'test375 = &mut testArena375 in {
5200
        let mut a = testResolver(testStorage375);
5201
        let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { width, height } => return width + height } }";
5202
        let result = try resolveProgramStr(&mut a, program);
5203
        try expectNoErrors(&result);
5204
    }
5205
}
5206
5207
/// Test record pattern with mixed shorthand and explicit labels.
5208
@test unsafe fn testResolveMatchRecordPatternMixed() throws (testing::TestError) {
5209
    let mut testArena376 = testArena();
5210
    let testStorage376: 'test376 = &mut testArena376 in {
5211
        let mut a = testResolver(testStorage376);
5212
        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 } }";
5213
        let result = try resolveProgramStr(&mut a, program);
5214
        try expectNoErrors(&result);
5215
    }
5216
}
5217
5218
/// Test record pattern with fields in reverse order.
5219
@test unsafe fn testResolveMatchRecordPatternReversed() throws (testing::TestError) {
5220
    let mut testArena377 = testArena();
5221
    let testStorage377: 'test377 = &mut testArena377 in {
5222
        let mut a = testResolver(testStorage377);
5223
        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 } }";
5224
        let result = try resolveProgramStr(&mut a, program);
5225
        try expectNoErrors(&result);
5226
    }
5227
}
5228
5229
/// Test record pattern with shorthand syntax in reverse order.
5230
/// Pattern `{ height, width }` binds all fields using shorthand, but not in definition order.
5231
@test unsafe fn testResolveMatchRecordPatternShorthandReversed() throws (testing::TestError) {
5232
    let mut testArena378 = testArena();
5233
    let testStorage378: 'test378 = &mut testArena378 in {
5234
        let mut a = testResolver(testStorage378);
5235
        let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { height, width } => return width + height } }";
5236
        let result = try resolveProgramStr(&mut a, program);
5237
        try expectNoErrors(&result);
5238
    }
5239
}
5240
5241
/// Test record pattern with `..` ignoring fields.
5242
@test unsafe fn testResolveMatchRecordPatternIgnoreRest() throws (testing::TestError) {
5243
    {
5244
        let mut testArena379 = testArena();
5245
        let testStorage379: 'test379 = &mut testArena379 in {
5246
            let mut a = testResolver(testStorage379);
5247
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { x, .. } => return x } }";
5248
            let result = try resolveProgramStr(&mut a, program);
5249
            try expectNoErrors(&result);
5250
        }
5251
    } {
5252
        let mut testArena380 = testArena();
5253
        let testStorage380: 'test380 = &mut testArena380 in {
5254
            let mut a = testResolver(testStorage380);
5255
            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 } }";
5256
            let result = try resolveProgramStr(&mut a, program);
5257
            try expectNoErrors(&result);
5258
        }
5259
    } {
5260
        let mut testArena381 = testArena();
5261
        let testStorage381: 'test381 = &mut testArena381 in {
5262
            let mut a = testResolver(testStorage381);
5263
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { z, .. } => return z } }";
5264
            let result = try resolveProgramStr(&mut a, program);
5265
            try expectNoErrors(&result);
5266
        }
5267
    } {
5268
        let mut testArena382 = testArena();
5269
        let testStorage382: 'test382 = &mut testArena382 in {
5270
            let mut a = testResolver(testStorage382);
5271
            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 } }";
5272
            let result = try resolveProgramStr(&mut a, program);
5273
            try expectNoErrors(&result);
5274
        }
5275
    } {
5276
        let mut testArena383 = testArena();
5277
        let testStorage383: 'test383 = &mut testArena383 in {
5278
            let mut a = testResolver(testStorage383);
5279
            let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> bool { match g { case G::Point { .. } => return true } }";
5280
            let result = try resolveProgramStr(&mut a, program);
5281
            try expectNoErrors(&result);
5282
        }
5283
    }
5284
}
5285
5286
/// Test standalone record pattern matching with unlabeled patterns.
5287
@test unsafe fn testResolveMatchStandaloneRecordUnlabeledPattern() throws (testing::TestError) {
5288
    let mut testArena384 = testArena();
5289
    let testStorage384: 'test384 = &mut testArena384 in {
5290
        let mut a = testResolver(testStorage384);
5291
        let program = "record S(i32); fn f(s: S) -> i32 { match s { case S(x) => return x, else => return 0 } }";
5292
        let result = try resolveProgramStr(&mut a, program);
5293
        try expectNoErrors(&result);
5294
    }
5295
}
5296
5297
/// Test standalone record pattern matching with labeled patterns.
5298
/// Pattern syntax: `T { x }` matches a named record and binds x to the field.
5299
@test unsafe fn testResolveMatchStandaloneRecordLabeledPattern() throws (testing::TestError) {
5300
    let mut testArena385 = testArena();
5301
    let testStorage385: 'test385 = &mut testArena385 in {
5302
        let mut a = testResolver(testStorage385);
5303
        let program = "record T { x: i32 } fn f(t: T) -> i32 { match t { case T { x } => return x, else => return 0 } }";
5304
        let result = try resolveProgramStr(&mut a, program);
5305
        try expectNoErrors(&result);
5306
    }
5307
}
5308
5309
/// Test standalone record pattern with multiple fields.
5310
/// Pattern syntax: `R(a, b)` matches an unlabeled record with multiple fields.
5311
@test unsafe fn testResolveMatchStandaloneRecordMultipleFields() throws (testing::TestError) {
5312
    let mut testArena386 = testArena();
5313
    let testStorage386: 'test386 = &mut testArena386 in {
5314
        let mut a = testResolver(testStorage386);
5315
        let program = "record R(bool, u8); fn f(r: R) -> u8 { match r { case R(_, x) => return x, else => return 0 } }";
5316
        let result = try resolveProgramStr(&mut a, program);
5317
        try expectNoErrors(&result);
5318
    }
5319
}
5320
5321
/// Test standalone record pattern with wrong field count.
5322
/// Pattern `S(x, y)` should fail for a single-field record.
5323
@test unsafe fn testResolveMatchStandaloneRecordWrongFieldCount() throws (testing::TestError) {
5324
    let mut testArena387 = testArena();
5325
    let testStorage387: 'test387 = &mut testArena387 in {
5326
        let mut a = testResolver(testStorage387);
5327
        let program = "record S(i32); fn f(s: S) -> i32 { match s { case S(x, y) => return x + y, else => return 0 } }";
5328
        let result = try resolveProgramStr(&mut a, program);
5329
        let err = try expectError(&result);
5330
        let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
5331
            else throw testing::TestError::Failed;
5332
    }
5333
}
5334
5335
/// Test array pattern matching with element bindings.
5336
/// Pattern syntax: `[x, y]` matches an array and binds elements.
5337
@test unsafe fn testResolveMatchArrayPattern() throws (testing::TestError) {
5338
    let mut testArena388 = testArena();
5339
    let testStorage388: 'test388 = &mut testArena388 in {
5340
        let mut a = testResolver(testStorage388);
5341
        let program = "fn f(arr: [i32; 2]) -> i32 { match arr { case [x, y] => return x + y } }";
5342
        let result = try resolveProgramStr(&mut a, program);
5343
        try expectNoErrors(&result);
5344
    }
5345
}
5346
5347
/// Test array pattern with placeholder elements.
5348
/// Pattern syntax: `[_, y]` ignores first element.
5349
@test unsafe fn testResolveMatchArrayPatternPlaceholder() throws (testing::TestError) {
5350
    let mut testArena389 = testArena();
5351
    let testStorage389: 'test389 = &mut testArena389 in {
5352
        let mut a = testResolver(testStorage389);
5353
        let program = "fn f(arr: [i32; 2]) -> i32 { match arr { case [_, y] => return y } }";
5354
        let result = try resolveProgramStr(&mut a, program);
5355
        try expectNoErrors(&result);
5356
    }
5357
}
5358
5359
/// Test identifier pattern that binds the whole value.
5360
/// Pattern syntax: `x` matches any value and binds it.
5361
@test unsafe fn testResolveMatchIdentPattern() throws (testing::TestError) {
5362
    let mut testArena390 = testArena();
5363
    let testStorage390: 'test390 = &mut testArena390 in {
5364
        let mut a = testResolver(testStorage390);
5365
        let program = "fn f(val: i32) -> i32 { match val { x => return x } }";
5366
        let result = try resolveProgramStr(&mut a, program);
5367
        try expectNoErrors(&result);
5368
    }
5369
}
5370
5371
/// Test numeric literal pattern matching.
5372
@test unsafe fn testResolveMatchNumericLiteralPattern() throws (testing::TestError) {
5373
    let mut testArena391 = testArena();
5374
    let testStorage391: 'test391 = &mut testArena391 in {
5375
        let mut a = testResolver(testStorage391);
5376
        let program = "fn f(val: i32) -> i32 { match val { case 42 => return 1, else => return 0 } }";
5377
        let result = try resolveProgramStr(&mut a, program);
5378
        try expectNoErrors(&result);
5379
    }
5380
}
5381
5382
/// Test string literal pattern matching.
5383
@test unsafe fn testResolveMatchStringLiteralPattern() throws (testing::TestError) {
5384
    let mut testArena392 = testArena();
5385
    let testStorage392: 'test392 = &mut testArena392 in {
5386
        let mut a = testResolver(testStorage392);
5387
        let program = "fn f(val: *[u8]) -> i32 { match val { case \"hello\" => return 1, else => return 0 } }";
5388
        let result = try resolveProgramStr(&mut a, program);
5389
        try expectNoErrors(&result);
5390
    }
5391
}
5392
5393
/// Test boolean literal pattern matching.
5394
@test unsafe fn testResolveMatchBoolLiteralPattern() throws (testing::TestError) {
5395
    let mut testArena393 = testArena();
5396
    let testStorage393: 'test393 = &mut testArena393 in {
5397
        let mut a = testResolver(testStorage393);
5398
        let program = "fn f(val: bool) -> i32 { match val { case true => return 1, case false => return 0 } }";
5399
        let result = try resolveProgramStr(&mut a, program);
5400
        try expectNoErrors(&result);
5401
    }
5402
}
5403
5404
/// Test @sliceOf with correct arguments succeeds.
5405
@test unsafe fn testResolveSliceOfCorrect() throws (testing::TestError) {
5406
    // Immutable pointer.
5407
    {
5408
        let mut testArena394 = testArena();
5409
        let testStorage394: 'test394 = &mut testArena394 in {
5410
            let mut a = testResolver(testStorage394);
5411
            let program = "unsafe fn f(ptr: *u8, len: u32) -> *[u8] { return @sliceOf(ptr, len); }";
5412
            let result = try resolveProgramStr(&mut a, program);
5413
            try expectNoErrors(&result);
5414
        }
5415
    }
5416
    // Mutable pointer produces mutable slice.
5417
    {
5418
        let mut testArena395 = testArena();
5419
        let testStorage395: 'test395 = &mut testArena395 in {
5420
            let mut a = testResolver(testStorage395);
5421
            let program = "unsafe fn f(ptr: *mut u8, len: u32) -> *mut [u8] { return @sliceOf(ptr, len); }";
5422
            let result = try resolveProgramStr(&mut a, program);
5423
            try expectNoErrors(&result);
5424
        }
5425
    }
5426
}
5427
5428
/// Test @sliceOf with wrong argument count produces an error.
5429
@test unsafe fn testResolveSliceOfWrongArgCount() throws (testing::TestError) {
5430
    // No arguments.
5431
    {
5432
        let mut testArena396 = testArena();
5433
        let testStorage396: 'test396 = &mut testArena396 in {
5434
            let mut a = testResolver(testStorage396);
5435
            let program = "fn f() -> *[u8] { return @sliceOf(); }";
5436
            let result = try resolveProgramStr(&mut a, program);
5437
            let err = try expectError(&result);
5438
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5439
                else throw testing::TestError::Failed;
5440
            try testing::expect(mismatch.expected == 2);
5441
            try testing::expect(mismatch.actual == 0);
5442
        }
5443
    }
5444
    // Too few arguments.
5445
    {
5446
        let mut testArena397 = testArena();
5447
        let testStorage397: 'test397 = &mut testArena397 in {
5448
            let mut a = testResolver(testStorage397);
5449
            let program = "fn f(ptr: *u8) -> *[u8] { return @sliceOf(ptr); }";
5450
            let result = try resolveProgramStr(&mut a, program);
5451
            let err = try expectError(&result);
5452
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5453
                else throw testing::TestError::Failed;
5454
            try testing::expect(mismatch.expected == 2);
5455
            try testing::expect(mismatch.actual == 1);
5456
        }
5457
    }
5458
    // Too many arguments.
5459
    {
5460
        let mut testArena398 = testArena();
5461
        let testStorage398: 'test398 = &mut testArena398 in {
5462
            let mut a = testResolver(testStorage398);
5463
            let program = "fn f(ptr: *u8, len: u32, cap: u32, extra: u32) -> *[u8] { return @sliceOf(ptr, len, cap, extra); }";
5464
            let result = try resolveProgramStr(&mut a, program);
5465
            let err = try expectError(&result);
5466
            let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
5467
                else throw testing::TestError::Failed;
5468
            try testing::expect(mismatch.expected == 2);
5469
            try testing::expect(mismatch.actual == 4);
5470
        }
5471
    }
5472
}
5473
5474
/// Test @sliceOf with wrong argument types produces errors.
5475
@test unsafe fn testResolveSliceOfWrongArgTypes() throws (testing::TestError) {
5476
    // Non-pointer first argument.
5477
    {
5478
        let mut testArena399 = testArena();
5479
        let testStorage399: 'test399 = &mut testArena399 in {
5480
            let mut a = testResolver(testStorage399);
5481
            let program = "fn f(val: u32, len: u32) -> *[u8] { return @sliceOf(val, len); }";
5482
            let result = try resolveProgramStr(&mut a, program);
5483
            let err = try expectError(&result);
5484
            let case super::ErrorKind::ExpectedPointer = err.kind
5485
                else throw testing::TestError::Failed;
5486
        }
5487
    }
5488
    // Array instead of pointer.
5489
    {
5490
        let mut testArena400 = testArena();
5491
        let testStorage400: 'test400 = &mut testArena400 in {
5492
            let mut a = testResolver(testStorage400);
5493
            let program = "fn f(arr: [u8; 4], len: u32) -> *[u8] { return @sliceOf(arr, len); }";
5494
            let result = try resolveProgramStr(&mut a, program);
5495
            let err = try expectError(&result);
5496
            let case super::ErrorKind::ExpectedPointer = err.kind
5497
                else throw testing::TestError::Failed;
5498
        }
5499
    }
5500
    // Non-numeric second argument.
5501
    {
5502
        let mut testArena401 = testArena();
5503
        let testStorage401: 'test401 = &mut testArena401 in {
5504
            let mut a = testResolver(testStorage401);
5505
            let program = "fn f(ptr: *u8, len: bool) -> *[u8] { return @sliceOf(ptr, len); }";
5506
            let result = try resolveProgramStr(&mut a, program);
5507
            let err = try expectError(&result);
5508
            let case super::ErrorKind::TypeMismatch(_) = err.kind
5509
                else throw testing::TestError::Failed;
5510
        }
5511
    }
5512
    // Pointer second argument.
5513
    {
5514
        let mut testArena402 = testArena();
5515
        let testStorage402: 'test402 = &mut testArena402 in {
5516
            let mut a = testResolver(testStorage402);
5517
            let program = "fn f(ptr: *u8, len: *u32) -> *[u8] { return @sliceOf(ptr, len); }";
5518
            let result = try resolveProgramStr(&mut a, program);
5519
            let err = try expectError(&result);
5520
            let case super::ErrorKind::TypeMismatch(_) = err.kind
5521
                else throw testing::TestError::Failed;
5522
        }
5523
    }
5524
}
5525
5526
/// Test @sliceOf with 3 arguments (ptr, len, cap) succeeds.
5527
@test unsafe fn testResolveSliceOfWithCap() throws (testing::TestError) {
5528
    {
5529
        let mut testArena403 = testArena();
5530
        let testStorage403: 'test403 = &mut testArena403 in {
5531
            let mut a = testResolver(testStorage403);
5532
            let program = "unsafe fn f(ptr: *u8, len: u32, cap: u32) -> *[u8] { return @sliceOf(ptr, len, cap); }";
5533
            let result = try resolveProgramStr(&mut a, program);
5534
            try expectNoErrors(&result);
5535
        }
5536
    }
5537
    // Mutable pointer produces mutable slice.
5538
    {
5539
        let mut testArena404 = testArena();
5540
        let testStorage404: 'test404 = &mut testArena404 in {
5541
            let mut a = testResolver(testStorage404);
5542
            let program = "unsafe fn f(ptr: *mut u8, len: u32, cap: u32) -> *mut [u8] { return @sliceOf(ptr, len, cap); }";
5543
            let result = try resolveProgramStr(&mut a, program);
5544
            try expectNoErrors(&result);
5545
        }
5546
    }
5547
}
5548
5549
/// Test @sliceOf with 3 arguments but wrong cap type.
5550
@test unsafe fn testResolveSliceOfCapWrongType() throws (testing::TestError) {
5551
    let mut testArena405 = testArena();
5552
    let testStorage405: 'test405 = &mut testArena405 in {
5553
        let mut a = testResolver(testStorage405);
5554
        let program = "fn f(ptr: *u8, len: u32, cap: bool) -> *[u8] { return @sliceOf(ptr, len, cap); }";
5555
        let result = try resolveProgramStr(&mut a, program);
5556
        let err = try expectError(&result);
5557
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5558
            else throw testing::TestError::Failed;
5559
    }
5560
}
5561
5562
/// Test .cap field access on slices resolves to u32.
5563
@test unsafe fn testResolveSliceCapField() throws (testing::TestError) {
5564
    let mut testArena406 = testArena();
5565
    let testStorage406: 'test406 = &mut testArena406 in {
5566
        let mut a = testResolver(testStorage406);
5567
        let program = "fn f(s: *[u8]) -> u32 { return s.cap; }";
5568
        let result = try resolveProgramStr(&mut a, program);
5569
        try expectNoErrors(&result);
5570
    }
5571
}
5572
5573
/// Test `.append()` on immutable slice produces an error.
5574
@test unsafe fn testResolveSliceAppendImmutable() throws (testing::TestError) {
5575
    let mut testArena407 = testArena();
5576
    let testStorage407: 'test407 = &mut testArena407 in {
5577
        let mut a = testResolver(testStorage407);
5578
        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); }";
5579
        let result = try resolveProgramStr(&mut a, program);
5580
        let err = try expectError(&result);
5581
        let case super::ErrorKind::ImmutableBinding = err.kind
5582
            else throw testing::TestError::Failed;
5583
    }
5584
}
5585
5586
/// Test `.append()` with wrong argument count produces an error.
5587
@test unsafe fn testResolveSliceAppendWrongArgCount() throws (testing::TestError) {
5588
    // Too few arguments.
5589
    {
5590
        let mut testArena408 = testArena();
5591
        let testStorage408: 'test408 = &mut testArena408 in {
5592
            let mut a = testResolver(testStorage408);
5593
            let program = "fn f(s: *mut [i32]) { s.append(1); }";
5594
            let result = try resolveProgramStr(&mut a, program);
5595
            let err = try expectError(&result);
5596
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
5597
                else throw testing::TestError::Failed;
5598
            try testing::expect(m.expected == 2);
5599
            try testing::expect(m.actual == 1);
5600
        }
5601
    }
5602
    // Too many arguments.
5603
    {
5604
        let mut testArena409 = testArena();
5605
        let testStorage409: 'test409 = &mut testArena409 in {
5606
            let mut a = testResolver(testStorage409);
5607
            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); }";
5608
            let result = try resolveProgramStr(&mut a, program);
5609
            let err = try expectError(&result);
5610
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
5611
                else throw testing::TestError::Failed;
5612
            try testing::expect(m.expected == 2);
5613
            try testing::expect(m.actual == 3);
5614
        }
5615
    }
5616
}
5617
5618
/// Test `.append()` with correct arguments succeeds.
5619
@test unsafe fn testResolveSliceAppendCorrect() throws (testing::TestError) {
5620
    let mut testArena410 = testArena();
5621
    let testStorage410: 'test410 = &mut testArena410 in {
5622
        let mut a = testResolver(testStorage410);
5623
        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); }";
5624
        let result = try resolveProgramStr(&mut a, program);
5625
        try expectNoErrors(&result);
5626
    }
5627
}
5628
5629
/// Test `.append()` with wrong element type produces an error.
5630
@test unsafe fn testResolveSliceAppendWrongElemType() throws (testing::TestError) {
5631
    let mut testArena411 = testArena();
5632
    let testStorage411: 'test411 = &mut testArena411 in {
5633
        let mut a = testResolver(testStorage411);
5634
        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); }";
5635
        let result = try resolveProgramStr(&mut a, program);
5636
        let err = try expectError(&result);
5637
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5638
            else throw testing::TestError::Failed;
5639
    }
5640
}
5641
5642
/// Test `.delete()` on immutable slice produces an error.
5643
@test unsafe fn testResolveSliceDeleteImmutable() throws (testing::TestError) {
5644
    let mut testArena412 = testArena();
5645
    let testStorage412: 'test412 = &mut testArena412 in {
5646
        let mut a = testResolver(testStorage412);
5647
        let program = "fn f(s: *[i32]) { s.delete(0); }";
5648
        let result = try resolveProgramStr(&mut a, program);
5649
        let err = try expectError(&result);
5650
        let case super::ErrorKind::ImmutableBinding = err.kind
5651
            else throw testing::TestError::Failed;
5652
    }
5653
}
5654
5655
/// Test `.delete()` with wrong argument count produces an error.
5656
@test unsafe fn testResolveSliceDeleteWrongArgCount() throws (testing::TestError) {
5657
    // No arguments.
5658
    {
5659
        let mut testArena413 = testArena();
5660
        let testStorage413: 'test413 = &mut testArena413 in {
5661
            let mut a = testResolver(testStorage413);
5662
            let program = "fn f(s: *mut [i32]) { s.delete(); }";
5663
            let result = try resolveProgramStr(&mut a, program);
5664
            let err = try expectError(&result);
5665
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
5666
                else throw testing::TestError::Failed;
5667
            try testing::expect(m.expected == 1);
5668
            try testing::expect(m.actual == 0);
5669
        }
5670
    }
5671
    // Too many arguments.
5672
    {
5673
        let mut testArena414 = testArena();
5674
        let testStorage414: 'test414 = &mut testArena414 in {
5675
            let mut a = testResolver(testStorage414);
5676
            let program = "fn f(s: *mut [i32]) { s.delete(0, 1); }";
5677
            let result = try resolveProgramStr(&mut a, program);
5678
            let err = try expectError(&result);
5679
            let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
5680
                else throw testing::TestError::Failed;
5681
            try testing::expect(m.expected == 1);
5682
            try testing::expect(m.actual == 2);
5683
        }
5684
    }
5685
}
5686
5687
/// Test `.delete()` with correct arguments succeeds.
5688
@test unsafe fn testResolveSliceDeleteCorrect() throws (testing::TestError) {
5689
    let mut testArena415 = testArena();
5690
    let testStorage415: 'test415 = &mut testArena415 in {
5691
        let mut a = testResolver(testStorage415);
5692
        let program = "fn f(s: *mut [i32]) { s.delete(0); }";
5693
        let result = try resolveProgramStr(&mut a, program);
5694
        try expectNoErrors(&result);
5695
    }
5696
}
5697
5698
/// Test `.delete()` with wrong argument type produces an error.
5699
@test unsafe fn testResolveSliceDeleteWrongArgType() throws (testing::TestError) {
5700
    let mut testArena416 = testArena();
5701
    let testStorage416: 'test416 = &mut testArena416 in {
5702
        let mut a = testResolver(testStorage416);
5703
        let program = "fn f(s: *mut [i32]) { s.delete(true); }";
5704
        let result = try resolveProgramStr(&mut a, program);
5705
        let err = try expectError(&result);
5706
        let case super::ErrorKind::TypeMismatch(_) = err.kind
5707
            else throw testing::TestError::Failed;
5708
    }
5709
}
5710
5711
/// Test `match &opt` produces immutable pointer bindings.
5712
@test unsafe fn testResolveMatchRefUnionBinding() throws (testing::TestError) {
5713
    let mut testArena417 = testArena();
5714
    let testStorage417: 'test417 = &mut testArena417 in {
5715
        let mut a = testResolver(testStorage417);
5716
        let program = "union Opt { Some(i32), None } fn f() { let opt = Opt::Some(42); match &opt { case Opt::Some(x) => { *x; } else => {} } }";
5717
        let result = try resolveProgramStr(&mut a, program);
5718
        try expectNoErrors(&result);
5719
5720
        let fnBlock = try getFnBody(&a, result.root, "f");
5721
        let matchNode = fnBlock.statements[1];
5722
        let case ast::NodeValue::Match(sw) = matchNode.value
5723
            else throw testing::TestError::Failed;
5724
        let caseNode = sw.prongs[0];
5725
5726
        let scope = super::scopeFor(&a, caseNode)
5727
            else throw testing::TestError::Failed;
5728
        let payloadSym = super::findSymbolInScope(scope, "x")
5729
            else throw testing::TestError::Failed;
5730
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
5731
            else throw testing::TestError::Failed;
5732
        let case super::Type::Pointer { class: types::PointerClass::Ref, target, mutable } = payloadValType
5733
            else throw testing::TestError::Failed;
5734
        try testing::expect(not mutable);
5735
        try testing::expect(*target == super::Type::I32);
5736
    }
5737
}
5738
5739
/// Test `match &mut opt` produces mutable pointer bindings.
5740
@test unsafe fn testResolveMatchMutRefUnionBinding() throws (testing::TestError) {
5741
    let mut testArena418 = testArena();
5742
    let testStorage418: 'test418 = &mut testArena418 in {
5743
        let mut a = testResolver(testStorage418);
5744
        let program = "union Opt { Some(i32), None } fn f() { let mut opt = Opt::Some(42); match &mut opt { case Opt::Some(x) => { *x; } else => {} } }";
5745
        let result = try resolveProgramStr(&mut a, program);
5746
        try expectNoErrors(&result);
5747
5748
        let fnBlock = try getFnBody(&a, result.root, "f");
5749
        let matchNode = fnBlock.statements[1];
5750
        let case ast::NodeValue::Match(sw) = matchNode.value
5751
            else throw testing::TestError::Failed;
5752
        let caseNode = sw.prongs[0];
5753
5754
        let scope = super::scopeFor(&a, caseNode)
5755
            else throw testing::TestError::Failed;
5756
        let payloadSym = super::findSymbolInScope(scope, "x")
5757
            else throw testing::TestError::Failed;
5758
        let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
5759
            else throw testing::TestError::Failed;
5760
        let case super::Type::Pointer { class: types::PointerClass::Ref, target, mutable } = payloadValType
5761
            else throw testing::TestError::Failed;
5762
        try testing::expect(mutable);
5763
        try testing::expect(*target == super::Type::I32);
5764
    }
5765
}
5766
5767
/// Non-constant integer widening must use an explicit cast.
5768
@test unsafe fn testResolveIntegerWideningRequiresCast() throws (testing::TestError) {
5769
    {
5770
        let mut testArena419 = testArena();
5771
        let testStorage419: 'test419 = &mut testArena419 in {
5772
            let mut a = testResolver(testStorage419);
5773
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = x;");
5774
            let err = try expectError(&result);
5775
            try expectTypeMismatch(err, super::Type::U32, super::Type::U8);
5776
        }
5777
    } {
5778
        let mut testArena420 = testArena();
5779
        let testStorage420: 'test420 = &mut testArena420 in {
5780
            let mut a = testResolver(testStorage420);
5781
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u16 = x;");
5782
            let err = try expectError(&result);
5783
            try expectTypeMismatch(err, super::Type::U16, super::Type::U8);
5784
        }
5785
    } {
5786
        let mut testArena421 = testArena();
5787
        let testStorage421: 'test421 = &mut testArena421 in {
5788
            let mut a = testResolver(testStorage421);
5789
            let result = try resolveBlockStr(&mut a, "let x: u16 = 1; let y: u32 = x;");
5790
            let err = try expectError(&result);
5791
            try expectTypeMismatch(err, super::Type::U32, super::Type::U16);
5792
        }
5793
    } {
5794
        let mut testArena422 = testArena();
5795
        let testStorage422: 'test422 = &mut testArena422 in {
5796
            let mut a = testResolver(testStorage422);
5797
            let result = try resolveBlockStr(&mut a, "let x: i8 = 1; let y: i32 = x;");
5798
            let err = try expectError(&result);
5799
            try expectTypeMismatch(err, super::Type::I32, super::Type::I8);
5800
        }
5801
    } {
5802
        let mut testArena423 = testArena();
5803
        let testStorage423: 'test423 = &mut testArena423 in {
5804
            let mut a = testResolver(testStorage423);
5805
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = x as u32;");
5806
            try expectNoErrors(&result);
5807
        }
5808
    } {
5809
        let mut testArena424 = testArena();
5810
        let testStorage424: 'test424 = &mut testArena424 in {
5811
            let mut a = testResolver(testStorage424);
5812
            let result = try resolveBlockStr(&mut a, "let x: i8 = 1; let y: i32 = x as i32;");
5813
            try expectNoErrors(&result);
5814
        }
5815
    }
5816
}
5817
5818
/// Mixed-width integer binary ops require an explicit cast.
5819
@test unsafe fn testResolveIntegerWideningBinOpRequiresCast() throws (testing::TestError) {
5820
    {
5821
        let mut testArena425 = testArena();
5822
        let testStorage425: 'test425 = &mut testArena425 in {
5823
            let mut a = testResolver(testStorage425);
5824
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = x | y;");
5825
            let err = try expectError(&result);
5826
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
5827
        }
5828
    } {
5829
        let mut testArena426 = testArena();
5830
        let testStorage426: 'test426 = &mut testArena426 in {
5831
            let mut a = testResolver(testStorage426);
5832
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 0xFF; let z: u32 = x & y;");
5833
            let err = try expectError(&result);
5834
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
5835
        }
5836
    } {
5837
        let mut testArena427 = testArena();
5838
        let testStorage427: 'test427 = &mut testArena427 in {
5839
            let mut a = testResolver(testStorage427);
5840
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = x + y;");
5841
            let err = try expectError(&result);
5842
            try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
5843
        }
5844
    } {
5845
        let mut testArena428 = testArena();
5846
        let testStorage428: 'test428 = &mut testArena428 in {
5847
            let mut a = testResolver(testStorage428);
5848
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u8 = x << 2;");
5849
            try expectNoErrors(&result);
5850
        }
5851
    } {
5852
        let mut testArena429 = testArena();
5853
        let testStorage429: 'test429 = &mut testArena429 in {
5854
            let mut a = testResolver(testStorage429);
5855
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = (x as u32) | y;");
5856
            try expectNoErrors(&result);
5857
        }
5858
    } {
5859
        let mut testArena430 = testArena();
5860
        let testStorage430: 'test430 = &mut testArena430 in {
5861
            let mut a = testResolver(testStorage430);
5862
            let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = (x as u32) + y;");
5863
            try expectNoErrors(&result);
5864
        }
5865
    }
5866
}
5867
5868
/// A mutable slice pointer should be assignable to an immutable slice pointer.
5869
@test unsafe fn testResolveMutSliceAssignableToImmutSlice() throws (testing::TestError) {
5870
    let mut testArena431 = testArena();
5871
    let testStorage431: 'test431 = &mut testArena431 in {
5872
        let mut a = testResolver(testStorage431);
5873
        let result = try resolveBlockStr(&mut a, "static arr: [i32; 3] = [1, 2, 3]; let p: *mut [i32] = &mut arr[..]; let q: *[i32] = p;");
5874
        try expectNoErrors(&result);
5875
    }
5876
}
5877
5878
/// Comprehensive tests for `as` cast expressions.
5879
@test unsafe fn testResolveAsCasts() throws (testing::TestError) {
5880
    { // Pointer to numeric.
5881
        let mut testArena432 = testArena();
5882
        let testStorage432: 'test432 = &mut testArena432 in {
5883
            let mut a = testResolver(testStorage432);
5884
            let result = try resolveBlockStr(&mut a, "static x: i32 = 0; let p = &x; p as u32;");
5885
            try expectNoErrors(&result);
5886
        }
5887
    } { // Function pointer to numeric.
5888
        let mut testArena433 = testArena();
5889
        let testStorage433: 'test433 = &mut testArena433 in {
5890
            let mut a = testResolver(testStorage433);
5891
            let result = try resolveProgramStr(&mut a, "fn run(f: fn()) { f as u32; }");
5892
            try expectNoErrors(&result);
5893
        }
5894
    } { // *u8 to *i32 (u8 to i32 is valid).
5895
        let mut testArena434 = testArena();
5896
        let testStorage434: 'test434 = &mut testArena434 in {
5897
            let mut a = testResolver(testStorage434);
5898
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: *u8 = undefined; p as *i32; }");
5899
            try expectNoErrors(&result);
5900
        }
5901
    } { // **u8 to **i32 (*u8 to *i32 is valid).
5902
        let mut testArena435 = testArena();
5903
        let testStorage435: 'test435 = &mut testArena435 in {
5904
            let mut a = testResolver(testStorage435);
5905
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: **u8 = undefined; p as **i32; }");
5906
            try expectNoErrors(&result);
5907
        }
5908
    }
5909
5910
    { // *[i32] to *[opaque].
5911
        let mut testArena436 = testArena();
5912
        let testStorage436: 'test436 = &mut testArena436 in {
5913
            let mut a = testResolver(testStorage436);
5914
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as *[opaque]; }");
5915
            try expectNoErrors(&result);
5916
        }
5917
    } { // *[opaque] to *[i32].
5918
        let mut testArena437 = testArena();
5919
        let testStorage437: 'test437 = &mut testArena437 in {
5920
            let mut a = testResolver(testStorage437);
5921
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[opaque] = undefined; s as *[i32]; }");
5922
            try expectNoErrors(&result);
5923
        }
5924
    }
5925
5926
    { // *[i32] to *[u8].
5927
        let mut testArena438 = testArena();
5928
        let testStorage438: 'test438 = &mut testArena438 in {
5929
            let mut a = testResolver(testStorage438);
5930
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[i32] = undefined; s as *[u8]; }");
5931
            try expectNoErrors(&result);
5932
        }
5933
    } { // *[record] to *[u8].
5934
        let mut testArena439 = testArena();
5935
        let testStorage439: 'test439 = &mut testArena439 in {
5936
            let mut a = testResolver(testStorage439);
5937
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } unsafe fn f(s: *[R]) { s as *[u8]; }");
5938
            try expectNoErrors(&result);
5939
        }
5940
    }
5941
5942
    { // *[u8] to *[i32].
5943
        let mut testArena440 = testArena();
5944
        let testStorage440: 'test440 = &mut testArena440 in {
5945
            let mut a = testResolver(testStorage440);
5946
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[u8] = undefined; s as *[i32]; }");
5947
            try expectNoErrors(&result);
5948
        }
5949
    } { // *[*u8] to *[*i32]
5950
        let mut testArena441 = testArena();
5951
        let testStorage441: 'test441 = &mut testArena441 in {
5952
            let mut a = testResolver(testStorage441);
5953
            let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[*u8] = undefined; s as *[*i32]; }");
5954
            try expectNoErrors(&result);
5955
        }
5956
    }
5957
5958
    { // Identity cast: *mut [i32] to *mut [i32].
5959
        let mut testArena442 = testArena();
5960
        let testStorage442: 'test442 = &mut testArena442 in {
5961
            let mut a = testResolver(testStorage442);
5962
            let result = try resolveProgramStr(&mut a, "fn run(s: *mut [i32]) { s as *mut [i32]; }");
5963
            try expectNoErrors(&result);
5964
        }
5965
    } { // Identity cast: *i32 to *i32.
5966
        let mut testArena443 = testArena();
5967
        let testStorage443: 'test443 = &mut testArena443 in {
5968
            let mut a = testResolver(testStorage443);
5969
            let result = try resolveProgramStr(&mut a, "fn run(p: *i32) { p as *i32; }");
5970
            try expectNoErrors(&result);
5971
        }
5972
    } { // Identity cast: i32 to i32.
5973
        let mut testArena444 = testArena();
5974
        let testStorage444: 'test444 = &mut testArena444 in {
5975
            let mut a = testResolver(testStorage444);
5976
            let result = try resolveBlockStr(&mut a, "let x: i32 = 0; x as i32;");
5977
            try expectNoErrors(&result);
5978
        }
5979
    }
5980
}
5981
5982
/// Tests for invalid `as` casts that should be rejected.
5983
@test unsafe fn testResolveAsCastsInvalid() throws (testing::TestError) {
5984
    { // Pointer to slice is invalid.
5985
        let mut testArena445 = testArena();
5986
        let testStorage445: 'test445 = &mut testArena445 in {
5987
            let mut a = testResolver(testStorage445);
5988
            let result = try resolveProgramStr(&mut a, "fn run(p: *i32) { p as *[i32]; }");
5989
            let err = try expectError(&result);
5990
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
5991
                else throw testing::TestError::Failed;
5992
        }
5993
    } { // Slice to pointer is invalid.
5994
        let mut testArena446 = testArena();
5995
        let testStorage446: 'test446 = &mut testArena446 in {
5996
            let mut a = testResolver(testStorage446);
5997
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as *i32; }");
5998
            let err = try expectError(&result);
5999
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6000
                else throw testing::TestError::Failed;
6001
        }
6002
    } { // *T to *i32 is invalid.
6003
        let mut testArena447 = testArena();
6004
        let testStorage447: 'test447 = &mut testArena447 in {
6005
            let mut a = testResolver(testStorage447);
6006
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(p: *R) { p as *i32; }");
6007
            let err = try expectError(&result);
6008
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6009
                else throw testing::TestError::Failed;
6010
        }
6011
    } { // *[T] to *[i32] is invalid.
6012
        let mut testArena448 = testArena();
6013
        let testStorage448: 'test448 = &mut testArena448 in {
6014
            let mut a = testResolver(testStorage448);
6015
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(s: *[R]) { s as *[i32]; }");
6016
            let err = try expectError(&result);
6017
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6018
                else throw testing::TestError::Failed;
6019
        }
6020
    } { // Slice to numeric is invalid.
6021
        let mut testArena449 = testArena();
6022
        let testStorage449: 'test449 = &mut testArena449 in {
6023
            let mut a = testResolver(testStorage449);
6024
            let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as u32; }");
6025
            let err = try expectError(&result);
6026
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6027
                else throw testing::TestError::Failed;
6028
        }
6029
    } { // *record to *u8 is invalid.
6030
        let mut testArena450 = testArena();
6031
        let testStorage450: 'test450 = &mut testArena450 in {
6032
            let mut a = testResolver(testStorage450);
6033
            let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(p: *R) { p as *u8; }");
6034
            let err = try expectError(&result);
6035
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
6036
                else throw testing::TestError::Failed;
6037
        }
6038
    }
6039
}
6040
6041
/// Test that catch binding is available in catch block scope.
6042
@test unsafe fn testResolveTryCatchBinding() throws (testing::TestError) {
6043
    {
6044
        let mut testArena451 = testArena();
6045
        let testStorage451: 'test451 = &mut testArena451 in {
6046
            let mut a = testResolver(testStorage451);
6047
            let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; } fn caller() -> u32 { return try fallible() catch err { return 0; }; }";
6048
            let result = try resolveProgramStr(&mut a, program);
6049
            try expectNoErrors(&result);
6050
        }
6051
    } {
6052
        let mut testArena452 = testArena();
6053
        let testStorage452: 'test452 = &mut testArena452 in {
6054
            let mut a = testResolver(testStorage452);
6055
            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; } }; }";
6056
            let result = try resolveProgramStr(&mut a, program);
6057
            try expectNoErrors(&result);
6058
        }
6059
    } {
6060
        let mut testArena453 = testArena();
6061
        let testStorage453: 'test453 = &mut testArena453 in {
6062
            let mut a = testResolver(testStorage453);
6063
            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; }; }";
6064
            let result = try resolveProgramStr(&mut a, program);
6065
            try expectNoErrors(&result);
6066
        }
6067
    } {
6068
        let mut testArena454 = testArena();
6069
        let testStorage454: 'test454 = &mut testArena454 in {
6070
            let mut a = testResolver(testStorage454);
6071
            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, } }; }";
6072
            let result = try resolveProgramStr(&mut a, program);
6073
            try expectNoErrors(&result);
6074
        }
6075
    }
6076
}
6077
6078
/// Test that duplicate union variant patterns are detected.
6079
@test unsafe fn testResolveMatchDuplicateUnionPattern() throws (testing::TestError) {
6080
    {
6081
        let mut testArena455 = testArena();
6082
        let testStorage455: 'test455 = &mut testArena455 in {
6083
            let mut a = testResolver(testStorage455);
6084
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::A => {}, else => {} } }";
6085
            let result = try resolveProgramStr(&mut a, program);
6086
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6087
        }
6088
    } {
6089
        // No duplicate: distinct variants are fine.
6090
        let mut testArena456 = testArena();
6091
        let testStorage456: 'test456 = &mut testArena456 in {
6092
            let mut a = testResolver(testStorage456);
6093
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::B => {} } }";
6094
            let result = try resolveProgramStr(&mut a, program);
6095
            try expectNoErrors(&result);
6096
        }
6097
    }
6098
}
6099
6100
/// Test that duplicate bool patterns are detected.
6101
@test unsafe fn testResolveMatchDuplicateBoolPattern() throws (testing::TestError) {
6102
    {
6103
        let mut testArena457 = testArena();
6104
        let testStorage457: 'test457 = &mut testArena457 in {
6105
            let mut a = testResolver(testStorage457);
6106
            let program = "fn f(x: bool) { match x { case true => {}, case true => {}, else => {} } }";
6107
            let result = try resolveProgramStr(&mut a, program);
6108
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6109
        }
6110
    } {
6111
        let mut testArena458 = testArena();
6112
        let testStorage458: 'test458 = &mut testArena458 in {
6113
            let mut a = testResolver(testStorage458);
6114
            let program = "fn f(x: bool) { match x { case false => {}, case false => {}, else => {} } }";
6115
            let result = try resolveProgramStr(&mut a, program);
6116
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6117
        }
6118
    }
6119
}
6120
6121
/// Test that duplicate nil patterns in optional match are detected.
6122
@test unsafe fn testResolveMatchDuplicateOptionalPattern() throws (testing::TestError) {
6123
    {
6124
        let mut testArena459 = testArena();
6125
        let testStorage459: 'test459 = &mut testArena459 in {
6126
            let mut a = testResolver(testStorage459);
6127
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {}, case nil => {} } }";
6128
            let result = try resolveProgramStr(&mut a, program);
6129
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6130
        }
6131
    } {
6132
        // Duplicate value binding.
6133
        let mut testArena460 = testArena();
6134
        let testStorage460: 'test460 = &mut testArena460 in {
6135
            let mut a = testResolver(testStorage460);
6136
            let program = "fn f(opt: ?i32) { match opt { v => {}, w => {}, case nil => {} } }";
6137
            let result = try resolveProgramStr(&mut a, program);
6138
            try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
6139
        }
6140
    }
6141
}
6142
6143
/// Test that guarded match arms are not considered duplicates.
6144
@test unsafe fn testResolveMatchGuardedNotDuplicate() throws (testing::TestError) {
6145
    {
6146
        // Guarded union variant followed by same variant is fine.
6147
        let mut testArena461 = testArena();
6148
        let testStorage461: 'test461 = &mut testArena461 in {
6149
            let mut a = testResolver(testStorage461);
6150
            let program = "union U { A, B } fn f(u: U) { match u { case U::A if true => {}, case U::A => {}, case U::B => {} } }";
6151
            let result = try resolveProgramStr(&mut a, program);
6152
            try expectNoErrors(&result);
6153
        }
6154
    } {
6155
        // Guarded bool pattern followed by same bool is fine.
6156
        let mut testArena462 = testArena();
6157
        let testStorage462: 'test462 = &mut testArena462 in {
6158
            let mut a = testResolver(testStorage462);
6159
            let program = "fn f(x: bool) { match x { case true if true => {}, case true => {}, case false => {} } }";
6160
            let result = try resolveProgramStr(&mut a, program);
6161
            try expectNoErrors(&result);
6162
        }
6163
    } {
6164
        // Guarded nil pattern followed by nil is fine.
6165
        let mut testArena463 = testArena();
6166
        let testStorage463: 'test463 = &mut testArena463 in {
6167
            let mut a = testResolver(testStorage463);
6168
            let program = "fn f(opt: ?i32) { match opt { case nil if true => {}, case nil => {}, v => {} } }";
6169
            let result = try resolveProgramStr(&mut a, program);
6170
            try expectNoErrors(&result);
6171
        }
6172
    } {
6173
        // Guarded value binding followed by another binding is fine.
6174
        let mut testArena464 = testArena();
6175
        let testStorage464: 'test464 = &mut testArena464 in {
6176
            let mut a = testResolver(testStorage464);
6177
            let program = "fn f(opt: ?i32) { match opt { v if true => {}, w => {}, case nil => {} } }";
6178
            let result = try resolveProgramStr(&mut a, program);
6179
            try expectNoErrors(&result);
6180
        }
6181
    }
6182
}
6183
6184
/// Test that unreachable else is detected when all union variants are covered.
6185
@test unsafe fn testResolveMatchUnreachableElseUnion() throws (testing::TestError) {
6186
    {
6187
        let mut testArena465 = testArena();
6188
        let testStorage465: 'test465 = &mut testArena465 in {
6189
            let mut a = testResolver(testStorage465);
6190
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::B => {}, else => {} } }";
6191
            let result = try resolveProgramStr(&mut a, program);
6192
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6193
        }
6194
    } {
6195
        // Partial coverage with else is fine.
6196
        let mut testArena466 = testArena();
6197
        let testStorage466: 'test466 = &mut testArena466 in {
6198
            let mut a = testResolver(testStorage466);
6199
            let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, else => {} } }";
6200
            let result = try resolveProgramStr(&mut a, program);
6201
            try expectNoErrors(&result);
6202
        }
6203
    }
6204
}
6205
6206
/// Test that unreachable else is detected when both bool cases are covered.
6207
@test unsafe fn testResolveMatchUnreachableElseBool() throws (testing::TestError) {
6208
    {
6209
        let mut testArena467 = testArena();
6210
        let testStorage467: 'test467 = &mut testArena467 in {
6211
            let mut a = testResolver(testStorage467);
6212
            let program = "fn f(x: bool) { match x { case true => {}, case false => {}, else => {} } }";
6213
            let result = try resolveProgramStr(&mut a, program);
6214
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6215
        }
6216
    } {
6217
        // Only one case with else is fine.
6218
        let mut testArena468 = testArena();
6219
        let testStorage468: 'test468 = &mut testArena468 in {
6220
            let mut a = testResolver(testStorage468);
6221
            let program = "fn f(x: bool) { match x { case true => {}, else => {} } }";
6222
            let result = try resolveProgramStr(&mut a, program);
6223
            try expectNoErrors(&result);
6224
        }
6225
    }
6226
}
6227
6228
/// Test that unreachable else is detected when both optional cases are covered.
6229
@test unsafe fn testResolveMatchUnreachableElseOptional() throws (testing::TestError) {
6230
    {
6231
        let mut testArena469 = testArena();
6232
        let testStorage469: 'test469 = &mut testArena469 in {
6233
            let mut a = testResolver(testStorage469);
6234
            let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {}, else => {} } }";
6235
            let result = try resolveProgramStr(&mut a, program);
6236
            try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
6237
        }
6238
    } {
6239
        // Only value binding with else is fine.
6240
        let mut testArena470 = testArena();
6241
        let testStorage470: 'test470 = &mut testArena470 in {
6242
            let mut a = testResolver(testStorage470);
6243
            let program = "fn f(opt: ?i32) { match opt { v => {}, else => {} } }";
6244
            let result = try resolveProgramStr(&mut a, program);
6245
            try expectNoErrors(&result);
6246
        }
6247
    }
6248
}
6249
6250
// --- Multi-error typed catch tests ---
6251
6252
@test unsafe fn testTypedCatchExhaustive() throws (testing::TestError) {
6253
    let mut testArena471 = testArena();
6254
    let testStorage471: 'test471 = &mut testArena471 in {
6255
        let mut a = testResolver(testStorage471);
6256
        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; }; }";
6257
        let result = try resolveProgramStr(&mut a, program);
6258
        try expectNoErrors(&result);
6259
    }
6260
}
6261
6262
@test unsafe fn testTypedCatchNonExhaustive() throws (testing::TestError) {
6263
    let mut testArena472 = testArena();
6264
    let testStorage472: 'test472 = &mut testArena472 in {
6265
        let mut a = testResolver(testStorage472);
6266
        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; }; }";
6267
        let result = try resolveProgramStr(&mut a, program);
6268
        try expectErrorKind(&result, super::ErrorKind::TryCatchNonExhaustive);
6269
    }
6270
}
6271
6272
@test unsafe fn testTypedCatchDuplicate() throws (testing::TestError) {
6273
    let mut testArena473 = testArena();
6274
    let testStorage473: 'test473 = &mut testArena473 in {
6275
        let mut a = testResolver(testStorage473);
6276
        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; }; }";
6277
        let result = try resolveProgramStr(&mut a, program);
6278
        try expectErrorKind(&result, super::ErrorKind::TryCatchDuplicateType);
6279
    }
6280
}
6281
6282
@test unsafe fn testTypedCatchWithCatchAll() throws (testing::TestError) {
6283
    let mut testArena474 = testArena();
6284
    let testStorage474: 'test474 = &mut testArena474 in {
6285
        let mut a = testResolver(testStorage474);
6286
        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; }; }";
6287
        let result = try resolveProgramStr(&mut a, program);
6288
        try expectNoErrors(&result);
6289
    }
6290
}
6291
6292
@test unsafe fn testTypedCatchWrongType() throws (testing::TestError) {
6293
    let mut testArena475 = testArena();
6294
    let testStorage475: 'test475 = &mut testArena475 in {
6295
        let mut a = testResolver(testStorage475);
6296
        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; }; }";
6297
        let result = try resolveProgramStr(&mut a, program);
6298
        try expectErrorKind(&result, super::ErrorKind::TryIncompatibleError);
6299
    }
6300
}
6301
6302
@test unsafe fn testInferredCatchMultiError() throws (testing::TestError) {
6303
    let mut testArena476 = testArena();
6304
    let testStorage476: 'test476 = &mut testArena476 in {
6305
        let mut a = testResolver(testStorage476);
6306
        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; }; }";
6307
        let result = try resolveProgramStr(&mut a, program);
6308
        try expectErrorKind(&result, super::ErrorKind::TryCatchMultiError);
6309
    }
6310
}
6311
6312
@test unsafe fn testResolveInstanceMissingMethod() throws (testing::TestError) {
6313
    let mut testArena477 = testArena();
6314
    let testStorage477: 'test477 = &mut testArena477 in {
6315
        let mut a = testResolver(testStorage477);
6316
        let program = "trait S { fn (*S) f() -> i32; } record R { x: i32 } instance S for R {}";
6317
        let result = try resolveProgramStr(&mut a, program);
6318
        try expectErrorKind(&result, super::ErrorKind::MissingTraitMethod("f"));
6319
    }
6320
}
6321
6322
@test unsafe fn testResolveInstanceUnknownMethod() throws (testing::TestError) {
6323
    let mut testArena478 = testArena();
6324
    let testStorage478: 'test478 = &mut testArena478 in {
6325
        let mut a = testResolver(testStorage478);
6326
        let program = "trait S { fn (*S) f() -> i32; } record R { x: i32 } instance S for R { fn (self: *R) x() -> i32 { return 0; } }";
6327
        let result = try resolveProgramStr(&mut a, program);
6328
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
6329
    }
6330
}
6331
6332
@test unsafe fn testResolveTraitDuplicateMethodRejected() throws (testing::TestError) {
6333
    let mut testArena479 = testArena();
6334
    let testStorage479: 'test479 = &mut testArena479 in {
6335
        let mut a = testResolver(testStorage479);
6336
        let program = "trait Adder { fn (*mut Adder) add(n: i32) -> i32; fn (*mut Adder) add(n: i32) -> i32; }";
6337
        let result = try resolveProgramStr(&mut a, program);
6338
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("add"));
6339
    }
6340
}
6341
6342
@test unsafe fn testResolveInstanceReceiverTypeMustMatchTarget() throws (testing::TestError) {
6343
    let mut testArena480 = testArena();
6344
    let testStorage480: 'test480 = &mut testArena480 in {
6345
        let mut a = testResolver(testStorage480);
6346
        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; } }";
6347
        let result = try resolveProgramStr(&mut a, program);
6348
        let err = try expectError(&result);
6349
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6350
            else throw testing::TestError::Failed;
6351
    }
6352
}
6353
6354
@test unsafe fn testResolveTraitMethodThrowsRequireTry() throws (testing::TestError) {
6355
    let mut testArena481 = testArena();
6356
    let testStorage481: 'test481 = &mut testArena481 in {
6357
        let mut a = testResolver(testStorage481);
6358
        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); }";
6359
        let result = try resolveProgramStr(&mut a, program);
6360
        try expectErrorKind(&result, super::ErrorKind::MissingTry);
6361
    }
6362
}
6363
6364
/// Trait declares immutable receiver (*Trait) but instance uses mutable (*mut Type).
6365
/// The instance method could mutate through what was originally an immutable pointer.
6366
@test unsafe fn testResolveInstanceMutReceiverOnImmutableTrait() throws (testing::TestError) {
6367
    let mut testArena482 = testArena();
6368
    let testStorage482: 'test482 = &mut testArena482 in {
6369
        let mut a = testResolver(testStorage482);
6370
        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; } }";
6371
        let result = try resolveProgramStr(&mut a, program);
6372
        // Should reject: instance declares *mut receiver but trait only requires immutable.
6373
        try expectErrorKind(&result, super::ErrorKind::ReceiverMutabilityMismatch);
6374
    }
6375
}
6376
6377
/// Instance method declares different parameter types than the trait.
6378
/// The resolver should reject the mismatch rather than silently using the trait's types.
6379
@test unsafe fn testResolveInstanceParamTypeMismatch() throws (testing::TestError) {
6380
    let mut testArena483 = testArena();
6381
    let testStorage483: 'test483 = &mut testArena483 in {
6382
        let mut a = testResolver(testStorage483);
6383
        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; } }";
6384
        let result = try resolveProgramStr(&mut a, program);
6385
        // Should reject: instance param type u8 doesn't match trait param type i32.
6386
        let err = try expectError(&result);
6387
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6388
            else throw testing::TestError::Failed;
6389
    }
6390
}
6391
6392
/// Duplicate instance declarations for the same (trait, type) pair should be rejected.
6393
@test unsafe fn testResolveInstanceDuplicateRejected() throws (testing::TestError) {
6394
    let mut testArena484 = testArena();
6395
    let testStorage484: 'test484 = &mut testArena484 in {
6396
        let mut a = testResolver(testStorage484);
6397
        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; } }";
6398
        let result = try resolveProgramStr(&mut a, program);
6399
        // Should reject: duplicate instance for (Adder, Counter).
6400
        try expectErrorKind(&result, super::ErrorKind::DuplicateInstance);
6401
    }
6402
}
6403
6404
/// Trait method receiver must point to the declaring trait type.
6405
@test unsafe fn testResolveTraitReceiverMismatch() throws (testing::TestError) {
6406
    let mut testArena485 = testArena();
6407
    let testStorage485: 'test485 = &mut testArena485 in {
6408
        let mut a = testResolver(testStorage485);
6409
        let program = "record Other { x: i32 } trait Foo { fn (*mut Other) bar() -> i32; }";
6410
        let result = try resolveProgramStr(&mut a, program);
6411
        try expectErrorKind(&result, super::ErrorKind::TraitReceiverMismatch);
6412
    }
6413
}
6414
6415
/// Using a trait name as a value expression should be rejected.
6416
@test unsafe fn testResolveTraitNameAsValueRejected() throws (testing::TestError) {
6417
    let mut testArena486 = testArena();
6418
    let testStorage486: 'test486 = &mut testArena486 in {
6419
        let mut a = testResolver(testStorage486);
6420
        let program = "trait Foo { fn (*Foo) bar() -> i32; } fn test() -> i32 { let x = Foo; return 0; }";
6421
        let result = try resolveProgramStr(&mut a, program);
6422
        try expectErrorKind(&result, super::ErrorKind::UnexpectedTraitName);
6423
    }
6424
}
6425
6426
/// Cross-module trait: coerce to trait object and dispatch from a different module.
6427
@test unsafe fn testResolveTraitCrossModuleCoercion() throws (testing::TestError) {
6428
    let mut testArena487 = testArena();
6429
    let testStorage487: 'test487 = &mut testArena487 in {
6430
        let mut a = testResolver(testStorage487);
6431
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6432
6433
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; mod app;", &mut arena);
6434
        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);
6435
        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);
6436
6437
        let result = try resolveModuleTree(&mut a, rootId);
6438
        try expectNoErrors(&result);
6439
    }
6440
}
6441
6442
/// Instance in a different module from trait and type.
6443
@test unsafe fn testResolveInstanceCrossModule() throws (testing::TestError) {
6444
    let mut testArena488 = testArena();
6445
    let testStorage488: 'test488 = &mut testArena488 in {
6446
        let mut a = testResolver(testStorage488);
6447
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6448
6449
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; export mod impls; mod app;", &mut arena);
6450
        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);
6451
        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);
6452
        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);
6453
6454
        let result = try resolveModuleTree(&mut a, rootId);
6455
        try expectNoErrors(&result);
6456
    }
6457
}
6458
6459
/// Calling a mutable-receiver trait method on an immutable trait object
6460
/// must be rejected.
6461
@test unsafe fn testResolveTraitMutMethodOnImmutableObject() throws (testing::TestError) {
6462
    let mut testArena489 = testArena();
6463
    let testStorage489: 'test489 = &mut testArena489 in {
6464
        let mut a = testResolver(testStorage489);
6465
        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); }";
6466
        let result = try resolveProgramStr(&mut a, program);
6467
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
6468
    }
6469
}
6470
6471
/// Immutable methods on an immutable trait object should be accepted.
6472
@test unsafe fn testResolveTraitImmutableMethodOnImmutableObject() throws (testing::TestError) {
6473
    let mut testArena490 = testArena();
6474
    let testStorage490: 'test490 = &mut testArena490 in {
6475
        let mut a = testResolver(testStorage490);
6476
        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(); }";
6477
        let result = try resolveProgramStr(&mut a, program);
6478
        try expectNoErrors(&result);
6479
    }
6480
}
6481
6482
/// Both mutable and immutable methods on a mutable trait object should work.
6483
@test unsafe fn testResolveTraitMixedMethodsOnMutableObject() throws (testing::TestError) {
6484
    let mut testArena491 = testArena();
6485
    let testStorage491: 'test491 = &mut testArena491 in {
6486
        let mut a = testResolver(testStorage491);
6487
        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(); }";
6488
        let result = try resolveProgramStr(&mut a, program);
6489
        try expectNoErrors(&result);
6490
    }
6491
}
6492
6493
/// Instance method body type must match the trait return type.
6494
/// The trait declares `-> i32` but the body returns `bool`.
6495
@test unsafe fn testResolveInstanceReturnTypeMismatch() throws (testing::TestError) {
6496
    let mut testArena492 = testArena();
6497
    let testStorage492: 'test492 = &mut testArena492 in {
6498
        let mut a = testResolver(testStorage492);
6499
        let program = "record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() -> bool { return true; } }";
6500
        let result = try resolveProgramStr(&mut a, program);
6501
        let err = try expectError(&result);
6502
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6503
            else throw testing::TestError::Failed;
6504
    }
6505
}
6506
6507
/// Diamond supertrait inheritance: traits B and C both extend A.
6508
/// Declaring them independently should work fine.
6509
@test unsafe fn testResolveTraitDiamondSupertrait() throws (testing::TestError) {
6510
    let mut testArena493 = testArena();
6511
    let testStorage493: 'test493 = &mut testArena493 in {
6512
        let mut a = testResolver(testStorage493);
6513
        let program = "trait A { fn (*A) f() -> i32; } trait B: A { fn (*B) g() -> i32; } trait C: A { fn (*C) h() -> i32; }";
6514
        let result = try resolveProgramStr(&mut a, program);
6515
        try expectNoErrors(&result);
6516
    }
6517
}
6518
6519
/// Diamond supertrait with a combined trait that would cause duplicate
6520
/// method names should be detected.
6521
@test unsafe fn testResolveTraitDiamondDuplicateMethod() throws (testing::TestError) {
6522
    let mut testArena494 = testArena();
6523
    let testStorage494: 'test494 = &mut testArena494 in {
6524
        let mut a = testResolver(testStorage494);
6525
        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; }";
6526
        let result = try resolveProgramStr(&mut a, program);
6527
        // B inherits `f` from A, C inherits `f` from A. D: B + C sees duplicate `f`.
6528
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("f"));
6529
    }
6530
}
6531
6532
/// Supertrait instance must exist when declaring a combined trait instance.
6533
@test unsafe fn testResolveInstanceMissingSupertraitInstance() throws (testing::TestError) {
6534
    let mut testArena495 = testArena();
6535
    let testStorage495: 'test495 = &mut testArena495 in {
6536
        let mut a = testResolver(testStorage495);
6537
        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; } }";
6538
        let result = try resolveProgramStr(&mut a, program);
6539
        try expectErrorKind(&result, super::ErrorKind::MissingSupertraitInstance("Base"));
6540
    }
6541
}
6542
6543
/// Instance method omits return type when the trait declares `-> i32`.
6544
/// This is rejected -- the return type must be stated explicitly.
6545
@test unsafe fn testResolveInstanceReturnTypeOmitted() throws (testing::TestError) {
6546
    let mut testArena496 = testArena();
6547
    let testStorage496: 'test496 = &mut testArena496 in {
6548
        let mut a = testResolver(testStorage496);
6549
        let program = "record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() { } }";
6550
        let result = try resolveProgramStr(&mut a, program);
6551
        let err = try expectError(&result);
6552
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6553
            else throw testing::TestError::Failed;
6554
    }
6555
}
6556
6557
/// Instance method declares throws but the trait method does not throw.
6558
@test unsafe fn testResolveInstanceThrowsMismatchExtra() throws (testing::TestError) {
6559
    let mut testArena497 = testArena();
6560
    let testStorage497: 'test497 = &mut testArena497 in {
6561
        let mut a = testResolver(testStorage497);
6562
        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; } }";
6563
        let result = try resolveProgramStr(&mut a, program);
6564
        let err = try expectError(&result);
6565
        let case super::ErrorKind::FnThrowCountMismatch(_) = err.kind
6566
            else throw testing::TestError::Failed;
6567
    }
6568
}
6569
6570
/// Instance method declares a different throws type than the trait.
6571
@test unsafe fn testResolveInstanceThrowsMismatchWrongType() throws (testing::TestError) {
6572
    let mut testArena498 = testArena();
6573
    let testStorage498: 'test498 = &mut testArena498 in {
6574
        let mut a = testResolver(testStorage498);
6575
        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; } }";
6576
        let result = try resolveProgramStr(&mut a, program);
6577
        let err = try expectError(&result);
6578
        let case super::ErrorKind::TypeMismatch(_) = err.kind
6579
            else throw testing::TestError::Failed;
6580
    }
6581
}
6582
6583
/// Instance method omits throws clause when trait declares throws.
6584
/// This is rejected -- the throws clause must match exactly.
6585
@test unsafe fn testResolveInstanceThrowsOmitted() throws (testing::TestError) {
6586
    let mut testArena499 = testArena();
6587
    let testStorage499: 'test499 = &mut testArena499 in {
6588
        let mut a = testResolver(testStorage499);
6589
        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; } }";
6590
        let result = try resolveProgramStr(&mut a, program);
6591
        let err = try expectError(&result);
6592
        let case super::ErrorKind::FnThrowCountMismatch(_) = err.kind
6593
            else throw testing::TestError::Failed;
6594
    }
6595
}
6596
6597
/// Instance method correctly matches the trait's throws clause.
6598
@test unsafe fn testResolveInstanceThrowsMatch() throws (testing::TestError) {
6599
    let mut testArena500 = testArena();
6600
    let testStorage500: 'test500 = &mut testArena500 in {
6601
        let mut a = testResolver(testStorage500);
6602
        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; } }";
6603
        let result = try resolveProgramStr(&mut a, program);
6604
        try expectNoErrors(&result);
6605
    }
6606
}
6607
6608
// Constant expression folding tests //////////////////////////////////////////
6609
6610
/// Resolve a program and verify that the constant at the given statement index
6611
/// has the expected integer magnitude.
6612
unsafe fn expectConstFold(program: *[u8], stmtIdx: u32, expected: u64)
6613
    throws (testing::TestError)
6614
{
6615
    let mut testArena501 = testArena();
6616
    let testStorage501: 'test501 = &mut testArena501 in {
6617
        let mut a = testResolver(testStorage501);
6618
        let result = try resolveProgramStr(&mut a, program);
6619
        try expectNoErrors(&result);
6620
6621
        let stmt = try getBlockStmt(result.root, stmtIdx);
6622
        let sym = super::symbolFor(&a, stmt)
6623
            else throw testing::TestError::Failed;
6624
        let case super::SymbolData::Constant { value, .. } = sym.data
6625
            else throw testing::TestError::Failed;
6626
        let val = value else throw testing::TestError::Failed;
6627
        let case super::ConstValue::Int(intVal) = val
6628
            else throw testing::TestError::Failed;
6629
        try testing::expect(intVal.magnitude == expected);
6630
    }
6631
}
6632
6633
/// Test arithmetic constant folding: add, sub, mul, div.
6634
@test unsafe fn testConstExprArithmetic() throws (testing::TestError) {
6635
    try expectConstFold("constant A: i32 = 10; constant B: i32 = 20; constant C: i32 = A + B;", 2, 30);
6636
    try expectConstFold("constant A: i32 = 50; constant B: i32 = 20; constant C: i32 = A - B;", 2, 30);
6637
    try expectConstFold("constant A: i32 = 6; constant B: i32 = 7; constant C: i32 = A * B;", 2, 42);
6638
    try expectConstFold("constant A: i32 = 100; constant B: i32 = 5; constant C: i32 = A / B;", 2, 20);
6639
}
6640
6641
/// Test bitwise constant folding: and, or, xor.
6642
@test unsafe fn testConstExprBitwise() throws (testing::TestError) {
6643
    try expectConstFold("constant A: i32 = 0xFF; constant B: i32 = 0x0F; constant C: i32 = A & B;", 2, 0x0F);
6644
    try expectConstFold("constant A: i32 = 0xF0; constant B: i32 = 0x0F; constant C: i32 = A | B;", 2, 0xFF);
6645
    try expectConstFold("constant A: i32 = 0xFF; constant B: i32 = 0x0F; constant C: i32 = A ^ B;", 2, 0xF0);
6646
}
6647
6648
/// Test shift constant folding.
6649
@test unsafe fn testConstExprShift() throws (testing::TestError) {
6650
    try expectConstFold("constant A: i32 = 1; constant B: i32 = A << 4;", 1, 16);
6651
    try expectConstFold("constant A: i32 = 32; constant B: i32 = A >> 2;", 1, 8);
6652
}
6653
6654
/// Test chained constant expressions (C depends on A + B, D depends on C).
6655
@test unsafe fn testConstExprChained() throws (testing::TestError) {
6656
    try expectConstFold("constant A: i32 = 10; constant B: i32 = 20; constant C: i32 = A + B; constant D: i32 = C * 2;", 3, 60);
6657
}
6658
6659
/// Test constant expression used as array size.
6660
@test unsafe fn testConstExprAsArraySize() throws (testing::TestError) {
6661
    let mut testArena502 = testArena();
6662
    let testStorage502: 'test502 = &mut testArena502 in {
6663
        let mut a = testResolver(testStorage502);
6664
        let program = "constant A: u32 = 2; constant B: u32 = 3; constant SIZE: u32 = A + B; constant ARR: [i32; SIZE] = [1, 2, 3, 4, 5];";
6665
        let result = try resolveProgramStr(&mut a, program);
6666
        try expectNoErrors(&result);
6667
6668
        let arrStmt = try getBlockStmt(result.root, 3);
6669
        let sym = super::symbolFor(&a, arrStmt)
6670
            else throw testing::TestError::Failed;
6671
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
6672
            else throw testing::TestError::Failed;
6673
        try testing::expect(arrType.length == 5);
6674
    }
6675
}
6676
6677
/// Test cross-module constant expression: a constant in one module references
6678
/// a constant from another module via scope access.
6679
@test unsafe fn testCrossModuleConstExpr() throws (testing::TestError) {
6680
    let mut testArena503 = testArena();
6681
    let testStorage503: 'test503 = &mut testArena503 in {
6682
        let mut a = testResolver(testStorage503);
6683
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6684
6685
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
6686
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant BASE: i32 = 100;", &mut arena);
6687
        let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; constant DERIVED: i32 = consts::BASE + 50;", &mut arena);
6688
6689
        let result = try resolveModuleTree(&mut a, rootId);
6690
        try expectNoErrors(&result);
6691
    }
6692
}
6693
6694
/// Test cross-module constant expression used as array size.
6695
@test unsafe fn testCrossModuleConstExprArraySize() throws (testing::TestError) {
6696
    let mut testArena504 = testArena();
6697
    let testStorage504: 'test504 = &mut testArena504 in {
6698
        let mut a = testResolver(testStorage504);
6699
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6700
6701
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
6702
        let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant WIDTH: u32 = 8; export constant HEIGHT: u32 = 4;", &mut arena);
6703
        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);
6704
6705
        let result = try resolveModuleTree(&mut a, rootId);
6706
        try expectNoErrors(&result);
6707
    }
6708
}
6709
6710
/// Test that non-constant expressions in constant declarations are still rejected.
6711
@test unsafe fn testConstExprNonConstRejected() throws (testing::TestError) {
6712
    let mut testArena505 = testArena();
6713
    let testStorage505: 'test505 = &mut testArena505 in {
6714
        let mut a = testResolver(testStorage505);
6715
        let program = "fn value() -> i32 { return 1; } constant BAD: i32 = value() + 1;";
6716
        let result = try resolveProgramStr(&mut a, program);
6717
        let err = try expectError(&result);
6718
        let case super::ErrorKind::ConstExprRequired = err.kind
6719
            else throw testing::TestError::Failed;
6720
    }
6721
}
6722
6723
/// Test unary negation in constant expressions.
6724
@test unsafe fn testConstExprUnaryNeg() throws (testing::TestError) {
6725
    let mut testArena506 = testArena();
6726
    let testStorage506: 'test506 = &mut testArena506 in {
6727
        let mut a = testResolver(testStorage506);
6728
        let program = "constant A: i32 = 10; constant B: i32 = -A;";
6729
        let result = try resolveProgramStr(&mut a, program);
6730
        try expectNoErrors(&result);
6731
    }
6732
}
6733
6734
/// Test unary not in constant expressions.
6735
@test unsafe fn testConstExprUnaryNot() throws (testing::TestError) {
6736
    let mut testArena507 = testArena();
6737
    let testStorage507: 'test507 = &mut testArena507 in {
6738
        let mut a = testResolver(testStorage507);
6739
        let program = "constant A: bool = true; constant B: bool = not A;";
6740
        let result = try resolveProgramStr(&mut a, program);
6741
        try expectNoErrors(&result);
6742
    }
6743
}
6744
6745
/// Test `as` casts in constant expressions: widening, narrowing, sign changes, chaining.
6746
@test unsafe fn testConstExprCast() throws (testing::TestError) {
6747
    try expectConstFold("constant A: i32 = 42; constant B: u64 = A as u64;", 1, 42);
6748
    try expectConstFold("constant A: u64 = 10; constant B: u8 = A as u8;", 1, 10);
6749
    try expectConstFold("constant A: i32 = 7; constant B: u32 = A as u32;", 1, 7);
6750
    try expectConstFold("constant A: u32 = 100; constant B: i32 = A as i32;", 1, 100);
6751
    try expectConstFold("constant A: u8 = 5; constant B: u64 = (A as u32) as u64;", 1, 5);
6752
    try expectConstFold("constant A: u8 = 3; constant B: u8 = 4; constant C: i32 = (A as i32) + (B as i32);", 2, 7);
6753
    // Cast of unsuffixed literal arithmetic.
6754
    try expectConstFold("constant A: u32 = (3 + 4) as u32;", 0, 7);
6755
    try expectConstFold("constant A: u32 = ((3 + 4) as u64) as u32;", 0, 7);
6756
    try expectConstFold("constant A: u32 = (3 + 4) as u32 + 1;", 0, 8);
6757
    try expectConstFold("constant A: i32 = (2 as i32) * (3 + 4);", 0, 14);
6758
}
6759
6760
/// Test `as` cast in constant expressions used as array size.
6761
@test unsafe fn testConstExprCastAsArraySize() throws (testing::TestError) {
6762
    let mut testArena508 = testArena();
6763
    let testStorage508: 'test508 = &mut testArena508 in {
6764
        let mut a = testResolver(testStorage508);
6765
        let program = "constant LEN: u64 = 4; constant SIZE: u32 = LEN as u32; constant ARR: [i32; SIZE] = [1, 2, 3, 4];";
6766
        let result = try resolveProgramStr(&mut a, program);
6767
        try expectNoErrors(&result);
6768
6769
        let arrStmt = try getBlockStmt(result.root, 2);
6770
        let sym = super::symbolFor(&a, arrStmt)
6771
            else throw testing::TestError::Failed;
6772
        let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
6773
            else throw testing::TestError::Failed;
6774
        try testing::expect(arrType.length == 4);
6775
    }
6776
}
6777
6778
/// Test unsuffixed integer literals in constant expressions.
6779
@test unsafe fn testConstExprUnsuffixedLiterals() throws (testing::TestError) {
6780
    try expectConstFold("constant A: u32 = 4 * 4;", 0, 16);
6781
    try expectConstFold("constant B: u32 = 10; constant C: u32 = B * 2;", 1, 20);
6782
    try expectConstFold("constant D: u32 = 3 + 7;", 0, 10);
6783
    try expectConstFold("constant E: u32 = 2 * 3 + 4;", 0, 10);
6784
    try expectConstFold("constant F: i32 = -(3 + 4);", 0, 7);
6785
}
6786
6787
/// References cannot escape through return types.
6788
@test unsafe fn testRefReturnRejected() throws (testing::TestError) {
6789
    let mut testArena509 = testArena();
6790
    let testStorage509: 'test509 = &mut testArena509 in {
6791
        let mut a = testResolver(testStorage509);
6792
        let program = "record Marker: Once {} fn bad(value: &u32) -> &u32 { return value; }";
6793
        let result = try resolveProgramStr(&mut a, program);
6794
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
6795
    }
6796
}
6797
6798
/// Case-pattern fallbacks must terminate instead of synthesizing bindings.
6799
@test unsafe fn testCaseLetElseFallbackMustTerminate() throws (testing::TestError) {
6800
    let mut testArena510 = testArena();
6801
    let testStorage510: 'test510 = &mut testArena510 in {
6802
        let mut a = testResolver(testStorage510);
6803
        let program = "union Value { Item(u32) } fn run(value: Value) { let case Value::Item(item) = value else value; item; }";
6804
        let result = try resolveProgramStr(&mut a, program);
6805
        try expectErrorKind(&result, super::ErrorKind::LinearLetElseMustTerminate);
6806
    }
6807
}
6808
6809
/// Case bindings are unavailable on the pattern-failure path.
6810
@test unsafe fn testCaseLetElseFallbackCannotUseBinding() throws (testing::TestError) {
6811
    let mut testArena511 = testArena();
6812
    let testStorage511: 'test511 = &mut testArena511 in {
6813
        let mut a = testResolver(testStorage511);
6814
        let program = "union Value { Item(u32) } fn run(value: Value) { let case Value::Item(item) = value else item; }";
6815
        let result = try resolveProgramStr(&mut a, program);
6816
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("item"));
6817
    }
6818
}
6819
6820
/// Unsafe pointer dereference requires an unsafe declaration.
6821
@test unsafe fn testUnsafePointerOperationRejected() throws (testing::TestError) {
6822
    let mut testArena512 = testArena();
6823
    let testStorage512: 'test512 = &mut testArena512 in {
6824
        let mut a = testResolver(testStorage512);
6825
        let program = "record Marker: Once {} fn load(pointer: *unsafe u32) -> u32 { return *pointer; }";
6826
        let result = try resolveProgramStr(&mut a, program);
6827
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
6828
    }
6829
}
6830
6831
/// Unsafe pointers remain freely copyable inside an unsafe declaration.
6832
@test unsafe fn testUnsafePointerOperationAllowed() throws (testing::TestError) {
6833
    let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; }";
6834
    try expectAnalyzeOk(program);
6835
}
6836
6837
/// Safe code cannot call a function that accepts unsafe operations.
6838
@test unsafe fn testUnsafeFunctionCallRejected() throws (testing::TestError) {
6839
    let mut testArena513 = testArena();
6840
    let testStorage513: 'test513 = &mut testArena513 in {
6841
        let mut a = testResolver(testStorage513);
6842
        let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } fn run(pointer: *unsafe u32) -> u32 { return load(pointer); }";
6843
        let result = try resolveProgramStr(&mut a, program);
6844
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
6845
    }
6846
}
6847
6848
/// Unsafe function values retain their call-site safety requirement.
6849
@test unsafe fn testUnsafeFunctionAliasCallRejected() throws (testing::TestError) {
6850
    let mut testArena514 = testArena();
6851
    let testStorage514: 'test514 = &mut testArena514 in {
6852
        let mut a = testResolver(testStorage514);
6853
        let program = "unsafe fn dangerous() -> u32 { return 42; } fn run() -> u32 { let alias = dangerous; return alias(); }";
6854
        let result = try resolveProgramStr(&mut a, program);
6855
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
6856
    }
6857
}
6858
6859
/// References cannot be embedded in aggregate fields.
6860
@test unsafe fn testRefFieldRejected() throws (testing::TestError) {
6861
    let mut testArena515 = testArena();
6862
    let testStorage515: 'test515 = &mut testArena515 in {
6863
        let mut a = testResolver(testStorage515);
6864
        let program = "record Marker: Once {} record Bad { value: &u32 }";
6865
        let result = try resolveProgramStr(&mut a, program);
6866
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
6867
    }
6868
}
6869
6870
/// Trait methods may use reference receivers.
6871
@test unsafe fn testTraitRefReceiver() throws (testing::TestError) {
6872
    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); }";
6873
    try expectAnalyzeOk(program);
6874
}
6875
6876
/// Trait implementations must preserve the receiver pointer class.
6877
@test unsafe fn testTraitReceiverClassMismatch() throws (testing::TestError) {
6878
    let mut testArena516 = testArena();
6879
    let testStorage516: 'test516 = &mut testArena516 in {
6880
        let mut a = testResolver(testStorage516);
6881
        let program = "record Value { number: i32 } trait Read { fn (&Read) get() -> i32; } instance Read for Value { fn (value: *Value) get() -> i32 { return value.number; } }";
6882
        let result = try resolveProgramStr(&mut a, program);
6883
        try expectErrorKind(&result, super::ErrorKind::TraitReceiverMismatch);
6884
    }
6885
}
6886
6887
/// Unmarked composite values may be discarded.
6888
@test unsafe fn testAffineCompositeMayBeDiscarded() throws (testing::TestError) {
6889
    let program = "record Value { number: u32 } fn run() { let value = Value { number: 1 }; }";
6890
    try expectAnalyzeOk(program);
6891
}
6892
6893
/// A by-value use moves an unmarked composite value.
6894
@test unsafe fn testAffineCompositeUseAfterMoveRejected() throws (testing::TestError) {
6895
    let mut testArena517 = testArena();
6896
    let testStorage517: 'test517 = &mut testArena517 in {
6897
        let mut a = testResolver(testStorage517);
6898
        let program = "record Value { number: u32 } fn take(value: Value) {} fn run() { let value = Value { number: 1 }; take(value); take(value); }";
6899
        let result = try resolveProgramStr(&mut a, program);
6900
        try expectErrorKind(&result, super::ErrorKind::AffineUseAfterMove("value"));
6901
    }
6902
}
6903
6904
/// Affine values may move on only one branch when not used later.
6905
@test unsafe fn testAffineConditionalMoveMayBeDiscarded() throws (testing::TestError) {
6906
    let program = "record Value { number: u32 } fn take(value: Value) {} fn run(condition: bool) { let value = Value { number: 1 }; if condition { take(value); } }";
6907
    try expectAnalyzeOk(program);
6908
}
6909
6910
/// A `Copy` composite remains available after a by-value use.
6911
@test unsafe fn testCopyCompositeMayBeReused() throws (testing::TestError) {
6912
    let program = "record Value: Copy { number: u32 } fn take(value: Value) {} fn run() { let value = Value { number: 1 }; take(value); take(value); }";
6913
    try expectAnalyzeOk(program);
6914
}
6915
6916
/// A `Copy` composite may contain only copy values.
6917
@test unsafe fn testCopyCompositeRejectsAffineField() throws (testing::TestError) {
6918
    let mut testArena518 = testArena();
6919
    let testStorage518: 'test518 = &mut testArena518 in {
6920
        let mut a = testResolver(testStorage518);
6921
        let program = "record Inner { number: u32 } record Outer: Copy { inner: Inner }";
6922
        let result = try resolveProgramStr(&mut a, program);
6923
        try expectErrorKind(&result, super::ErrorKind::CopyContainsNonCopy);
6924
    }
6925
}
6926
6927
/// A composite cannot carry conflicting ownership markers.
6928
@test unsafe fn testConflictingOwnershipMarkersRejected() throws (testing::TestError) {
6929
    let mut testArena519 = testArena();
6930
    let testStorage519: 'test519 = &mut testArena519 in {
6931
        let mut a = testResolver(testStorage519);
6932
        let program = "record Value: Copy + Once { number: u32 }";
6933
        let result = try resolveProgramStr(&mut a, program);
6934
        try expectErrorKind(&result, super::ErrorKind::ConflictingOwnershipMarkers);
6935
    }
6936
}
6937
6938
/// Linear composites still require one consuming use.
6939
@test unsafe fn testLinearCompositeMustBeConsumed() throws (testing::TestError) {
6940
    let mut testArena520 = testArena();
6941
    let testStorage520: 'test520 = &mut testArena520 in {
6942
        let mut a = testResolver(testStorage520);
6943
        let program = "record Token: Once { number: u32 } fn run() { let token = Token { number: 1 }; }";
6944
        let result = try resolveProgramStr(&mut a, program);
6945
        try expectErrorKind(&result, super::ErrorKind::LinearNotConsumed("token"));
6946
    }
6947
}
6948
6949
/// The compiler-known marker cannot be derived more than once.
6950
@test unsafe fn testDuplicateOnceMarkerRejected() throws (testing::TestError) {
6951
    let mut testArena521 = testArena();
6952
    let testStorage521: 'test521 = &mut testArena521 in {
6953
        let mut a = testResolver(testStorage521);
6954
        let program = "record Token: Once + Once { value: u32 }";
6955
        let result = try resolveProgramStr(&mut a, program);
6956
        try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("Once"));
6957
    }
6958
}
6959
6960
/// Stack storage cannot produce a safe stored pointer or slice.
6961
@test unsafe fn testStackPointerRejected() throws (testing::TestError) {
6962
    let programs = &[
6963
        "fn run() { let value: u32 = 0; let pointer: *u32 = &value; }",
6964
        "fn run() -> *u32 { let value: u32 = 0; return &value; }",
6965
        "fn run(value: u32) -> *u32 { return &value; }",
6966
        "record Cell { value: u32 } fn run() { let cell = Cell { value: 1 }; let pointer: *u32 = &(cell.value); }",
6967
        "fn run() { let values = [1, 2]; let pointer: *i32 = &values[0]; }",
6968
        "fn run() { let values = [1, 2]; let slice: *[i32] = &values[..]; }",
6969
        "fn run(value: i32) { let slice: *[i32] = &[value]; }",
6970
        "fn run(value: &u32) -> *u32 { return value; }",
6971
        "fn run(value: &u32) -> *u32 { return &*value; }",
6972
        "fn run(values: &[u32]) -> *[u32] { return values; }",
6973
        "fn run(values: &[u32]) -> *[u32] { return &values[..]; }",
6974
        "fn run(values: &[u32]) -> *u32 { return values.ptr; }",
6975
        "fn run() -> *i32 { return &[1, 2][0]; }",
6976
        "fn run() -> *[i32] { return &[1, 2][..]; }",
6977
        "fn run(value: *u32) -> **u32 { return &value; }",
6978
        "fn run(values: *[u32]) -> *u32 { return &values.len; }",
6979
        "unsafe fn run(value: *unsafe u32) -> *u32 { return &*value; }",
6980
        "fn run() { let value: u32 = 7; let pointer: *unsafe u32 = &value; }",
6981
        "record Cell { value: u32 } fn run(value: &Cell) -> *u32 { return &value.value; }",
6982
        "record Cell { value: *u32 } fn run(value: &u32) -> Cell { return Cell { value }; }",
6983
        "fn run(value: &u32) -> *[u32] { return @sliceOf(value, 1); }",
6984
    ];
6985
    for program in programs {
6986
        let mut testArena522 = testArena();
6987
        let testStorage522: 'test522 = &mut testArena522 in {
6988
            let mut resolver = testResolver(testStorage522);
6989
            let result = try resolveProgramStr(&mut resolver, program);
6990
            let _ = try expectError(&result);
6991
        }
6992
    }
6993
}
6994
6995
/// Stack values can be borrowed for a call.
6996
@test unsafe fn testStackBorrowAllowed() throws (testing::TestError) {
6997
    try expectAnalyzeOk("fn read(value: &u32) -> u32 { return *value; } fn run() -> u32 { let value: u32 = 7; return read(&value); }");
6998
    try expectAnalyzeOk("fn write(values: &mut [u32]) { set values[0] = 7; } fn run() { let mut values: [u32; 2] = [1, 2]; write(&mut values[..]); }");
6999
}
7000
7001
/// Raw pointers and slices can be borrowed in an unsafe context.
7002
@test unsafe fn testImplicitRawBorrowAllowed() throws (testing::TestError) {
7003
    let programs = &[
7004
        "fn read(p: &u32) -> u32 { return *p; } unsafe fn run(p: *unsafe u32) -> u32 { return read(p); }",
7005
        "fn write(p: &mut u32) { set *p = 7; } fn run(p: *unsafe mut u32) { unsafe { write(p); write(p); } }",
7006
        "fn read(p: &[u32]) -> u32 { return p[0]; } unsafe fn run(p: *unsafe [u32]) -> u32 { return read(p); }",
7007
        "fn write(p: &mut [u32]) { set p[0] = 7; } unsafe fn run(p: *unsafe mut [u32]) { write(p); write(p); }",
7008
        "fn read(p: &u32) {} unsafe fn run(p: *unsafe mut u32) { read(p); }",
7009
        "trait Read { fn (&Read) get(); } fn read(p: &opaque Read) {} unsafe fn run(p: *unsafe opaque Read) { read(p); }",
7010
    ];
7011
    for program in programs {
7012
        try expectAnalyzeOk(program);
7013
    }
7014
}
7015
7016
/// An implicit borrow of raw storage requires an unsafe context.
7017
@test unsafe fn testImplicitRawBorrowRequiresUnsafe() throws (testing::TestError) {
7018
    let programs = &[
7019
        "fn read(p: &u32) {} fn run(p: *unsafe u32) { read(p); }",
7020
        "fn write(p: &mut u32) {} fn run(p: *unsafe mut u32) { write(p); }",
7021
        "fn read(p: &[u32]) {} fn run(p: *unsafe [u32]) { read(p); }",
7022
        "fn write(p: &mut [u32]) {} fn run(p: *unsafe mut [u32]) { write(p); }",
7023
        "trait Read { fn (&Read) get(); } fn read(p: &opaque Read) {} fn run(p: *unsafe opaque Read) { read(p); }",
7024
        "fn read(p: &u32) {} fn run(p: *unsafe u32) { unsafe { read(p); } read(p); }",
7025
    ];
7026
    for program in programs {
7027
        let mut testArena523 = testArena();
7028
        let testStorage523: 'test523 = &mut testArena523 in {
7029
            let mut a = testResolver(testStorage523);
7030
            let result = try resolveProgramStr(&mut a, program);
7031
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7032
        }
7033
    }
7034
}
7035
7036
/// Raw borrows preserve mutability, storage type, and ownership constraints.
7037
@test unsafe fn testImplicitRawBorrowPreservesTypes() throws (testing::TestError) {
7038
    let programs = &[
7039
        "fn write(p: &mut u32) {} unsafe fn run(p: *unsafe u32) { write(p); }",
7040
        "fn write(p: &mut [u32]) {} unsafe fn run(p: *unsafe [u32]) { write(p); }",
7041
        "fn read(p: &u64) {} unsafe fn run(p: *unsafe u32) { read(p); }",
7042
        "fn read(p: &[u64]) {} unsafe fn run(p: *unsafe [u32]) { read(p); }",
7043
        "fn take(p: *u32) {} unsafe fn run(p: *unsafe u32) { take(p); }",
7044
        "fn take(p: *[u32]) {} unsafe fn run(p: *unsafe [u32]) { take(p); }",
7045
        "fn read(p: &*u32) {} unsafe fn run(p: *unsafe *unsafe u32) { read(p); }",
7046
    ];
7047
    for program in programs {
7048
        let mut testArena524 = testArena();
7049
        let testStorage524: 'test524 = &mut testArena524 in {
7050
            let mut a = testResolver(testStorage524);
7051
            let result = try resolveProgramStr(&mut a, program);
7052
            let err = try expectError(&result);
7053
            let case super::ErrorKind::TypeMismatch(_) = err.kind
7054
                else throw testing::TestError::Failed;
7055
        }
7056
    }
7057
}
7058
7059
/// Implicit raw borrows retain the call's exclusive-borrow checks.
7060
@test unsafe fn testImplicitRawBorrowConflict() throws (testing::TestError) {
7061
    let mut testArena525 = testArena();
7062
    let testStorage525: 'test525 = &mut testArena525 in {
7063
        let mut a = testResolver(testStorage525);
7064
        let result = try resolveProgramStr(&mut a,
7065
            "fn useBoth(a: &mut u32, b: &u32) {} unsafe fn run(p: *unsafe mut u32) { useBoth(p, p); }");
7066
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("p"));
7067
    }
7068
}
7069
7070
/// Unsafe declarations can store raw pointers to stack values.
7071
@test unsafe fn testUnsafeStackPointerAllowed() throws (testing::TestError) {
7072
    try expectAnalyzeOk("unsafe fn run() { let mut value: u32 = 0; let pointer: *unsafe mut u32 = &mut value as *unsafe mut u32; set *pointer = 7; }");
7073
    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; }");
7074
    try expectAnalyzeOk("unsafe fn run() { let value: u32 = 7; let pointer: *unsafe u32 = &value; }");
7075
    try expectAnalyzeOk("unsafe fn run() { let values: [u32; 2] = [1, 2]; let slice: *unsafe [u32] = &values[..]; }");
7076
}
7077
7078
/// Permanent storage can produce safe stored pointers and slices.
7079
@test unsafe fn testPermanentPointerAllowed() throws (testing::TestError) {
7080
    try expectAnalyzeOk("static VALUE: u32 = 7; fn run() -> *u32 { return &VALUE; }");
7081
    try expectAnalyzeOk("static VALUES: [u32; 2] = [1, 2]; fn run() -> *[u32] { return &VALUES[..]; }");
7082
    try expectAnalyzeOk("fn run() -> *[u32] { return &[1, 2]; }");
7083
    try expectAnalyzeOk("fn run(value: *u32) -> *u32 { return &*value; }");
7084
    try expectAnalyzeOk("fn run(values: *[u32]) -> *[u32] { return &values[..]; }");
7085
    try expectAnalyzeOk("record Cell { value: u32 } fn run(value: *Cell) -> *u32 { return &value.value; }");
7086
    try expectAnalyzeOk("fn run(values: *[u32]) -> *u32 { return &values[0]; }");
7087
    try expectAnalyzeOk("unsafe fn run(values: *[u32]) -> *u32 { return values.ptr; }");
7088
    try expectAnalyzeOk("unsafe fn run(value: *u32) -> *[u32] { return @sliceOf(value, 1); }");
7089
}
7090
7091
/// References are rejected from every nested or storable type position.
7092
@test unsafe fn testNestedRefPositionsRejected() throws (testing::TestError) {
7093
    {
7094
        let mut testArena526 = testArena();
7095
        let testStorage526: 'test526 = &mut testArena526 in {
7096
            let mut a = testResolver(testStorage526);
7097
            let program = "record Marker: Once {} union Bad { Value(&u32) }";
7098
            let result = try resolveProgramStr(&mut a, program);
7099
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7100
        }
7101
    } {
7102
        let mut testArena527 = testArena();
7103
        let testStorage527: 'test527 = &mut testArena527 in {
7104
            let mut a = testResolver(testStorage527);
7105
            let program = "record Marker: Once {} fn bad(value: ?&u32) {}";
7106
            let result = try resolveProgramStr(&mut a, program);
7107
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7108
        }
7109
    } {
7110
        let mut testArena528 = testArena();
7111
        let testStorage528: 'test528 = &mut testArena528 in {
7112
            let mut a = testResolver(testStorage528);
7113
            let program = "record Marker: Once {} fn bad(value: [&u32; 1]) {}";
7114
            let result = try resolveProgramStr(&mut a, program);
7115
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7116
        }
7117
    } {
7118
        let mut testArena529 = testArena();
7119
        let testStorage529: 'test529 = &mut testArena529 in {
7120
            let mut a = testResolver(testStorage529);
7121
            let program = "record Marker: Once {} fn bad(value: *&u32) {}";
7122
            let result = try resolveProgramStr(&mut a, program);
7123
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7124
        }
7125
    } {
7126
        let mut testArena530 = testArena();
7127
        let testStorage530: 'test530 = &mut testArena530 in {
7128
            let mut a = testResolver(testStorage530);
7129
            let program = "record Marker: Once {} static BAD: &u32 = undefined;";
7130
            let result = try resolveProgramStr(&mut a, program);
7131
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7132
        }
7133
    } {
7134
        let mut testArena531 = testArena();
7135
        let testStorage531: 'test531 = &mut testArena531 in {
7136
            let mut a = testResolver(testStorage531);
7137
            let program = "record Marker: Once {} fn bad(callback: fn() -> &u32) {}";
7138
            let result = try resolveProgramStr(&mut a, program);
7139
            try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
7140
        }
7141
    }
7142
}
7143
7144
/// Function pointer parameter references remain call-scoped and valid.
7145
@test unsafe fn testFunctionPointerRefParameterAllowed() throws (testing::TestError) {
7146
    let program = "record Marker: Once {} fn invoke(callback: fn(&u32), value: &u32) { callback(value); }";
7147
    try expectAnalyzeOk(program);
7148
}
7149
7150
/// Pointer and slice casts cannot change reference ownership.
7151
@test unsafe fn testRefCastClassPreserved() throws (testing::TestError) {
7152
    {
7153
        let mut testArena532 = testArena();
7154
        let testStorage532: 'test532 = &mut testArena532 in {
7155
            let mut a = testResolver(testStorage532);
7156
            let program = "record Marker: Once {} fn cast(value: &u32) { value as *u32; }";
7157
            let result = try resolveProgramStr(&mut a, program);
7158
            let err = try expectError(&result);
7159
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
7160
                else throw testing::TestError::Failed;
7161
        }
7162
    } {
7163
        let mut testArena533 = testArena();
7164
        let testStorage533: 'test533 = &mut testArena533 in {
7165
            let mut a = testResolver(testStorage533);
7166
            let program = "record Marker: Once {} fn cast(values: &[u32]) { values as *[u32]; }";
7167
            let result = try resolveProgramStr(&mut a, program);
7168
            let err = try expectError(&result);
7169
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
7170
                else throw testing::TestError::Failed;
7171
        }
7172
    }
7173
}
7174
7175
/// Every operation that interprets an unsafe address requires an unsafe declaration.
7176
@test unsafe fn testUnsafePointerOperationsRejected() throws (testing::TestError) {
7177
    {
7178
        let mut testArena534 = testArena();
7179
        let testStorage534: 'test534 = &mut testArena534 in {
7180
            let mut a = testResolver(testStorage534);
7181
            let program = "record Marker: Once {} fn cast(pointer: *unsafe u32) -> u64 { return pointer as u64; }";
7182
            let result = try resolveProgramStr(&mut a, program);
7183
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7184
        }
7185
    } {
7186
        let mut testArena535 = testArena();
7187
        let testStorage535: 'test535 = &mut testArena535 in {
7188
            let mut a = testResolver(testStorage535);
7189
            let program = "record Marker: Once {} fn compare(pointer: *unsafe u32) -> bool { return pointer == pointer; }";
7190
            let result = try resolveProgramStr(&mut a, program);
7191
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7192
        }
7193
    } {
7194
        let mut testArena536 = testArena();
7195
        let testStorage536: 'test536 = &mut testArena536 in {
7196
            let mut a = testResolver(testStorage536);
7197
            let program = "record Marker: Once {} fn offset(pointer: *unsafe u32) -> *unsafe u32 { return pointer + 1; }";
7198
            let result = try resolveProgramStr(&mut a, program);
7199
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7200
        }
7201
    } {
7202
        let mut testArena537 = testArena();
7203
        let testStorage537: 'test537 = &mut testArena537 in {
7204
            let mut a = testResolver(testStorage537);
7205
            let program = "record Marker: Once {} fn index(values: *unsafe [u32]) -> u32 { return values[0]; }";
7206
            let result = try resolveProgramStr(&mut a, program);
7207
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7208
        }
7209
    } {
7210
        let mut testArena538 = testArena();
7211
        let testStorage538: 'test538 = &mut testArena538 in {
7212
            let mut a = testResolver(testStorage538);
7213
            let program = "record Marker: Once {} record Cell { value: u32 } fn field(cell: *unsafe Cell) -> u32 { return cell.value; }";
7214
            let result = try resolveProgramStr(&mut a, program);
7215
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7216
        }
7217
    } {
7218
        let mut testArena539 = testArena();
7219
        let testStorage539: 'test539 = &mut testArena539 in {
7220
            let mut a = testResolver(testStorage539);
7221
            let program = "record Marker: Once {} fn store(pointer: *unsafe mut u32) { set *pointer = 1; }";
7222
            let result = try resolveProgramStr(&mut a, program);
7223
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7224
        }
7225
    } {
7226
        let mut testArena540 = testArena();
7227
        let testStorage540: 'test540 = &mut testArena540 in {
7228
            let mut a = testResolver(testStorage540);
7229
            let program = "record Marker: Once {} fn cast() { let value: u32 = 0; let pointer = &value as *unsafe u32; }";
7230
            let result = try resolveProgramStr(&mut a, program);
7231
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7232
        }
7233
    }
7234
}
7235
7236
/// Pointer offsets require an unsafe function for either operand order.
7237
@test unsafe fn testPointerArithmeticRequiresUnsafe() throws (testing::TestError) {
7238
    let programs = &[
7239
        "fn run(p: *u8) -> *u8 { return p + 1; }",
7240
        "fn run(p: *u8) -> *u8 { return 1 + p; }",
7241
        "fn run(p: *u8) -> *u8 { return p - 1; }",
7242
        "fn run(input: *mut u8) { let mut p = input; set p += 1; }",
7243
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let p = &DATA[0]; return *(p + 1); }",
7244
    ];
7245
    for program in programs {
7246
        let mut testArena541 = testArena();
7247
        let testStorage541: 'test541 = &mut testArena541 in {
7248
            let mut a = testResolver(testStorage541);
7249
            let result = try resolveProgramStr(&mut a, program);
7250
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7251
        }
7252
    }
7253
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return p + 1; }");
7254
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return 1 + p; }");
7255
    try expectAnalyzeOk("unsafe fn run(p: *mut u8) -> *mut u8 { return p - 1; }");
7256
    try expectAnalyzeOk("fn run(value: u32) -> u32 { return value + 1; }");
7257
}
7258
7259
/// Casts that reinterpret storage require an unsafe function.
7260
@test unsafe fn testStorageCastsRequireUnsafe() throws (testing::TestError) {
7261
    let programs = &[
7262
        "fn run(p: *u8) -> *u64 { return p as *u64; }",
7263
        "fn run(p: &u8) -> u64 { return *(p as &u64); }",
7264
        "fn run(p: *mut u8) -> *mut u64 { return p as *mut u64; }",
7265
        "fn run(p: *opaque) -> *u64 { return p as *u64; }",
7266
        "fn run(p: **u8) -> **u64 { return p as **u64; }",
7267
        "fn run(s: *[u8]) -> *[u64] { return s as *[u64]; }",
7268
        "fn run(s: *[opaque]) -> *[u64] { return s as *[u64]; }",
7269
        "fn run(s: &mut [u64]) { let _ = s as &mut [u8]; }",
7270
        "static DATA: [u8; 1] = [42]; fn run() -> u64 { return *(&DATA[0] as *u64); }",
7271
    ];
7272
    for program in programs {
7273
        let mut testArena542 = testArena();
7274
        let testStorage542: 'test542 = &mut testArena542 in {
7275
            let mut a = testResolver(testStorage542);
7276
            let result = try resolveProgramStr(&mut a, program);
7277
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7278
        }
7279
    }
7280
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u64 { return p as *u64; }");
7281
    try expectAnalyzeOk("unsafe fn run(p: &u8) -> u64 { return *(p as &u64); }");
7282
    try expectAnalyzeOk("unsafe fn run(s: *[u8]) -> *[u64] { return s as *[u64]; }");
7283
    try expectAnalyzeOk("fn run(p: *u8) -> *u8 { return p as *u8; }");
7284
    try expectAnalyzeOk("fn run(p: *u8) -> *opaque { return p as *opaque; }");
7285
    try expectAnalyzeOk("fn run(s: *[u8]) -> *[opaque] { return s as *[opaque]; }");
7286
    try expectAnalyzeOk("fn run(p: *mut u8) -> *u8 { return p as *u8; }");
7287
}
7288
7289
/// Explicit slice bounds require an unsafe function.
7290
@test unsafe fn testSliceConstructionRequiresUnsafe() throws (testing::TestError) {
7291
    let programs = &[
7292
        "fn run(p: *u8) -> *[u8] { return @sliceOf(p, 100); }",
7293
        "fn run(p: *mut u8) -> *mut [u8] { return @sliceOf(p, 0, 100); }",
7294
        "fn run(p: &u8) -> u8 { return @sliceOf(p, 100)[99]; }",
7295
        "fn run(p: &mut u8) { set @sliceOf(p, 100)[99] = 1; }",
7296
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let s = @sliceOf(&DATA[0], 100); return s[99]; }",
7297
    ];
7298
    for program in programs {
7299
        let mut testArena543 = testArena();
7300
        let testStorage543: 'test543 = &mut testArena543 in {
7301
            let mut a = testResolver(testStorage543);
7302
            let result = try resolveProgramStr(&mut a, program);
7303
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7304
        }
7305
    }
7306
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *[u8] { return @sliceOf(p, 100); }");
7307
    try expectAnalyzeOk("unsafe fn run(p: *mut u8) -> *mut [u8] { return @sliceOf(p, 0, 100); }");
7308
    try expectAnalyzeOk("unsafe fn run(p: &u8) -> u8 { return @sliceOf(p, 1)[0]; }");
7309
    try expectAnalyzeOk("fn run(s: *[u8]) -> *[u8] { return &s[..]; }");
7310
}
7311
7312
/// Slice header writes and mutable field borrows require an unsafe function.
7313
@test unsafe fn testSliceHeaderMutationRequiresUnsafe() throws (testing::TestError) {
7314
    let programs = &[
7315
        "fn run(s: *mut [u8]) { set s.len = 100; }",
7316
        "fn run(s: *mut [u8]) { set s.cap = 100; }",
7317
        "fn run(s: *mut [u8], p: *mut u8) { set s.ptr = p; }",
7318
        "fn run(s: *mut [u8]) { set s.len += 1; }",
7319
        "fn change(n: &mut u32) { set *n = 100; } fn run(s: *mut [u8]) { change(&mut s.len); }",
7320
        "fn change(n: &mut u32) { set *n = 100; } fn run(s: *mut [u8]) { change(&mut s.cap); }",
7321
        "fn change(p: &mut *u8, q: *u8) { set *p = q; } fn run(q: *u8) { let mut s: *[u8] = &[]; change(&mut s.ptr, q); }",
7322
        "fn run(s: &mut *[u8]) { set s.len = 100; }",
7323
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let mut s = &DATA[..]; set s.len = 100; return s[99]; }",
7324
    ];
7325
    for program in programs {
7326
        let mut testArena544 = testArena();
7327
        let testStorage544: 'test544 = &mut testArena544 in {
7328
            let mut a = testResolver(testStorage544);
7329
            let result = try resolveProgramStr(&mut a, program);
7330
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7331
        }
7332
    }
7333
    try expectAnalyzeOk("unsafe fn run(s: *mut [u8]) { set s.len = 0; set s.cap = 0; }");
7334
    try expectAnalyzeOk("unsafe fn run(s: *mut [u8], p: *mut u8) { set s.ptr = p; }");
7335
    try expectAnalyzeOk("fn change(n: &mut u32) { set *n = 0; } unsafe fn run(s: *mut [u8]) { change(&mut s.len); }");
7336
    try expectAnalyzeOk("fn run(s: *mut [u8]) { set s[0] = 1; }");
7337
    try expectAnalyzeOk("record R { len: u32 } fn run(r: &mut R) { set r.len = 1; }");
7338
}
7339
7340
/// Unsafe blocks permit operations within a safe function.
7341
@test unsafe fn testUnsafeBlocksAllowed() throws (testing::TestError) {
7342
    try expectAnalyzeOk("fn run(p: *u8) -> *u8 { unsafe { return p + 1; } }");
7343
    try expectAnalyzeOk("unsafe fn read(p: *unsafe u8) -> u8 { return *p; } fn run(p: *unsafe u8) -> u8 { unsafe { return read(p); } }");
7344
    try expectAnalyzeOk("fn run(p: *u8) -> *[u8] { unsafe { { return @sliceOf(p, 1); } } }");
7345
    try expectAnalyzeOk("fn run(p: *u8) -> *u64 { unsafe { unsafe { return p as *u64; } } }");
7346
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { unsafe {} return p + 1; }");
7347
}
7348
7349
/// Unsafe permission ends at the closing brace and at function boundaries.
7350
@test unsafe fn testUnsafeBlockContextRestored() throws (testing::TestError) {
7351
    let programs = &[
7352
        "fn run(p: *u8) -> *u8 { unsafe { let q = p + 1; } return p + 1; }",
7353
        "fn run(p: *u8) -> *u8 { unsafe { unsafe {} } return p + 1; }",
7354
        "unsafe fn first(p: *u8) -> *u8 { return p + 1; } fn second(p: *u8) -> *u8 { return p + 1; }",
7355
    ];
7356
    for program in programs {
7357
        let mut testArena545 = testArena();
7358
        let testStorage545: 'test545 = &mut testArena545 in {
7359
            let mut a = testResolver(testStorage545);
7360
            let result = try resolveProgramStr(&mut a, program);
7361
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7362
        }
7363
    }
7364
    let mut testArena546 = testArena();
7365
    let testStorage546: 'test546 = &mut testArena546 in {
7366
        let mut a = testResolver(testStorage546);
7367
        let result = try resolveProgramStr(&mut a, "unsafe fn act() {} fn run() { unsafe { act(); } act(); }");
7368
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7369
    }
7370
}
7371
7372
/// Resolution errors do not extend an unsafe block's permission.
7373
@test unsafe fn testUnsafeBlockErrorRestoresContext() throws (testing::TestError) {
7374
    let mut testArena547 = testArena();
7375
    let testStorage547: 'test547 = &mut testArena547 in {
7376
        let mut a = testResolver(testStorage547);
7377
        let result = try resolveProgramStr(&mut a, "fn run(p: *u8) { unsafe { missing; } let q = p + 1; }");
7378
        let mut found = false;
7379
        for err in result.diagnostics.errors {
7380
            if let case super::ErrorKind::UnsafeOperation = err.kind {
7381
                set found = true;
7382
            }
7383
        }
7384
        try testing::expect(found);
7385
    }
7386
}
7387
7388
/// Unsafe blocks preserve reference lifetime checks.
7389
@test unsafe fn testUnsafeBlockPreservesReferences() throws (testing::TestError) {
7390
    let mut testArena548 = testArena();
7391
    let testStorage548: 'test548 = &mut testArena548 in {
7392
        let mut a = testResolver(testStorage548);
7393
        let result = try resolveProgramStr(&mut a, "fn run() { let mut n: u32 = 1; let p = &n; unsafe { set n = 2; } }");
7394
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("n"));
7395
    }
7396
}
7397
7398
/// Slice pointer access requires an unsafe context for every slice class.
7399
@test unsafe fn testSlicePointerRequiresUnsafe() throws (testing::TestError) {
7400
    let programs = &[
7401
        "fn run(s: *[u8]) -> *u8 { return s.ptr; }",
7402
        "fn run(s: *mut [u8]) -> *mut u8 { return s.ptr; }",
7403
        "fn run(s: &[u8]) -> u8 { return *s.ptr; }",
7404
        "fn run(s: &mut [u8]) { set *s.ptr = 1; }",
7405
        "fn run(s: &*[u8]) -> *u8 { return s.ptr; }",
7406
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let s = &DATA[1..]; return *s.ptr; }",
7407
        "fn run(s: *[u8]) -> u64 { return s.ptr as u64; }",
7408
    ];
7409
    for program in programs {
7410
        let mut testArena549 = testArena();
7411
        let testStorage549: 'test549 = &mut testArena549 in {
7412
            let mut a = testResolver(testStorage549);
7413
            let result = try resolveProgramStr(&mut a, program);
7414
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7415
        }
7416
    }
7417
    try expectAnalyzeOk("unsafe fn run(s: *[u8]) -> *u8 { return s.ptr; }");
7418
    try expectAnalyzeOk("fn run(s: *[u8]) -> u64 { unsafe { return s.ptr as u64; } }");
7419
    try expectAnalyzeOk("fn run(s: *[u8]) -> *u8 { return &s[0]; }");
7420
    try expectAnalyzeOk("fn run(s: *[u8]) -> u32 { return s.len + s.cap; }");
7421
    try expectAnalyzeOk("record R { ptr: u32 } fn run(r: R) -> u32 { return r.ptr; }");
7422
}
7423
7424
/// Unsafe statics require unsafe permission for reads, writes, and addresses.
7425
@test unsafe fn testUnsafeStaticAccessRejected() throws (testing::TestError) {
7426
    let programs = &[
7427
        "unsafe static VALUE: u32 = 7; fn run() -> u32 { return VALUE; }",
7428
        "unsafe static VALUE: u32 = 7; fn run() { set VALUE = 8; }",
7429
        "unsafe static VALUE: u32 = 7; fn run() -> *u32 { return &VALUE; }",
7430
        "unsafe static VALUE: u32 = 7; fn run() -> *mut u32 { return &mut VALUE; }",
7431
        "unsafe static DATA: [u8; 1] = [42]; fn run() -> u8 { return DATA[0]; }",
7432
        "unsafe static DATA: [u8; 1] = [42]; fn run() -> u32 { return DATA.len; }",
7433
        "record R { value: u32 } unsafe static DATA: R = R { value: 7 }; fn run() -> u32 { return DATA.value; }",
7434
    ];
7435
    for program in programs {
7436
        let mut testArena550 = testArena();
7437
        let testStorage550: 'test550 = &mut testArena550 in {
7438
            let mut a = testResolver(testStorage550);
7439
            let result = try resolveProgramStr(&mut a, program);
7440
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7441
        }
7442
    }
7443
}
7444
7445
/// Unsafe blocks and functions can access unsafe statics.
7446
@test unsafe fn testUnsafeStaticAccessAllowed() throws (testing::TestError) {
7447
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; unsafe fn run() -> u32 { set VALUE = 8; return VALUE; }");
7448
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; fn run() -> u32 { unsafe { return VALUE; } }");
7449
    try expectAnalyzeOk("unsafe static VALUE: u32 = 7; unsafe fn run() -> *mut u32 { return &mut VALUE; }");
7450
    try expectAnalyzeOk("static VALUE: u32 = 7; fn run() -> u32 { return VALUE; }");
7451
    try expectAnalyzeOk("constant BYTES: *[u8] = \"x\"; unsafe static DATA: *[u64] = BYTES as *[u64];");
7452
}
7453
7454
/// Imports preserve the unsafe access requirement of a static.
7455
@test unsafe fn testUnsafeStaticImportsRejected() throws (testing::TestError) {
7456
    let programs = &[
7457
        "use root::storage; fn run() -> u32 { return storage::VALUE; }",
7458
        "use root::storage::*; fn run() -> u32 { return VALUE; }",
7459
    ];
7460
    for program in programs {
7461
        let mut testArena551 = testArena();
7462
        let testStorage551: 'test551 = &mut testArena551 in {
7463
            let mut a = testResolver(testStorage551);
7464
            let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
7465
            let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod storage; mod app;", &mut arena);
7466
            let _ = try registerModule(&mut MODULE_GRAPH, rootId, "storage", "export unsafe static VALUE: u32 = 7;", &mut arena);
7467
            let _ = try registerModule(&mut MODULE_GRAPH, rootId, "app", program, &mut arena);
7468
            let result = try resolveModuleTree(&mut a, rootId);
7469
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7470
        }
7471
    }
7472
}
7473
7474
/// An invalid unsafe static initializer does not grant permission to other initializers.
7475
@test unsafe fn testUnsafeStaticInitializerRestoresContext() throws (testing::TestError) {
7476
    let mut testArena552 = testArena();
7477
    let testStorage552: 'test552 = &mut testArena552 in {
7478
        let mut a = testResolver(testStorage552);
7479
        let result = try resolveProgramStr(&mut a, "unsafe static BAD: u32 = true; static DATA: *[u64] = &[1 as u8] as *[u64];");
7480
        let _ = try expectError(&result);
7481
        try testing::expect(not a.inUnsafeContext);
7482
7483
        let mut testArena553 = testArena();
7484
        let testStorage553: 'test553 = &mut testArena553 in {
7485
            let mut b = testResolver(testStorage553);
7486
            let next = try resolveProgramStr(&mut b, "constant BYTES: *[u8] = \"x\"; unsafe static VALUE: u32 = 7; static DATA: *[u64] = BYTES as *[u64];");
7487
            try expectErrorKind(&next, super::ErrorKind::UnsafeOperation);
7488
        }
7489
    }
7490
}
7491
7492
/// Uninitialized values require an explicit unsafe context in every value position.
7493
@test unsafe fn testUndefinedRequiresUnsafe() throws (testing::TestError) {
7494
    let programs = &[
7495
        "fn run() -> u8 { let pointers: [*u8; 1] = undefined; return *pointers[0]; }",
7496
        "fn run() { let n: u32 = undefined; }",
7497
        "fn run() -> *u8 { return undefined; }",
7498
        "fn take(p: *u8) {} fn run() { take(undefined); }",
7499
        "fn run(p: *u8) { let mut q = p; set q = undefined; }",
7500
        "fn run() { let pointers: [*u8; 1] = [undefined]; }",
7501
        "fn run() { let pointers: [*u8; 2] = [undefined; 2]; }",
7502
        "record R: Copy { p: *u8 } fn run() { let r = R { p: undefined }; }",
7503
        "union U: Copy { Value { p: *u8 } } fn run() { let u = U::Value { p: undefined }; }",
7504
        "static P: *u8 = undefined;",
7505
        "constant P: *u8 = undefined;",
7506
        "static DATA: [u8; 4] = undefined;",
7507
        "record R: Copy { p: *u8 } static VALUE: R = R { p: undefined };",
7508
    ];
7509
    for program in programs {
7510
        let mut testArena554 = testArena();
7511
        let testStorage554: 'test554 = &mut testArena554 in {
7512
            let mut a = testResolver(testStorage554);
7513
            let result = try resolveProgramStr(&mut a, program);
7514
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7515
        }
7516
    }
7517
    try expectAnalyzeOk("unsafe fn run() { let p: *u8 = undefined; }");
7518
    try expectAnalyzeOk("fn run() -> u32 { unsafe { let mut n: u32 = undefined; set n = 7; return n; } }");
7519
    try expectAnalyzeOk("unsafe static P: *u8 = undefined;");
7520
    try expectAnalyzeOk("record R: Copy { p: *u8 } unsafe static VALUE: R = R { p: undefined };");
7521
    try expectAnalyzeOk("fn run() { let data: [u8; 4] = [0; 4]; let pointer: ?*u8 = nil; }");
7522
    try expectAnalyzeOk("static DATA: [u8; 4] = [0; 4];");
7523
}
7524
7525
/// Unsafe initialization does not grant permission to subsequent safe expressions.
7526
@test unsafe fn testUndefinedContextRestored() throws (testing::TestError) {
7527
    let mut testArena555 = testArena();
7528
    let testStorage555: 'test555 = &mut testArena555 in {
7529
        let mut a = testResolver(testStorage555);
7530
        let result = try resolveProgramStr(&mut a, "fn run() { unsafe { let p: *u8 = undefined; } let q: *u8 = undefined; }");
7531
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7532
        let mut testArena556 = testArena();
7533
        let testStorage556: 'test556 = &mut testArena556 in {
7534
            let mut b = testResolver(testStorage556);
7535
            let next = try resolveProgramStr(&mut b, "unsafe static P: *u8 = undefined; static Q: *u8 = undefined;");
7536
            try expectErrorKind(&next, super::ErrorKind::UnsafeOperation);
7537
        }
7538
    }
7539
}
7540
7541
/// Unsafe declarations may compose unsafe operations and calls.
7542
@test unsafe fn testUnsafePointerOperationsAllowed() throws (testing::TestError) {
7543
    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); }";
7544
    try expectAnalyzeOk(program);
7545
}
7546
7547
/// Unsafe code may drop a checked reference to an unsafe pointer.
7548
@test unsafe fn testUnsafePointerFromReference() throws (testing::TestError) {
7549
    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); }";
7550
    try expectAnalyzeOk(program);
7551
}
7552
7553
/// Dropping a reference to an unsafe pointer cannot add mutability.
7554
@test unsafe fn testUnsafePointerCastCannotAddMutability() throws (testing::TestError) {
7555
    let mut testArena557 = testArena();
7556
    let testStorage557: 'test557 = &mut testArena557 in {
7557
        let mut a = testResolver(testStorage557);
7558
        let program = "record Marker: Once {} unsafe fn run(value: &u32) { value as *unsafe mut u32; }";
7559
        let result = try resolveProgramStr(&mut a, program);
7560
        let err = try expectError(&result);
7561
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
7562
            else throw testing::TestError::Failed;
7563
    }
7564
}
7565
7566
/// Recursive cast validation cannot hide a checked-to-unsafe transition.
7567
@test unsafe fn testNestedUnsafePointerCastRejected() throws (testing::TestError) {
7568
    let mut testArena558 = testArena();
7569
    let testStorage558: 'test558 = &mut testArena558 in {
7570
        let mut a = testResolver(testStorage558);
7571
        let program = "record Marker: Once {} fn run(value: **u32) { value as **unsafe u32; }";
7572
        let result = try resolveProgramStr(&mut a, program);
7573
        let err = try expectError(&result);
7574
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
7575
            else throw testing::TestError::Failed;
7576
    }
7577
}
7578
7579
/// Unsafe code may drop a checked slice reference to an unsafe slice.
7580
@test unsafe fn testUnsafeSliceFromReference() throws (testing::TestError) {
7581
    let program = "record Marker: Once {} unsafe fn run(values: &[u32]) { let raw: *unsafe [u32] = values as *unsafe [u32]; }";
7582
    try expectAnalyzeOk(program);
7583
}
7584
7585
/// Slice casts cannot add mutability.
7586
@test unsafe fn testSliceCastCannotAddMutability() throws (testing::TestError) {
7587
    let mut testArena559 = testArena();
7588
    let testStorage559: 'test559 = &mut testArena559 in {
7589
        let mut a = testResolver(testStorage559);
7590
        let program = "record Marker: Once {} fn run(values: &[u32]) { values as &mut [u32]; }";
7591
        let result = try resolveProgramStr(&mut a, program);
7592
        let err = try expectError(&result);
7593
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
7594
            else throw testing::TestError::Failed;
7595
    }
7596
}
7597
7598
/// Mutable unsafe receivers do not create checked exclusive loans.
7599
@test unsafe fn testUnsafeReceiverDoesNotBorrowExclusively() throws (testing::TestError) {
7600
    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); }";
7601
    try expectAnalyzeOk(program);
7602
}
7603
7604
/// Unsafe instance-method attributes enable unsafe operations in the body.
7605
@test unsafe fn testUnsafeInstanceMethodBody() throws (testing::TestError) {
7606
    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; } }";
7607
    try expectAnalyzeOk(program);
7608
}
7609
7610
/// Unsafe instance methods cannot implement safe trait contracts.
7611
@test unsafe fn testUnsafeInstanceMethodSafetyMismatch() throws (testing::TestError) {
7612
    let mut testArena560 = testArena();
7613
    let testStorage560: 'test560 = &mut testArena560 in {
7614
        let mut a = testResolver(testStorage560);
7615
        let program = "record Value {} trait Read { fn (&Read) get(); } instance Read for Value { unsafe fn (value: &Value) get() {} }";
7616
        let result = try resolveProgramStr(&mut a, program);
7617
        try expectErrorKind(&result, super::ErrorKind::TraitMethodSafetyMismatch);
7618
    }
7619
}
7620
7621
/// Unsafe trait methods retain their call-site requirement through dispatch.
7622
@test unsafe fn testUnsafeTraitMethodCallRejected() throws (testing::TestError) {
7623
    let mut testArena561 = testArena();
7624
    let testStorage561: 'test561 = &mut testArena561 in {
7625
        let mut a = testResolver(testStorage561);
7626
        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(); }";
7627
        let result = try resolveProgramStr(&mut a, program);
7628
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7629
    }
7630
}
7631
7632
/// An unsafe callback retains its requirement at an indirect call.
7633
@test unsafe fn testUnsafeCallbackCallRejected() throws (testing::TestError) {
7634
    let mut testArena562 = testArena();
7635
    let testStorage562: 'test562 = &mut testArena562 in {
7636
        let mut a = testResolver(testStorage562);
7637
        let result = try resolveProgramStr(&mut a,
7638
            "fn run(callback: unsafe fn() -> u32) -> u32 { return callback(); }");
7639
        try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
7640
    }
7641
}
7642
7643
/// An unsafe function cannot enter a safe callback slot.
7644
@test unsafe fn testUnsafeCallbackAssignmentRejected() throws (testing::TestError) {
7645
    let mut testArena563 = testArena();
7646
    let testStorage563: 'test563 = &mut testArena563 in {
7647
        let mut a = testResolver(testStorage563);
7648
        let result = try resolveProgramStr(&mut a,
7649
            "unsafe fn load() -> u32 { return 1; } fn run() { let callback: fn() -> u32 = load; }");
7650
        let err = try expectError(&result);
7651
        let case super::ErrorKind::TypeMismatch(_) = err.kind
7652
            else throw testing::TestError::Failed;
7653
    }
7654
}
7655
7656
/// A safe function can enter an unsafe callback slot.
7657
@test unsafe fn testSafeCallbackIntoUnsafeSlot() throws (testing::TestError) {
7658
    try expectAnalyzeOk(
7659
        "fn load() -> u32 { return 1; } unsafe fn run() -> u32 { let callback: unsafe fn() -> u32 = load; return callback(); }");
7660
}
7661
7662
/// Borrowed callback storage must preserve its function safety type.
7663
@test unsafe fn testBorrowedCallbackSafetyInvariant() throws (testing::TestError) {
7664
    let mut testArena564 = testArena();
7665
    let testStorage564: 'test564 = &mut testArena564 in {
7666
        let mut a = testResolver(testStorage564);
7667
        let result = try resolveProgramStr(&mut a,
7668
            "fn replace(slot: &mut unsafe fn()) {} fn load() {} fn run() { let mut callback: fn() = load; replace(&mut callback); }");
7669
        let err = try expectError(&result);
7670
        let case super::ErrorKind::TypeMismatch(_) = err.kind
7671
            else throw testing::TestError::Failed;
7672
    }
7673
}
7674
7675
/// Referenced storage must preserve its exact element type in every context.
7676
@test unsafe fn testPointerStorageCoercionsRejected() throws (testing::TestError) {
7677
    let programs = &[
7678
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; fn run() { let mut p = &DATA; replace(&mut p); }",
7679
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; unsafe fn run() { let mut p = &DATA; replace(&mut p); }",
7680
        "fn replace(p: &mut ?*u8) { set *p = nil; } static DATA: u8 = 7; fn run() { let mut p = &DATA; unsafe { replace(&mut p); } }",
7681
        "fn take(p: *?u32) {} fn run(p: *u32) { take(p); }",
7682
        "unsafe fn take(p: *unsafe mut ?*u8) {} unsafe fn run(p: *unsafe mut *u8) { take(p); }",
7683
        "fn take(p: *[?*u8]) {} fn run(p: *[*u8]) { take(p); }",
7684
        "unsafe fn take(p: *mut [?*u8]) {} unsafe fn run(p: *mut [*u8]) { take(p); }",
7685
        "fn take(p: &mut **u8) {} fn run(p: &mut *mut *u8) { take(p); }",
7686
    ];
7687
    for program in programs {
7688
        let mut testArena565 = testArena();
7689
        let testStorage565: 'test565 = &mut testArena565 in {
7690
            let mut a = testResolver(testStorage565);
7691
            let result = try resolveProgramStr(&mut a, program);
7692
            let err = try expectError(&result);
7693
            let case super::ErrorKind::TypeMismatch(_) = err.kind
7694
                else throw testing::TestError::Failed;
7695
        }
7696
    }
7697
    try expectAnalyzeOk("fn take(p: &mut ?*u8) {} fn run() { let mut p: ?*u8 = nil; take(&mut p); }");
7698
    try expectAnalyzeOk("fn run(p: *mut u8) -> *u8 { return p; }");
7699
    try expectAnalyzeOk("fn run(p: *u8) -> *opaque { return p; }");
7700
}
7701
7702
/// Casts cannot add or remove optionality in referenced storage.
7703
@test unsafe fn testPointerOptionalStorageCastsRejected() throws (testing::TestError) {
7704
    let programs = &[
7705
        "fn run(p: **u8) { p as *?*u8; }",
7706
        "unsafe fn run(p: *mut *u8) { p as *mut ?*u8; }",
7707
        "fn run(p: *mut *u8) { unsafe { p as *mut ?*u8; } }",
7708
        "unsafe fn run(p: *mut ?*u8) { p as *mut *u8; }",
7709
        "unsafe fn run(p: *unsafe mut *u8) { p as *unsafe mut ?*u8; }",
7710
        "unsafe fn run(p: *mut [*u8]) { p as *mut [?*u8]; }",
7711
    ];
7712
    for program in programs {
7713
        let mut testArena566 = testArena();
7714
        let testStorage566: 'test566 = &mut testArena566 in {
7715
            let mut a = testResolver(testStorage566);
7716
            let result = try resolveProgramStr(&mut a, program);
7717
            let err = try expectError(&result);
7718
            let case super::ErrorKind::InvalidAsCast(_) = err.kind
7719
                else throw testing::TestError::Failed;
7720
        }
7721
    }
7722
}
7723
7724
/// Pattern references prevent replacement of their source in every context.
7725
@test unsafe fn testPatternLoanMutationRejected() throws (testing::TestError) {
7726
    let programs = &[
7727
        "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 => {} } }",
7728
        "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 => {} } }",
7729
        "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 => {} } }",
7730
        "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 => {} } }",
7731
        "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; } }",
7732
        "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; } }",
7733
        "union U: Copy { A(u64), B(u64) } fn run(u: *mut U) { match u { case U::A(p) => { let moved = u; *p; } else => {} } }",
7734
        "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 => {} } }",
7735
        "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 => {} } }",
7736
    ];
7737
    for program in programs {
7738
        let mut testArena567 = testArena();
7739
        let testStorage567: 'test567 = &mut testArena567 in {
7740
            let mut a = testResolver(testStorage567);
7741
            let result = try resolveProgramStr(&mut a, program);
7742
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
7743
        }
7744
    }
7745
}
7746
7747
/// Pattern loans end at their scope and permit writes through mutable payload references.
7748
@test unsafe fn testPatternLoanScopeAllowed() throws (testing::TestError) {
7749
    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); }");
7750
    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); }");
7751
    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); }");
7752
}
7753
7754
/// Replacing a borrowed pointer payload cannot forge an address.
7755
@test unsafe fn testBorrowedPointerPayloadReplacementRejected() throws (testing::TestError) {
7756
    let programs = &[
7757
        "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, } }",
7758
        "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, } }",
7759
    ];
7760
    for program in programs {
7761
        let mut testArena568 = testArena();
7762
        let testStorage568: 'test568 = &mut testArena568 in {
7763
            let mut a = testResolver(testStorage568);
7764
            let result = try resolveProgramStr(&mut a, program);
7765
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
7766
        }
7767
    }
7768
}
7769
7770
/// Guards, nested patterns, and unsafe calls must preserve pattern source storage.
7771
@test unsafe fn testPatternLoanIndirectMutationRejected() throws (testing::TestError) {
7772
    let programs = &[
7773
        "fn run() { let mut u: ?u64 = 7; match &u { p => { set u = nil; *p; } else => {} } }",
7774
        "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 => {} } }",
7775
        "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 => {} } }",
7776
        "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 => {} } }",
7777
        "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 => {} } }",
7778
        "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 => {} } }",
7779
    ];
7780
    for program in programs {
7781
        let mut testArena569 = testArena();
7782
        let testStorage569: 'test569 = &mut testArena569 in {
7783
            let mut a = testResolver(testStorage569);
7784
            let result = try resolveProgramStr(&mut a, program);
7785
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("u"));
7786
        }
7787
    }
7788
}
7789
7790
/// Binding mutability does not permit writes through immutable pointers.
7791
@test unsafe fn testMutableBindingImmutableTargetRejected() throws (testing::TestError) {
7792
    let programs = &[
7793
        "record R: Copy { n: u8 } fn run(input: *R) { let mut p = input; set p.n = 1; }",
7794
        "record R: Copy { n: u8 } fn run(input: *R) { let mut p = input; let q = &mut p.n; }",
7795
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; set p[0] = 1; }",
7796
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; set p[..] = 1; }",
7797
        "static DATA: [u8; 1] = [0]; fn run() { let mut p = &DATA; let q = &mut p[0]; }",
7798
        "record R: Copy { n: u8 } fn (r: &mut R) change() { set r.n = 1; } fn run(input: *R) { let mut p = input; p.change(); }",
7799
        "fn run(p: *mut u8, q: *mut u8) { set p = q; }",
7800
    ];
7801
    for program in programs {
7802
        let mut testArena570 = testArena();
7803
        let testStorage570: 'test570 = &mut testArena570 in {
7804
            let mut a = testResolver(testStorage570);
7805
            let result = try resolveProgramStr(&mut a, program);
7806
            try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
7807
        }
7808
    }
7809
}
7810
7811
/// Mutable targets support access through fixed and mutable pointer bindings.
7812
@test unsafe fn testMutablePointerTargetsAllowed() throws (testing::TestError) {
7813
    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; }");
7814
    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; }");
7815
    try expectAnalyzeOk("fn run(first: *u8, second: *u8) { let mut p = first; set p = second; }");
7816
}
7817
7818
/// Pattern access through raw pointers requires an unsafe context.
7819
@test unsafe fn testRawPointerPatternRejected() throws (testing::TestError) {
7820
    let programs = &[
7821
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { match p { case U::A(n) => { *n; } else => {} } }",
7822
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { if let case U::A(n) = p { *n; } }",
7823
        "union U: Copy { A(u8), B } fn run(p: *unsafe U) { while let case U::A(n) = p { *n; break; } }",
7824
        "record R: Copy { n: u8 } fn run(p: *unsafe R) { let case R { n } = p else return; }",
7825
    ];
7826
    for program in programs {
7827
        let mut testArena571 = testArena();
7828
        let testStorage571: 'test571 = &mut testArena571 in {
7829
            let mut a = testResolver(testStorage571);
7830
            let result = try resolveProgramStr(&mut a, program);
7831
            try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
7832
        }
7833
    }
7834
}
7835
7836
/// Unsafe contexts permit pattern access through raw pointers.
7837
@test unsafe fn testRawPointerPatternsAllowed() throws (testing::TestError) {
7838
    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; } }");
7839
    try expectAnalyzeOk("record R: Copy { n: u8 } unsafe fn run(p: *unsafe R) { let case R { n } = p else return; }");
7840
}
7841
7842
/// Slice append requires the allocator layout and callback signature.
7843
@test unsafe fn testSliceAppendAllocatorRejected() throws (testing::TestError) {
7844
    let programs = &[
7845
        "fn run(s: *mut [u8]) { s.append(1, 0); }",
7846
        "record A { ctx: *mut opaque, func: fn(*mut opaque, u32, u32) -> *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
7847
        "record A { func: u64, ctx: u64 } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
7848
        "record A { func: fn(*mut opaque, u64, u32) -> *mut opaque, ctx: *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
7849
        "record A { func: fn(*mut opaque, u32, u32) -> *opaque, ctx: *mut opaque } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
7850
        "record A { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: u64 } fn run(s: *mut [u8], a: A) { s.append(1, a); }",
7851
        "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); }",
7852
    ];
7853
    for program in programs {
7854
        let mut testArena572 = testArena();
7855
        let testStorage572: 'test572 = &mut testArena572 in {
7856
            let mut a = testResolver(testStorage572);
7857
            let result = try resolveProgramStr(&mut a, program);
7858
            try expectErrorKind(&result, super::ErrorKind::InvalidSliceAllocator);
7859
        }
7860
    }
7861
}
7862
7863
/// Slice allocators can use raw context pointers.
7864
@test unsafe fn testSliceAppendRawContextAllowed() throws (testing::TestError) {
7865
    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); }");
7866
}
7867
7868
/// A live pattern reference protects its payload from writes through copied pointers.
7869
@test unsafe fn testPatternPayloadPointerAliasesRejected() throws (testing::TestError) {
7870
    let programs = &[
7871
        "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 => {} } }",
7872
        "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, } }",
7873
        "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; } }",
7874
        "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; } }",
7875
    ];
7876
    for program in programs {
7877
        let mut testArena573 = testArena();
7878
        let testStorage573: 'test573 = &mut testArena573 in {
7879
            let mut a = testResolver(testStorage573);
7880
            let result = try resolveProgramStr(&mut a, program);
7881
            let _ = try expectError(&result);
7882
        }
7883
    }
7884
}
7885
7886
/// Every access to a moved safe mutable pointer is rejected.
7887
@test unsafe fn testMutablePointerMovesRejected() throws (testing::TestError) {
7888
    let programs = &[
7889
        "fn run(p: *mut u8) { let q = p; *p; }",
7890
        "fn run(p: *mut u8) { let q = p; set *p = 1; }",
7891
        "fn run(p: *mut u8) { let q = p; let r = &*p; }",
7892
        "fn read(p: &u8) {} fn run(p: *mut u8) { let q = p; read(p); }",
7893
        "fn run(p: &mut u8) { let q = p; *p; }",
7894
        "fn run(p: *mut [u8]) { let q = p; p.len; }",
7895
        "fn run(p: &mut [u8]) { let q = p; p[0]; }",
7896
        "record R { value: u8 } fn run(p: *mut R) { let q = p; p.value; }",
7897
        "trait T { fn (&T) read(); } fn run(p: *mut opaque T) { let q = p; p.read(); }",
7898
        "fn run(p: *mut u8, flag: bool) { if flag { let q = p; } *p; }",
7899
        "fn run(p: *mut u8) { loop { let q = p; } }",
7900
    ];
7901
    for program in programs {
7902
        let mut testArena574 = testArena();
7903
        let testStorage574: 'test574 = &mut testArena574 in {
7904
            let mut a = testResolver(testStorage574);
7905
            let result = try resolveProgramStr(&mut a, program);
7906
            let _ = try expectError(&result);
7907
        }
7908
    }
7909
}
7910
7911
/// Copy composites cannot contain safe mutable owners or their containers.
7912
@test unsafe fn testCopyMutablePointerFieldsRejected() throws (testing::TestError) {
7913
    let programs = &[
7914
        "record R: Copy { p: *mut u8 }",
7915
        "union U: Copy { A(*mut u8), B }",
7916
        "record R: Copy { p: ?*mut u8 }",
7917
        "record R: Copy { p: [*mut u8; 2] }",
7918
        "record R: Copy { p: *mut [u8] }",
7919
        "trait T {} record R: Copy { p: *mut opaque T }",
7920
        "record Inner { p: *mut u8 } record Outer: Copy { inner: Inner }",
7921
    ];
7922
    for program in programs {
7923
        let mut testArena575 = testArena();
7924
        let testStorage575: 'test575 = &mut testArena575 in {
7925
            let mut a = testResolver(testStorage575);
7926
            let result = try resolveProgramStr(&mut a, program);
7927
            try expectErrorKind(&result, super::ErrorKind::CopyContainsNonCopy);
7928
        }
7929
    }
7930
}
7931
7932
/// Moves transfer safe mutable pointers, and calls can borrow them temporarily.
7933
@test unsafe fn testMutablePointerMovesAllowed() throws (testing::TestError) {
7934
    try expectAnalyzeOk("fn run(p: *mut u8) -> u8 { let q = p; set *q = 1; return *q; }");
7935
    try expectAnalyzeOk("fn setValue(p: &mut u8) { set *p = 1; } fn run(p: *mut u8) { setValue(p); setValue(p); *p; }");
7936
    try expectAnalyzeOk("fn run(p: *u8) { let q = p; *p; *q; }");
7937
    try expectAnalyzeOk("fn run(p: *mut u8, q: *mut u8) { unsafe { p == q; p as u64; } set *p = 1; set *q = 2; }");
7938
    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; }");
7939
    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; }");
7940
}
7941
7942
/// Function signature inspection uses immutable descriptors in safe code.
7943
fn expectImmutableFunctionSignatures 'arena (res: &super::Resolver 'arena, root: *ast::Node) throws (testing::TestError) {
7944
    let first = try typeOf(res, try getBlockStmt(root, 0));
7945
    let equivalent = try typeOf(res, try getBlockStmt(root, 1));
7946
    let throwing = try typeOf(res, try getBlockStmt(root, 2));
7947
    let unsafeCall = try typeOf(res, try getBlockStmt(root, 3));
7948
    try testing::expect(super::typesEqual(first, equivalent));
7949
    try testing::expect(not super::typesEqual(first, throwing));
7950
    try testing::expect(not super::typesEqual(first, unsafeCall));
7951
}
7952
7953
/// Local analysis state does not change function signature identity.
7954
@test unsafe fn testImmutableFunctionSignatures() throws (testing::TestError) {
7955
    let mut testArena576 = testArena();
7956
    let testStorage576: 'test576 = &mut testArena576 in {
7957
        let mut res = testResolver(testStorage576);
7958
        let result = try resolveProgramStr(&mut res,
7959
            "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; }");
7960
        try expectNoErrors(&result);
7961
        try expectImmutableFunctionSignatures(&res, result.root);
7962
    }
7963
}
7964
7965
/// A diagnostic snapshot keeps its contents when the resolver buffer changes.
7966
@test unsafe fn testDiagnosticSnapshotOwnsItsErrors() throws (testing::TestError) {
7967
    let mut testArena577 = testArena();
7968
    let testStorage577: 'test577 = &mut testArena577 in {
7969
        let mut res = testResolver(testStorage577);
7970
        let result = try resolveProgramStr(&mut res, "fn run() { missing; }");
7971
        let snapshot = result.diagnostics;
7972
        let original = super::errorAt(snapshot.errors, 0) else throw testing::TestError::Failed;
7973
        set res.errors.entries[0] = super::Error {
7974
            kind: super::ErrorKind::Internal, node: nil, moduleId: 0,
7975
        };
7976
        let later = super::diagnostics(&mut res);
7977
        try testing::expect(snapshot.errors.len == 1);
7978
        try testing::expect(later.errors.len == 1);
7979
        let first = super::errorAt(snapshot.errors, 0) else throw testing::TestError::Failed;
7980
        try testing::expect(first.kind == original.kind);
7981
        try testing::expect(later.errors[0].kind == super::ErrorKind::Internal);
7982
        try testing::expect(super::errorAt(snapshot.errors, 1) == nil);
7983
    }
7984
}
7985
7986
/// Prefixes, equal fields, and uncertain element locations must conflict.
7987
@test unsafe fn testOverlappingFieldBorrows() throws (testing::TestError) {
7988
    let programs = &[
7989
        "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); }",
7990
        "record R: Copy { a: u32, b: u32 } fn take(a: &mut R, b: &u32) {} fn run(r: &mut R) { take(r, &r.b); }",
7991
        "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]); }",
7992
        "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); }",
7993
    ];
7994
    for program in programs {
7995
        let mut testArena578 = testArena();
7996
        let testStorage578: 'test578 = &mut testArena578 in {
7997
            let mut a = testResolver(testStorage578);
7998
            let result = try resolveProgramStr(&mut a, program);
7999
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8000
        }
8001
    }
8002
}
8003
8004
/// Local loans exclude writes, competing references, and source reads.
8005
@test unsafe fn testLocalReferenceConflicts() throws (testing::TestError) {
8006
    let programs = &[
8007
        "fn run() { let mut n: u32 = 4; let p = &n; set n = 1; }",
8008
        "fn run() { let mut n: u32 = 4; let p = &mut n; n; }",
8009
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &n; }",
8010
        "fn run() { let mut n: u32 = 4; let p = &n; let q = &mut n; }",
8011
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &mut *p; set *p = 1; }",
8012
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &*p; set *p = 1; }",
8013
        "fn take(p: &mut u32) {} fn run() { let mut n: u32 = 4; let p = &n; take(&mut n); }",
8014
        "fn run() { let mut n: u32 = 4; let p = &n; unsafe { set n = 1; } }",
8015
        "fn run() { let mut n: u32 = 4; let p = &mut n; let q = &*p; let moved = p; }",
8016
    ];
8017
    for program in programs {
8018
        let mut testArena579 = testArena();
8019
        let testStorage579: 'test579 = &mut testArena579 in {
8020
            let mut a = testResolver(testStorage579);
8021
            let result = try resolveProgramStr(&mut a, program);
8022
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("n"));
8023
        }
8024
    }
8025
}
8026
8027
/// Reference bindings cannot outlive temporary storage or change their source.
8028
@test unsafe fn testLocalReferenceStorage() throws (testing::TestError) {
8029
    let programs = &[
8030
        "fn f 'r (p: &'r mut u32) { let mut cursor = p; }",
8031
        "unsafe fn f 'r (p: &'r mut u32) { let mut cursor = p; }",
8032
        "fn run() { let n: u32 = 4; let mut p: &u32 = &n; }",
8033
        "record R: Copy { n: u32 } fn make() -> R { return R { n: 4 }; } fn run() { let p: &u32 = &make().n; }",
8034
    ];
8035
    for program in programs {
8036
        let mut testArena580 = testArena();
8037
        let testStorage580: 'test580 = &mut testArena580 in {
8038
            let mut a = testResolver(testStorage580);
8039
            let result = try resolveProgramStr(&mut a, program);
8040
            try expectErrorKind(&result, super::ErrorKind::RefBinding);
8041
        }
8042
    }
8043
}
8044
8045
/// Stored and returned values cannot contain a local reference.
8046
@test unsafe fn testLocalReferenceEscapeRejected() throws (testing::TestError) {
8047
    let programs = &[
8048
        "fn run() -> *u32 { let n: u32 = 1; let p = &n; return p; }",
8049
        "fn run() -> *u32 { let n: u32 = 1; let p = &n; return p as *u32; }",
8050
        "static DATA: u32 = 0; static P: *u32 = &DATA; fn run() { let n: u32 = 1; let p = &n; set P = p; }",
8051
        "record R: Copy { p: *u32 } fn run() { let n: u32 = 1; let p = &n; let r = R { p }; }",
8052
    ];
8053
    for program in programs {
8054
        let mut testArena581 = testArena();
8055
        let testStorage581: 'test581 = &mut testArena581 in {
8056
            let mut a = testResolver(testStorage581);
8057
            let result = try resolveProgramStr(&mut a, program);
8058
            let _ = try expectError(&result);
8059
        }
8060
    }
8061
}
8062
8063
/// Pointer indirection cannot prove that sibling pointees are disjoint.
8064
@test unsafe fn testIndirectFieldBorrowConflict() throws (testing::TestError) {
8065
    let programs = &[
8066
        "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); }",
8067
        "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; }",
8068
    ];
8069
    for program in programs {
8070
        let mut testArena582 = testArena();
8071
        let testStorage582: 'test582 = &mut testArena582 in {
8072
            let mut a = testResolver(testStorage582);
8073
            let result = try resolveProgramStr(&mut a, program);
8074
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8075
        }
8076
    }
8077
}
8078
8079
/// Pattern references protect their field and permit writes to disjoint fields.
8080
@test unsafe fn testDisjointPatternFieldBorrow() throws (testing::TestError) {
8081
    let mut testArena583 = testArena();
8082
    let testStorage583: 'test583 = &mut testArena583 in {
8083
        let mut a = testResolver(testStorage583);
8084
        let result = try resolveProgramStr(&mut a,
8085
            "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 => {} } }");
8086
        try expectErrorKind(&result, super::ErrorKind::BorrowConflict("r"));
8087
    }
8088
}
8089
8090
/// Slice mutations must preserve storage held by a local reference.
8091
@test unsafe fn testLocalReferenceSliceMutationRejected() throws (testing::TestError) {
8092
    let programs = &[
8093
        "fn run(s: *mut [u8]) { let p: &u8 = &s[0]; s.delete(0); }",
8094
        "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); }",
8095
    ];
8096
    for program in programs {
8097
        let mut testArena584 = testArena();
8098
        let testStorage584: 'test584 = &mut testArena584 in {
8099
            let mut a = testResolver(testStorage584);
8100
            let result = try resolveProgramStr(&mut a, program);
8101
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("s"));
8102
        }
8103
    }
8104
}
8105
8106
/// Owner moves and mutable methods cannot invalidate a local loan.
8107
@test unsafe fn testLocalReferenceOwnerMutationRejected() throws (testing::TestError) {
8108
    let programs = &[
8109
        "fn run(p: *mut u32) { let r: &u32 = &*p; let moved = p; }",
8110
        "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(); }",
8111
    ];
8112
    for program in programs {
8113
        let mut testArena585 = testArena();
8114
        let testStorage585: 'test585 = &mut testArena585 in {
8115
            let mut a = testResolver(testStorage585);
8116
            let result = try resolveProgramStr(&mut a, program);
8117
            try expectErrorKind(&result, super::ErrorKind::BorrowConflict("p"));
8118
        }
8119
    }
8120
}
8121
8122
/// Reference locals require a function scope and a reachable initializer result.
8123
@test unsafe fn testLocalReferenceDeclarationContext() throws (testing::TestError) {
8124
    let mut testArena586 = testArena();
8125
    let testStorage586: 'test586 = &mut testArena586 in {
8126
        let mut a = testResolver(testStorage586);
8127
        let result = try resolveProgramStr(&mut a, "let n: u32 = 1; let p: &u32 = &n;");
8128
        try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
8129
    }
8130
}
8131
8132
/// Test-only imports do not require their modules in a normal build.
8133
@test unsafe fn testConditionalUse() throws (testing::TestError) {
8134
    let mut testArena587 = testArena();
8135
    let testStorage587: 'test587 = &mut testArena587 in {
8136
        let mut a = testResolver(testStorage587);
8137
        set a.config.buildTest = false;
8138
        let source = "@test use missing::testing; fn value() -> u32 { return 1; }";
8139
        let result = try resolveProgramStr(&mut a, source);
8140
        try expectNoErrors(&result);
8141
        set a.config.buildTest = true;
8142
        let enabled = try resolveProgramStr(&mut a, source);
8143
        try testing::expect(enabled.diagnostics.errors.len > 0);
8144
    }
8145
}
8146
8147
/// Resolver metadata retains its caller's arena when the context moves.
8148
unsafe fn relocateResolver 'arena (context: super::Resolver 'arena) -> super::Resolver 'arena {
8149
    return context;
8150
}
8151
8152
@test unsafe fn testResolverRelocation() throws (testing::TestError) {
8153
    static DATA: [u8; 65536] = [0; 65536];
8154
    static AST_DATA: [u8; 8192] = [0; 8192];
8155
    static NODES: [super::NodeData; 128] = undefined;
8156
    static ERRORS: [super::Error; 8] = undefined;
8157
    static SCOPE: super::Scope = undefined;
8158
    static POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
8159
    let mut arena = alloc::new(&mut DATA[..]);
8160
    let mut astArena = ast::nodeArena(&mut AST_DATA[..]);
8161
    let root = try! parser::parse(scanner::SourceLoc::String,
8162
        "fn answer() -> u32 { return 42; }", &mut astArena, &mut POOL);
8163
    let storage = super::ResolverStorage {
8164
        nodeData: &mut NODES[..], pkgScope: &mut SCOPE, errors: &mut ERRORS[..],
8165
    };
8166
    let arenaRef: 'arena = &mut arena in {
8167
        let context = super::resolver(arenaRef, storage, super::Config { buildTest: false });
8168
        let initialized = alloc::used(context.arena);
8169
        try testing::expect(initialized > 0);
8170
        let mut moved = relocateResolver(context);
8171
        let diagnostics = try! super::resolveModuleRoot(&mut moved, root);
8172
        try testing::expect(super::success(&diagnostics));
8173
        try testing::expect(alloc::used(moved.arena) > initialized);
8174
        try testing::expect(moved.arena.offset == alloc::used(moved.arena));
8175
        let output = try! alloc::alloc(&mut *moved.arena, @sizeOf(u32), @alignOf(u32)) as *mut u32;
8176
        set *output = 42;
8177
        try testing::expect(*output == 42);
8178
    }
8179
}