lib/std/lang/resolver/tests.rad 223.6 KiB raw
1
//! Resolver tests.
2
3
use std::mem;
4
use std::testing;
5
use std::lang::alloc;
6
use std::lang::ast;
7
use std::lang::parser;
8
use std::lang::scanner;
9
use std::lang::module;
10
use std::lang::strings;
11
12
/// Synthetic file path used for resolver tests.
13
const MODULE_PATH: *[u8] = "/dev/test.rad";
14
15
static AST_ARENA: [u8; 2097152] = undefined;
16
static ARENA_STORAGE: [u8; 2097152] = undefined;
17
static NODE_DATA_STORAGE: [super::NodeData; 256] = undefined;
18
static ERROR_STORAGE: [super::Error; 16] = undefined;
19
static PKG_SCOPE: super::Scope = undefined;
20
static MODULE_ENTRIES: [module::ModuleEntry; 8] = undefined;
21
static MODULE_GRAPH: module::ModuleGraph = undefined;
22
static MODULE_ARENA_STORAGE: [u8; 4096] = undefined;
23
static MODULE_ARENA: ast::NodeArena = undefined;
24
static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
25
26
/// String literals used in tests.
27
const LITERALS: [*[u8]; 15] = [
28
    "Ok", "Error", "R", "S",
29
    "f", "Status", "Pending",
30
    "Some", "None", "First",
31
    "Second", "Opt", "x",
32
    "value", "idx"
33
];
34
35
/// Resolver result with AST, used by test helpers.
36
record TestResult {
37
    diagnostics: super::Diagnostics,
38
    root: *ast::Node,
39
}
40
41
/// Create isolated storage for tests to avoid conflicts with global resolver storage.
42
fn testStorage() -> super::ResolverStorage {
43
    return super::ResolverStorage {
44
        arena: alloc::new(&mut ARENA_STORAGE[..]),
45
        nodeData: &mut NODE_DATA_STORAGE[..],
46
        pkgScope: &mut PKG_SCOPE,
47
        errors: &mut ERROR_STORAGE[..],
48
    };
49
}
50
51
/// Construct a resolver backed by test storage and a synthetic module graph.
52
fn testResolver() -> super::Resolver {
53
    // TODO: This should be initialized only once.
54
    for i in 0..LITERALS.len {
55
        strings::intern(&mut STRING_POOL, LITERALS[i]);
56
    }
57
    // TODO: Use local static for this.
58
    // Reset the module graph for each test.
59
    MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]);
60
    MODULE_GRAPH = module::moduleGraph(&mut MODULE_ENTRIES[..], &mut STRING_POOL, &mut MODULE_ARENA);
61
    let config = super::Config { buildTest: true };
62
    let res = super::resolver(testStorage(), config);
63
64
    return res;
65
}
66
67
/// Resolve a block of statements by wrapping them in a synthetic function.
68
fn resolveStatements(
69
    self: *mut super::Resolver, block: ast::Block, arena: *mut ast::NodeArena
70
) -> TestResult throws (super::ResolveError) {
71
    let module = ast::synthFnModule(arena, super::ANALYZE_BLOCK_FN_NAME, block.statements);
72
    let diagnostics = try super::resolveModuleRoot(self, module.modBody) catch {
73
        return TestResult { diagnostics: super::Diagnostics { errors: self.errors }, root: module.modBody };
74
    };
75
    return TestResult { diagnostics, root: module.fnBody };
76
}
77
78
/// Parse and analyze an expression string for testing.
79
fn resolveExprStr(self: *mut super::Resolver, stmt: *[u8]) -> TestResult throws (testing::TestError) {
80
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
81
    let mut p = parser::mkParser(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL);
82
    parser::advance(&mut p);
83
84
    let expr = try parser::parseExpr(&mut p) catch {
85
        panic "resolveExprStr: parsing failed";
86
    };
87
    let diagnostics = try super::resolveExpr(self, expr, &mut arena) catch {
88
        throw testing::TestError::Failed;
89
    };
90
    return TestResult { diagnostics, root: expr };
91
}
92
93
/// Parse and analyze a module string for testing.
94
/// Use this for code with `fn`, `record`, `union`, etc. at the top level.
95
fn resolveProgramStr(self: *mut super::Resolver, stmt: *[u8]) -> TestResult throws (testing::TestError) {
96
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
97
    let stmt = try parser::parse(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL) catch {
98
        panic "resolveProgramStr: parsing failed";
99
    };
100
    let diagnostics = try super::resolveModuleRoot(self, stmt) catch {
101
        throw testing::TestError::Failed;
102
    };
103
    return TestResult { diagnostics, root: stmt };
104
}
105
106
/// Parse and analyze a block of statements (eg. inside a function body) for testing.
107
/// Use this for code with `let` bindings and expressions, not module-level declarations.
108
fn resolveBlockStr(self: *mut super::Resolver, stmt: *[u8]) -> TestResult throws (testing::TestError) {
109
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
110
    let parsed = try parser::parse(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL) catch {
111
        panic "resolveBlockStr: parsing failed";
112
    };
113
    let case ast::NodeValue::Block(block) = parsed.value
114
        else panic "resolveBlockStr: expected block root";
115
116
    let analysis = try resolveStatements(self, block, &mut arena) catch {
117
        throw testing::TestError::Failed;
118
    };
119
    return TestResult {
120
        diagnostics: analysis.diagnostics,
121
        root: analysis.root,
122
    };
123
}
124
125
/// Resolve a module with the full resolution process.
126
fn resolveModuleTree(
127
    res: *mut super::Resolver,
128
    rootId: u16
129
) -> TestResult throws (testing::TestError) {
130
    let root = module::get(&MODULE_GRAPH, rootId)
131
        else throw testing::TestError::Failed;
132
    let rootAst = root.ast
133
        else throw testing::TestError::Failed;
134
    let packages: *[super::Pkg] = &[super::Pkg {
135
        rootEntry: root,
136
        rootAst,
137
    }];
138
    let diagnostics = try super::resolve(res, &MODULE_GRAPH, packages) catch {
139
        throw testing::TestError::Failed;
140
    };
141
    return TestResult { diagnostics, root: rootAst };
142
}
143
144
/// Register a module in the graph and attach a parsed AST to it.
145
/// If parentId is nil, registers as a root module.
146
fn registerModule(
147
    graph: *mut module::ModuleGraph,
148
    parentId: ?u16,
149
    name: *[u8],
150
    code: *[u8],
151
    arena: *mut ast::NodeArena
152
) -> u16 throws (testing::TestError) {
153
    let filePath = "<test>";
154
    let mut modId: u16 = undefined;
155
    if let parent = parentId {
156
        modId = try module::registerChild(graph, parent, name, filePath) catch {
157
            throw testing::TestError::Failed;
158
        };
159
    } else {
160
        modId = try module::registerRootWithName(graph, 0, name, filePath) catch {
161
            throw testing::TestError::Failed;
162
        };
163
    }
164
    let root = try parser::parse(scanner::SourceLoc::String, code, arena, &mut STRING_POOL) catch {
165
        panic "registerModule: parsing failed";
166
    };
167
    try module::setAst(graph, modId, root) catch {
168
        panic "registerModule: module not found";
169
    };
170
    return modId;
171
}
172
173
/// Ensure an expression statement produces the expected type and return the expression node.
174
fn expectExprStmtType(self: *super::Resolver, node: *ast::Node, expected: super::Type) -> *ast::Node
175
    throws (testing::TestError)
176
{
177
    let case ast::NodeValue::ExprStmt(expr) = node.value
178
        else throw testing::TestError::Failed;
179
    try expectType(self, expr, expected);
180
181
    return expr;
182
}
183
184
/// Assert that the test result contains no diagnostic errors.
185
fn expectNoErrors(r: *TestResult) throws (testing::TestError) {
186
    try testing::expect(super::success(&r.diagnostics));
187
}
188
189
/// Extract the first error from a test result, failing if none exists.
190
fn expectError(result: *TestResult) -> *super::Error throws (testing::TestError) {
191
    let err = super::errorAt(&result.diagnostics.errors[..], 0)
192
        else throw testing::TestError::Failed;
193
    return err;
194
}
195
196
/// Check if two error kinds match.
197
fn errorKindMatches(actual: *super::ErrorKind, expected: super::ErrorKind) -> bool {
198
    if let case super::ErrorKind::DuplicateBinding(expectedName) = expected {
199
        if let case super::ErrorKind::DuplicateBinding(actualName) = *actual {
200
            return mem::eq(actualName, expectedName);
201
        }
202
        return false;
203
    }
204
    if let case super::ErrorKind::UnresolvedSymbol(expectedName) = expected {
205
        if let case super::ErrorKind::UnresolvedSymbol(actualName) = *actual {
206
            return mem::eq(actualName, expectedName);
207
        }
208
        return false;
209
    }
210
    if let case super::ErrorKind::RecordFieldMissing(expectedName) = expected {
211
        if let case super::ErrorKind::RecordFieldMissing(actualName) = *actual {
212
            return mem::eq(actualName, expectedName);
213
        }
214
        return false;
215
    }
216
    if let case super::ErrorKind::RecordFieldUnknown(expectedName) = expected {
217
        if let case super::ErrorKind::RecordFieldUnknown(actualName) = *actual {
218
            return mem::eq(actualName, expectedName);
219
        }
220
        return false;
221
    }
222
    if let case super::ErrorKind::ArrayFieldUnknown(expectedName) = expected {
223
        if let case super::ErrorKind::ArrayFieldUnknown(actualName) = *actual {
224
            return mem::eq(actualName, expectedName);
225
        }
226
        return false;
227
    }
228
    if let case super::ErrorKind::SliceFieldUnknown(expectedName) = expected {
229
        if let case super::ErrorKind::SliceFieldUnknown(actualName) = *actual {
230
            return mem::eq(actualName, expectedName);
231
        }
232
        return false;
233
    }
234
    if let case super::ErrorKind::UnionVariantPayloadMissing(expectedName) = expected {
235
        if let case super::ErrorKind::UnionVariantPayloadMissing(actualName) = *actual {
236
            return mem::eq(actualName, expectedName);
237
        }
238
        return false;
239
    }
240
    if let case super::ErrorKind::UnionVariantPayloadUnexpected(expectedName) = expected {
241
        if let case super::ErrorKind::UnionVariantPayloadUnexpected(actualName) = *actual {
242
            return mem::eq(actualName, expectedName);
243
        }
244
        return false;
245
    }
246
    if let case super::ErrorKind::UnionMatchNonExhaustive(expectedName) = expected {
247
        if let case super::ErrorKind::UnionMatchNonExhaustive(actualName) = *actual {
248
            return mem::eq(actualName, expectedName);
249
        }
250
        return false;
251
    }
252
    if let case super::ErrorKind::MissingTraitMethod(expectedName) = expected {
253
        if let case super::ErrorKind::MissingTraitMethod(actualName) = *actual {
254
            return mem::eq(actualName, expectedName);
255
        }
256
        return false;
257
    }
258
    if let case super::ErrorKind::MissingSupertraitInstance(expectedName) = expected {
259
        if let case super::ErrorKind::MissingSupertraitInstance(actualName) = *actual {
260
            return mem::eq(actualName, expectedName);
261
        }
262
        return false;
263
    }
264
    return *actual == expected;
265
}
266
267
/// Extract the first error and ensure it has the expected kind.
268
fn expectErrorKind(result: *TestResult, kind: super::ErrorKind) -> *super::Error
269
    throws (testing::TestError)
270
{
271
    let err = try expectError(result);
272
    try testing::expect(errorKindMatches(&err.kind, kind));
273
    return err;
274
}
275
276
/// Ensure an expression resolves to the expected type annotation.
277
fn expectType(self: *super::Resolver, expr: *ast::Node, expected: super::Type)
278
    throws (testing::TestError)
279
{
280
    let actual = super::typeFor(self, expr)
281
        else throw testing::TestError::Failed;
282
283
    if actual != expected {
284
        throw testing::TestError::Failed;
285
    }
286
}
287
288
/// Verify that an error represents a specific type mismatch.
289
fn expectTypeMismatch(err: *super::Error, expected: super::Type, actual: super::Type)
290
    throws (testing::TestError)
291
{
292
    let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
293
        else throw testing::TestError::Failed;
294
    try testing::expect(mismatch.expected == expected);
295
    try testing::expect(mismatch.actual == actual);
296
}
297
298
fn expectAnalyzeOk(program: *[u8]) throws (testing::TestError) {
299
    let mut a = testResolver();
300
    let result = try resolveProgramStr(&mut a, program);
301
    try expectNoErrors(&result);
302
}
303
304
fn expectIntMismatch(program: *[u8], expected: super::Type)
305
    throws (testing::TestError)
306
{
307
    let mut a = testResolver();
308
    let result = try resolveProgramStr(&mut a, program);
309
    let err = try expectError(&result);
310
    try expectTypeMismatch(err, expected, super::Type::Int);
311
}
312
313
/// Retrieve the nth statement from a block node.
314
fn getBlockStmt(block: *ast::Node, index: u32) -> *ast::Node
315
    throws (testing::TestError)
316
{
317
    let case ast::NodeValue::Block(body) = block.value
318
        else throw testing::TestError::Failed;
319
320
    if index >= body.statements.len {
321
        throw testing::TestError::Failed;
322
    }
323
    return body.statements[index];
324
}
325
326
/// Retrieve a function body block by function name from the program scope.
327
fn getFnBody(a: *super::Resolver, root: *ast::Node, name: *[u8]) -> ast::Block
328
    throws (testing::TestError)
329
{
330
    let scope = super::scopeFor(a, root)
331
        else throw testing::TestError::Failed;
332
    let sym = super::findSymbolInScope(scope, name)
333
        else throw testing::TestError::Failed;
334
    // Verify it's a value symbol by pattern matching.
335
    let case super::SymbolData::Value { .. } = sym.data
336
        else throw testing::TestError::Failed;
337
338
    let case ast::NodeValue::FnDecl(fnDecl) = sym.node.value
339
        else throw testing::TestError::Failed;
340
341
    let body = fnDecl.body
342
        else throw testing::TestError::Failed;
343
    let case ast::NodeValue::Block(blk) = body.value
344
        else throw testing::TestError::Failed;
345
346
    return blk;
347
}
348
349
/// Get the payload type of a union variant, if it has one.
350
/// For single-field unlabeled variants like `Variant(i32)`, unwraps to return the inner type.
351
fn getUnionVariantPayload(nominalTy: *super::NominalType, variantName: *[u8]) -> super::Type {
352
    let case super::NominalType::Union(unionType) = *nominalTy
353
        else panic "getUnionVariantPayload: not a union";
354
    for i in 0..unionType.variants.len {
355
        if mem::eq(unionType.variants[i].name, variantName) {
356
            let payloadType = unionType.variants[i].valueType;
357
            // Unwrap single-field unlabeled records to get the inner type.
358
            if let case super::Type::Nominal(super::NominalType::Record(recInfo)) = payloadType {
359
                if not recInfo.labeled and recInfo.fields.len == 1 {
360
                    return recInfo.fields[0].fieldType;
361
                }
362
            }
363
            return payloadType;
364
        }
365
    }
366
    panic "getUnionVariantPayload: variant not found";
367
}
368
369
/// Get a nominal type by name, in the scope of the given block node.
370
fn getTypeInScopeOf(a: *super::Resolver, blk: *ast::Node, name: *[u8]) -> *super::NominalType
371
    throws (testing::TestError)
372
{
373
    let scope = super::scopeFor(a, blk)
374
        else throw testing::TestError::Failed;
375
    let sym = super::findSymbolInScope(scope, name)
376
        else throw testing::TestError::Failed;
377
    let case super::SymbolData::Type(ty) = sym.data
378
        else throw testing::TestError::Failed;
379
    return ty;
380
}
381
382
fn typeOf(a: *super::Resolver, node: *ast::Node) -> super::Type
383
    throws (testing::TestError)
384
{
385
    let ty = super::typeFor(a, node)
386
        else throw testing::TestError::Failed;
387
    return ty;
388
}
389
390
fn expectArrayType(ty: super::Type, length: u32) -> super::Type
391
    throws (testing::TestError)
392
{
393
    let case super::Type::Array(info) = ty
394
        else throw testing::TestError::Failed;
395
    try testing::expect(info.length == length);
396
397
    return *info.item;
398
}
399
400
fn expectSliceType(ty: super::Type, mutable: bool) -> super::Type
401
    throws (testing::TestError)
402
{
403
    let case super::Type::Slice { item, mutable: sliceMut } = ty
404
        else throw testing::TestError::Failed;
405
    try testing::expect(sliceMut == mutable);
406
407
    return *item;
408
}
409
410
fn expectPointerType(ty: super::Type, mutable: bool) -> super::Type
411
    throws (testing::TestError)
412
{
413
    let case super::Type::Pointer { target, mutable: ptrMut } = ty
414
        else throw testing::TestError::Failed;
415
    try testing::expect(ptrMut == mutable);
416
417
    return *target;
418
}
419
420
/// Verify that a node has a constant integer value with the expected magnitude.
421
fn expectConstInt(a: *super::Resolver, node: *ast::Node, expected: u32)
422
    throws (testing::TestError)
423
{
424
    let constVal = super::constValueEntry(a, node)
425
        else throw testing::TestError::Failed;
426
427
    let case super::ConstValue::Int(int) = constVal
428
        else throw testing::TestError::Failed;
429
430
    try testing::expect(int.magnitude == expected);
431
}
432
433
/// Resolve an expression that should evaluate to a constant, and verify it equals the expected value.
434
fn resolveAndExpectConstExpr(expr: *[u8], expected: u32)
435
    throws (testing::TestError)
436
{
437
    let mut a = testResolver();
438
    let result = try resolveExprStr(&mut a, expr);
439
    try expectNoErrors(&result);
440
    try expectType(&a, result.root, super::Type::U32);
441
    try expectConstInt(&a, result.root, expected);
442
}
443
444
/// Resolve a statement that should evaluate to a constant, and verify it equals the expected value.
445
fn resolveAndExpectConstStmt(expr: *[u8], expected: u32)
446
    throws (testing::TestError)
447
{
448
    let mut a = testResolver();
449
    let result = try resolveProgramStr(&mut a, expr);
450
    try expectNoErrors(&result);
451
    let stmt = try getBlockStmt(result.root, 1);
452
    let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
453
    try expectConstInt(&a, expr, expected);
454
}
455
456
// Tests ///////////////////////////////////////////////////////////////////////
457
458
@test fn testResolveLit() throws (testing::TestError) {
459
    let mut a = testResolver();
460
    let result = try resolveExprStr(&mut a, "true");
461
462
    try expectNoErrors(&result);
463
    try expectType(&a, result.root, super::Type::Bool);
464
}
465
466
@test fn testResolveStringLiteralType() throws (testing::TestError) {
467
    let mut a = testResolver();
468
    let result = try resolveExprStr(&mut a, "\"hello\"");
469
470
    try expectNoErrors(&result);
471
    let ty = try typeOf(&a, result.root);
472
    let elemTy = try expectSliceType(ty, false);
473
    try testing::expect(elemTy == super::Type::U8);
474
}
475
476
@test fn testResolveAsNumeric() throws (testing::TestError) {
477
    {
478
        let mut a = testResolver();
479
        let result = try resolveExprStr(&mut a, "1 as u32");
480
        try expectNoErrors(&result);
481
        try expectType(&a, result.root, super::Type::U32);
482
    } {
483
        let mut a = testResolver();
484
        let result = try resolveBlockStr(&mut a, "let x: u32 = 913; x as u8;");
485
        try expectNoErrors(&result);
486
487
        let x = try getBlockStmt(result.root, 1);
488
        try expectExprStmtType(&a, x, super::Type::U8);
489
    }
490
}
491
492
@test fn testResolveAsInvalid() throws (testing::TestError) {
493
    let mut a = testResolver();
494
    let result = try resolveProgramStr(&mut a, "true as u32");
495
496
    try expectErrorKind(
497
        &result,
498
        super::ErrorKind::InvalidAsCast(super::InvalidAsCast {
499
            from: super::Type::Bool,
500
            to: super::Type::U32,
501
        })
502
    );
503
}
504
505
@test fn testResolveAsUnionToInt() throws (testing::TestError) {
506
    let mut a = testResolver();
507
    let program = "union Color { Red } Color::Red as u32;";
508
    let result = try resolveProgramStr(&mut a, program);
509
    try expectNoErrors(&result);
510
511
    let red = try getBlockStmt(result.root, 1);
512
    try expectExprStmtType(&a, red, super::Type::U32);
513
}
514
515
@test fn testResolveBinding() throws (testing::TestError) {
516
    let mut a = testResolver();
517
    let result = try resolveBlockStr(&mut a, "let x: bool = true; x;");
518
    let stmt = try parser::tests::getBlockLastStmt(result.root);
519
520
    try expectNoErrors(&result);
521
    try expectType(&a, stmt, super::Type::Void);
522
    try expectExprStmtType(&a, stmt, super::Type::Bool);
523
524
    let case ast::NodeValue::ExprStmt(x) = stmt.value
525
        else throw testing::TestError::Failed;
526
527
    let sym = super::symbolFor(&a, x)
528
        else throw testing::TestError::Failed;
529
    let case super::SymbolData::Value { type: valType, .. } = sym.data
530
        else throw testing::TestError::Failed;
531
    try testing::expect(valType == super::Type::Bool);
532
}
533
534
@test fn testResolveBindingInvalid() throws (testing::TestError) {
535
    let mut a = testResolver();
536
    let result = try resolveBlockStr(&mut a, "let x: i32 = true;");
537
    let err = try expectError(&result);
538
    try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
539
}
540
541
@test fn testResolveDuplicateBinding() throws (testing::TestError) {
542
    let mut a = testResolver();
543
    let result = try resolveBlockStr(&mut a, "let x: bool = true; let x: u8 = 1;");
544
    let stmt = try parser::tests::getBlockLastStmt(result.root);
545
    try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("x"));
546
}
547
548
@test fn testResolveConstLiteralValue() throws (testing::TestError) {
549
    let mut a = testResolver();
550
    let program = "const ANSWER: i32 = 42;";
551
    let result = try resolveProgramStr(&mut a, program);
552
    try expectNoErrors(&result);
553
554
    let constNode = try getBlockStmt(result.root, 0);
555
    let sym = super::symbolFor(&a, constNode)
556
        else throw testing::TestError::Failed;
557
    let case super::SymbolData::Constant { type: constType, .. } = sym.data
558
        else throw testing::TestError::Failed;
559
    try testing::expect(constType == super::Type::I32);
560
}
561
562
@test fn testResolveConstRequiresConstantExpr() throws (testing::TestError) {
563
    let mut a = testResolver();
564
    let program = "fn value() -> i32 { return 1 } fn main() { const ANSWER: i32 = value(); }";
565
    let result = try resolveProgramStr(&mut a, program);
566
    let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
567
568
    let errNode = err.node
569
        else throw testing::TestError::Failed;
570
    let case ast::NodeValue::Call(_) = errNode.value
571
        else throw testing::TestError::Failed;
572
}
573
574
@test fn testResolveStaticLiteralValue() throws (testing::TestError) {
575
    let mut a = testResolver();
576
    let program = "static COUNTER: i32 = 0;";
577
    let result = try resolveProgramStr(&mut a, program);
578
    try expectNoErrors(&result);
579
580
    let staticNode = try getBlockStmt(result.root, 0);
581
    let sym = super::symbolFor(&a, staticNode)
582
        else throw testing::TestError::Failed;
583
    let case super::SymbolData::Value { type: valType, .. } = sym.data
584
        else throw testing::TestError::Failed;
585
    try testing::expect(valType == super::Type::I32);
586
}
587
588
@test fn testResolveStaticRequiresConstantExpr() throws (testing::TestError) {
589
    let mut a = testResolver();
590
    let program = "fn seed() -> i32 { return 1; } static COUNTER: i32 = seed();";
591
    let result = try resolveProgramStr(&mut a, program);
592
    let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
593
594
    let errNode = err.node
595
        else throw testing::TestError::Failed;
596
    let case ast::NodeValue::Call(_) = errNode.value
597
        else throw testing::TestError::Failed;
598
}
599
600
@test fn testSymbolStoresFnAttributes() throws (testing::TestError) {
601
    let mut a = testResolver();
602
    let program = "@default pub fn f() { return; }";
603
    let result = try resolveProgramStr(&mut a, program);
604
    try expectNoErrors(&result);
605
606
    let scope = super::scopeFor(&a, result.root)
607
        else throw testing::TestError::Failed;
608
    let sym = super::findSymbolInScope(scope, "f")
609
        else throw testing::TestError::Failed;
610
611
    try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Pub));
612
    try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Default));
613
    try testing::expectNot(ast::hasAttribute(sym.attrs, ast::Attribute::Extern));
614
}
615
616
@test fn testSymbolStoresRecordAttributes() throws (testing::TestError) {
617
    let mut a = testResolver();
618
    let program = "pub record S { value: i32 }";
619
    let result = try resolveProgramStr(&mut a, program);
620
    try expectNoErrors(&result);
621
622
    let scope = super::scopeFor(&a, result.root)
623
        else throw testing::TestError::Failed;
624
    let sym = super::findSymbolInScope(scope, "S")
625
        else throw testing::TestError::Failed;
626
627
    try testing::expect(ast::hasAttribute(sym.attrs, ast::Attribute::Pub));
628
    try testing::expectNot(ast::hasAttribute(sym.attrs, ast::Attribute::Default));
629
}
630
631
@test fn testDefaultAttributeRejectedOnRecord() throws (testing::TestError) {
632
    let mut a = testResolver();
633
    let program = "@default record T { value: i32 }";
634
    let result = try resolveProgramStr(&mut a, program);
635
    try expectErrorKind(&result, super::ErrorKind::DefaultAttrOnlyOnFn);
636
}
637
638
@test fn testDefaultAttributeRejectedOnUnion() throws (testing::TestError) {
639
    let mut a = testResolver();
640
    let program = "@default union Result { Ok, Err }";
641
    let result = try resolveProgramStr(&mut a, program);
642
    try expectErrorKind(&result, super::ErrorKind::DefaultAttrOnlyOnFn);
643
}
644
645
@test fn testResolveArrayLiteralTyped() throws (testing::TestError) {
646
    let mut a = testResolver();
647
    let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1, 2];");
648
    try expectNoErrors(&result);
649
650
    let stmt = try getBlockStmt(result.root, 0);
651
    let case ast::NodeValue::Let(decl) = stmt.value
652
        else throw testing::TestError::Failed;
653
    let arrayTy = try typeOf(&a, decl.value);
654
    let elemTy = try expectArrayType(arrayTy, 2);
655
    try testing::expect(elemTy == super::Type::I32);
656
}
657
658
@test fn testResolveArrayLiteralElementMismatch() throws (testing::TestError) {
659
    let mut a = testResolver();
660
    let result = try resolveProgramStr(&mut a, "let xs: [bool; 2] = [true, 1];");
661
    let err = try expectError(&result);
662
    try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
663
}
664
665
@test fn testResolveArrayLiteralCannotInfer() throws (testing::TestError) {
666
    let mut a = testResolver();
667
    let result = try resolveProgramStr(&mut a, "let xs = [1, 2];");
668
    try expectErrorKind(&result, super::ErrorKind::CannotInferType);
669
}
670
671
@test fn testResolveArrayLiteralOverflow() throws (testing::TestError) {
672
    let mut a = testResolver();
673
    let result = try resolveProgramStr(&mut a, "let xs: [u8; 2] = [1, 256];");
674
    let err = try expectError(&result);
675
    let case super::ErrorKind::TypeMismatch(_) = err.kind
676
        else throw testing::TestError::Failed;
677
}
678
679
@test fn testResolveArrayLiteralTooFewElements() throws (testing::TestError) {
680
    let mut a = testResolver();
681
    let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1];");
682
    let err = try expectError(&result);
683
    let case super::ErrorKind::TypeMismatch(_) = err.kind
684
        else throw testing::TestError::Failed;
685
}
686
687
@test fn testResolveArrayLiteralTooManyElements() throws (testing::TestError) {
688
    let mut a = testResolver();
689
    let result = try resolveProgramStr(&mut a, "let xs: [i32; 2] = [1, 2, 3];");
690
    let err = try expectError(&result);
691
    let case super::ErrorKind::TypeMismatch(_) = err.kind
692
        else throw testing::TestError::Failed;
693
}
694
695
@test fn testResolveArrayLiteralEmptyWithAnnotation() throws (testing::TestError) {
696
    let mut a = testResolver();
697
    let result = try resolveProgramStr(&mut a, "let xs: [i32; 0] = [];");
698
    try expectNoErrors(&result);
699
}
700
701
@test fn testResolveNestedArrayLiteralTyped() throws (testing::TestError) {
702
    let mut a = testResolver();
703
    let result = try resolveProgramStr(&mut a, "let grid: [[i32; 2]; 2] = [[1, 2], [3, 4]];");
704
    try expectNoErrors(&result);
705
706
    let stmt = try getBlockStmt(result.root, 0);
707
    let case ast::NodeValue::Let(decl) = stmt.value
708
        else throw testing::TestError::Failed;
709
    let gridTy = try typeOf(&a, decl.value);
710
    let rowTy = try expectArrayType(gridTy, 2);
711
    let elemTy = try expectArrayType(rowTy, 2);
712
    try testing::expect(elemTy == super::Type::I32);
713
}
714
715
@test fn testResolveArrayLiteralWithOptionalElems() throws (testing::TestError) {
716
    let mut a = testResolver();
717
    let result = try resolveProgramStr(&mut a, "let xs: [?i32; 2] = [1, 2];");
718
    try expectNoErrors(&result);
719
720
    let stmt = try getBlockStmt(result.root, 0);
721
    let case ast::NodeValue::Let(decl) = stmt.value
722
        else throw testing::TestError::Failed;
723
    let arrayTy = try typeOf(&a, decl.value);
724
    let elemTy = try expectArrayType(arrayTy, 2);
725
    let case super::Type::Optional(inner) = elemTy
726
        else throw testing::TestError::Failed;
727
    try testing::expect(*inner == super::Type::I32);
728
}
729
730
@test fn testResolveArrayLiteralOptionalMismatch() throws (testing::TestError) {
731
    let mut a = testResolver();
732
    let result = try resolveProgramStr(&mut a, "let xs: [?bool; 2] = [1, 2];");
733
    let err = try expectError(&result);
734
    let case super::ErrorKind::TypeMismatch(_) = err.kind
735
        else throw testing::TestError::Failed;
736
}
737
738
@test fn testResolveArrayRepeatBasic() throws (testing::TestError) {
739
    let mut a = testResolver();
740
    let result = try resolveProgramStr(&mut a, "let xs: [i32; 3] = [42; 3];");
741
    try expectNoErrors(&result);
742
743
    let stmt = try getBlockStmt(result.root, 0);
744
    let case ast::NodeValue::Let(decl) = stmt.value
745
        else throw testing::TestError::Failed;
746
    let arrayTy = try typeOf(&a, decl.value);
747
    let elemTy = try expectArrayType(arrayTy, 3);
748
    try testing::expect(elemTy == super::Type::I32);
749
}
750
751
@test fn testResolveArrayRepeatWithExpression() throws (testing::TestError) {
752
    let mut a = testResolver();
753
    let result = try resolveProgramStr(&mut a, "let xs: [i32; 5] = [3 + 2; 5];");
754
    try expectNoErrors(&result);
755
756
    let stmt = try getBlockStmt(result.root, 0);
757
    let case ast::NodeValue::Let(decl) = stmt.value
758
        else throw testing::TestError::Failed;
759
    let arrayTy = try typeOf(&a, decl.value);
760
    let elemTy = try expectArrayType(arrayTy, 5);
761
    try testing::expect(elemTy == super::Type::I32);
762
}
763
764
@test fn testResolveArrayRepeatLiteralArithmetic() throws (testing::TestError) {
765
    let mut a = testResolver();
766
    // `3 * 1` folds to a compile-time constant, so the repeat count is valid.
767
    let result = try resolveProgramStr(&mut a, "let xs: [i32; 3] = [42; 3 * 1];");
768
    try expectNoErrors(&result);
769
}
770
771
@test fn testResolveArrayRepeatNonConstCount() throws (testing::TestError) {
772
    let mut a = testResolver();
773
    // A function call is not a constant expression.
774
    let result = try resolveProgramStr(&mut a, "fn f() -> u32 { return 3; } let xs: [i32; 3] = [42; f()];");
775
    try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
776
}
777
778
@test fn testResolveArrayRepeatCountMismatch() throws (testing::TestError) {
779
    let mut a = testResolver();
780
    let result = try resolveProgramStr(&mut a, "let xs: [i32; 4] = [1; 3];");
781
    let err = try expectError(&result);
782
    let case super::ErrorKind::TypeMismatch(_) = err.kind
783
        else throw testing::TestError::Failed;
784
}
785
786
@test fn testResolveArrayIndex() throws (testing::TestError) {
787
    let mut a = testResolver();
788
    let program = "let xs: [i32; 3] = [1, 2, 3]; xs[1];";
789
    let result = try resolveProgramStr(&mut a, program);
790
    try expectNoErrors(&result);
791
792
    let stmt = try getBlockStmt(result.root, 1);
793
    try expectExprStmtType(&a, stmt, super::Type::I32);
794
}
795
796
@test fn testResolveSliceIndex() throws (testing::TestError) {
797
    let mut a = testResolver();
798
    let program = "let xs: [i32; 4] = [1, 2, 3, 4]; let slice = &xs[1..]; slice[1];";
799
    let result = try resolveProgramStr(&mut a, program);
800
    try expectNoErrors(&result);
801
802
    let sliceStmt = try getBlockStmt(result.root, 1);
803
    let case ast::NodeValue::Let(sliceDecl) = sliceStmt.value
804
        else throw testing::TestError::Failed;
805
    let sliceTy = try typeOf(&a, sliceDecl.value);
806
    let elemTy = try expectSliceType(sliceTy, false);
807
    try testing::expect(elemTy == super::Type::I32);
808
809
    let indexStmt = try getBlockStmt(result.root, 2);
810
    try expectExprStmtType(&a, indexStmt, super::Type::I32);
811
}
812
813
@test fn testResolveSliceFields() throws (testing::TestError) {
814
    let mut a = testResolver();
815
    let program = "let xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[1..]; slice.len; slice.ptr;";
816
    let result = try resolveProgramStr(&mut a, program);
817
    try expectNoErrors(&result);
818
819
    let lenStmt = try getBlockStmt(result.root, 2);
820
    let case ast::NodeValue::ExprStmt(lenExpr) = lenStmt.value
821
        else throw testing::TestError::Failed;
822
    let lenTy = try typeOf(&a, lenExpr);
823
    try testing::expect(lenTy == super::Type::U32);
824
825
    let ptrStmt = try getBlockStmt(result.root, 3);
826
    let case ast::NodeValue::ExprStmt(ptrExpr) = ptrStmt.value
827
        else throw testing::TestError::Failed;
828
    let ptrTy = try typeOf(&a, ptrExpr);
829
    let targetTy = try expectPointerType(ptrTy, false);
830
    try testing::expect(targetTy == super::Type::I32);
831
}
832
833
@test fn testResolveSliceLiteralImmutable() throws (testing::TestError) {
834
    let mut a = testResolver();
835
    let program = "let slice: *[i32] = &[1, 2, 3];";
836
    let result = try resolveProgramStr(&mut a, program);
837
    try expectNoErrors(&result);
838
}
839
840
/// Empty array literal infers element type from slice annotation.
841
@test fn testResolveSliceLiteralEmpty() throws (testing::TestError) {
842
    let mut a = testResolver();
843
    let program = "let slice: *[i32] = &[];";
844
    let result = try resolveProgramStr(&mut a, program);
845
    try expectNoErrors(&result);
846
}
847
848
/// Nested array literal should infer inner element type from slice annotation.
849
@test fn testResolveSliceLiteralNestedArray() throws (testing::TestError) {
850
    let mut a = testResolver();
851
    let program = "let slice: *[[i32; 2]] = &[[1, 2], [3, 4]];";
852
    let result = try resolveProgramStr(&mut a, program);
853
    try expectNoErrors(&result);
854
}
855
856
@test fn testResolveSliceFromArray() throws (testing::TestError) {
857
    {
858
        let mut a = testResolver();
859
        let program = "let xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[..];";
860
        let result = try resolveProgramStr(&mut a, program);
861
        try expectNoErrors(&result);
862
    } {
863
        let mut a = testResolver();
864
        let program = "let xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[0..3];";
865
        let result = try resolveProgramStr(&mut a, program);
866
        try expectNoErrors(&result);
867
    } {
868
        let mut a = testResolver();
869
        let program = "let xs: [i32; 3] = [1, 2, 3]; let slice: *[i32] = &xs[..3];";
870
        let result = try resolveProgramStr(&mut a, program);
871
        try expectNoErrors(&result);
872
    } {
873
        let mut a = testResolver();
874
        let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[1..1];";
875
        let result = try resolveProgramStr(&mut a, program);
876
        try expectNoErrors(&result);
877
    }
878
}
879
880
@test fn testResolveSliceLiteralMutableRequiresMut() throws (testing::TestError) {
881
    let mut a = testResolver();
882
    let program = "let slice: *mut [i32] = &[1, 2, 3];";
883
    let result = try resolveProgramStr(&mut a, program);
884
    let err = try expectError(&result);
885
    let case super::ErrorKind::TypeMismatch(_) = err.kind
886
        else throw testing::TestError::Failed;
887
}
888
889
@test fn testResolveSliceLiteralMutable() throws (testing::TestError) {
890
    let mut a = testResolver();
891
    let program = "let slice: *mut [i32] = &mut [1, 2, 3];";
892
    let result = try resolveProgramStr(&mut a, program);
893
    try expectNoErrors(&result);
894
}
895
896
@test fn testResolvePointerMutableAssignmentRequiresMut() throws (testing::TestError) {
897
    let mut a = testResolver();
898
    let program = "let x: i32 = 0; let ptr: *mut i32 = &x;";
899
    let result = try resolveProgramStr(&mut a, program);
900
    let err = try expectError(&result);
901
    let case super::ErrorKind::TypeMismatch(_) = err.kind
902
        else throw testing::TestError::Failed;
903
}
904
905
@test fn testResolvePointerMutableToImmutableAssignment() throws (testing::TestError) {
906
    let mut a = testResolver();
907
    let program = "let mut x: i32 = 0; let mptr: *mut i32 = &mut x; let ptr: *i32 = mptr;";
908
    let result = try resolveProgramStr(&mut a, program);
909
    try expectNoErrors(&result);
910
}
911
912
@test fn testResolveAddressOfRequiresMutableBinding() throws (testing::TestError) {
913
    {
914
        let mut a = testResolver();
915
        let program = "let x: i32 = 0; let ptr = &mut x;";
916
        let result = try resolveProgramStr(&mut a, program);
917
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
918
    } {
919
        let mut a = testResolver();
920
        let program = "let mut x: i32 = 0; let ptr = &mut x;";
921
        let result = try resolveProgramStr(&mut a, program);
922
        try expectNoErrors(&result);
923
    }
924
}
925
926
@test fn testResolveAddressOfSliceRequiresMutableBinding() throws (testing::TestError) {
927
    {
928
        let mut a = testResolver();
929
        let program = "let xs: [i32; 3] = [1, 2, 3]; let slice = &mut xs[..];";
930
        let result = try resolveProgramStr(&mut a, program);
931
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
932
    } {
933
        let mut a = testResolver();
934
        let program = "let mut xs: [i32; 3] = [1, 2, 3]; let slice = &mut xs[..];";
935
        let result = try resolveProgramStr(&mut a, program);
936
        try expectNoErrors(&result);
937
    }
938
}
939
940
@test fn testResolveSliceCannotAssignToArray() throws (testing::TestError) {
941
    let mut a = testResolver();
942
    let program = "let xs: *[u8] = &[1, 2]; let ys: [u8; 2] = xs;";
943
    let result = try resolveProgramStr(&mut a, program);
944
    let err = try expectError(&result);
945
    let case super::ErrorKind::TypeMismatch(_) = err.kind
946
        else throw testing::TestError::Failed;
947
}
948
949
@test fn testResolveSliceSyntaxRequiresAddressOf() throws (testing::TestError) {
950
    let mut a = testResolver();
951
    let program = "let xs: [u8; 2] = [1, 2]; xs[..];";
952
    let result = try resolveProgramStr(&mut a, program);
953
    try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
954
}
955
956
@test fn testResolveSliceResliceRequiresAddressOf() throws (testing::TestError) {
957
    let mut a = testResolver();
958
    let program = "fn f(s: *[u8]) -> *[u8] { return s[..]; }";
959
    let result = try resolveProgramStr(&mut a, program);
960
    try expectErrorKind(&result, super::ErrorKind::SliceRequiresAddress);
961
}
962
963
@test fn testResolveSliceRangeOutOfBounds() throws (testing::TestError) {
964
    {
965
        let mut a = testResolver();
966
        let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[..3];";
967
        let result = try resolveProgramStr(&mut a, program);
968
        try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
969
    } {
970
        let mut a = testResolver();
971
        let program = "let xs: [u8; 2] = [1, 2]; let slice = &xs[2..];";
972
        let result = try resolveProgramStr(&mut a, program);
973
        try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
974
    } {
975
        let mut a = testResolver();
976
        let program = "let xs: [u8; 4] = [1, 2, 3, 4]; let slice = &xs[3..2];";
977
        let result = try resolveProgramStr(&mut a, program);
978
        try expectErrorKind(&result, super::ErrorKind::SliceRangeOutOfBounds);
979
    }
980
}
981
982
@test fn testResolveArrayLenConstValue() throws (testing::TestError) {
983
    let mut a = testResolver();
984
    let program = "let xs: [i32; 3] = [1, 2, 3]; const LEN: u32 = xs.len;";
985
    let result = try resolveBlockStr(&mut a, program);
986
    try expectNoErrors(&result);
987
988
    let constStmt = try getBlockStmt(result.root, 1);
989
    let case ast::NodeValue::ConstDecl(decl) = constStmt.value
990
        else throw testing::TestError::Failed;
991
    let valueConst = super::constValueEntry(&a, decl.value)
992
        else throw testing::TestError::Failed;
993
    let case super::ConstValue::Int(lenVal) = valueConst
994
        else throw testing::TestError::Failed;
995
    try testing::expect(lenVal.magnitude == 3);
996
    try testing::expect(not lenVal.negative);
997
}
998
999
@test fn testResolveIndexNonIndexable() throws (testing::TestError) {
1000
    let mut a = testResolver();
1001
    let program = "let flag: bool = true; flag[0];";
1002
    let result = try resolveProgramStr(&mut a, program);
1003
    try expectErrorKind(&result, super::ErrorKind::ExpectedIndexable);
1004
}
1005
1006
@test fn testResolveSliceFieldUnknown() throws (testing::TestError) {
1007
    let mut a = testResolver();
1008
    let program = "let xs: [i32; 2] = [1, 2]; (&xs[0..]).unknown;";
1009
    let result = try resolveProgramStr(&mut a, program);
1010
    try expectErrorKind(&result, super::ErrorKind::SliceFieldUnknown("unknown"));
1011
}
1012
1013
@test fn testResolveArrayFieldUnknown() throws (testing::TestError) {
1014
    let mut a = testResolver();
1015
    let program = "let xs: [i32; 2] = [1, 2]; xs.field;";
1016
    let result = try resolveProgramStr(&mut a, program);
1017
    try expectErrorKind(&result, super::ErrorKind::ArrayFieldUnknown("field"));
1018
}
1019
1020
@test fn testResolveIfConditionRequiresBool() throws (testing::TestError) {
1021
    {
1022
        let mut a = testResolver();
1023
        let result = try resolveProgramStr(&mut a, "if 42 {}");
1024
        let err = try expectError(&result);
1025
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1026
    } {
1027
        let mut a = testResolver();
1028
        let result = try resolveProgramStr(&mut a, "if true {}");
1029
        try expectNoErrors(&result);
1030
    }
1031
}
1032
1033
@test fn testResolveIfLetScopeBinding() throws (testing::TestError) {
1034
    let mut a = testResolver();
1035
    let result = try resolveProgramStr(&mut a, "let opt: ?i32 = 42; if let x = opt { x }");
1036
    try expectNoErrors(&result);
1037
1038
    // Get the if-let statement and verify `x` has type `i32`.
1039
    let ifLetStmt = try parser::tests::getBlockLastStmt(result.root);
1040
    let case ast::NodeValue::IfLet(ifLet) = ifLetStmt.value
1041
        else throw testing::TestError::Failed;
1042
1043
    let thenStmt = try parser::tests::getBlockLastStmt(ifLet.thenBranch);
1044
    let case ast::NodeValue::ExprStmt(xExpr) = thenStmt.value
1045
        else throw testing::TestError::Failed;
1046
1047
    try expectType(&a, xExpr, super::Type::I32);
1048
1049
    let scope = super::scopeFor(&a, ifLetStmt)
1050
        else throw testing::TestError::Failed;
1051
    let xSym = super::findSymbolInScope(scope, "x")
1052
        else throw testing::TestError::Failed;
1053
    let case super::SymbolData::Value { type: valType, .. } = xSym.data
1054
        else throw testing::TestError::Failed;
1055
1056
    try testing::expect(valType == super::Type::I32);
1057
}
1058
1059
@test fn testResolveIfLetScopeBindingError() throws (testing::TestError) {
1060
    let mut a = testResolver();
1061
    let result = try resolveProgramStr(&mut a, "let opt: ?i32 = 42; if let x = opt { x } else { x }");
1062
    let err = try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1063
1064
    // Verify the error comes from the else branch (offset 48).
1065
    let errNode = err.node
1066
        else throw testing::TestError::Failed;
1067
    try testing::expect(errNode.span.offset == 48);
1068
}
1069
1070
/// Tests that `if let` with a condition expression binds the variable in scope.
1071
@test fn testResolveIfLetConditionBindsVariable() throws (testing::TestError) {
1072
    let mut a = testResolver();
1073
    let program = "let opt: ?i32 = 42; if let x = opt; x == 1 { x }";
1074
    let result = try resolveProgramStr(&mut a, program);
1075
    try expectNoErrors(&result);
1076
}
1077
1078
@test fn testResolveWhileConditionRequiresBool() throws (testing::TestError) {
1079
    {
1080
        let mut a = testResolver();
1081
        let result = try resolveProgramStr(&mut a, "while 1 {}");
1082
        let err = try expectError(&result);
1083
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1084
    } {
1085
        let mut a = testResolver();
1086
        let result = try resolveProgramStr(&mut a, "while true {}");
1087
        try expectNoErrors(&result);
1088
    }
1089
}
1090
1091
@test fn testResolveWhileLetBindingScope() throws (testing::TestError) {
1092
    {
1093
        let mut a = testResolver();
1094
        let program = "let mut opt: ?i32 = 42; while let x = opt; x > 0 { x; opt; }";
1095
        let result = try resolveProgramStr(&mut a, program);
1096
        try expectNoErrors(&result);
1097
1098
        let whileStmt = try parser::tests::getBlockLastStmt(result.root);
1099
        let case ast::NodeValue::WhileLet(loopNode) = whileStmt.value
1100
            else throw testing::TestError::Failed;
1101
1102
        let bodyStmt = try parser::tests::getBlockFirstStmt(loopNode.body);
1103
        try expectExprStmtType(&a, bodyStmt, super::Type::I32);
1104
1105
        let scope = super::scopeFor(&a, whileStmt)
1106
            else throw testing::TestError::Failed;
1107
        let xSym = super::findSymbolInScope(scope, "x")
1108
            else throw testing::TestError::Failed;
1109
        let case super::SymbolData::Value { type: valType, .. } = xSym.data
1110
            else throw testing::TestError::Failed;
1111
        try testing::expect(valType == super::Type::I32);
1112
    } {
1113
        let mut a = testResolver();
1114
        let program = "let opt: ?i32 = nil; while let x = opt; true { break } else { x }";
1115
        let result = try resolveProgramStr(&mut a, program);
1116
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1117
    }
1118
}
1119
1120
@test fn testResolveForArrayBindsElementType() throws (testing::TestError) {
1121
    let mut a = testResolver();
1122
    let program = "let xs: [i32; 2] = [1, 2]; for x in xs { x; }";
1123
    let result = try resolveProgramStr(&mut a, program);
1124
    try expectNoErrors(&result);
1125
1126
    let forStmt = try parser::tests::getBlockLastStmt(result.root);
1127
    let case ast::NodeValue::For(loopNode) = forStmt.value
1128
        else throw testing::TestError::Failed;
1129
1130
    let scope = super::scopeFor(&a, forStmt)
1131
        else throw testing::TestError::Failed;
1132
    let sym = super::findSymbolInScope(scope, "x")
1133
        else throw testing::TestError::Failed;
1134
    let case super::SymbolData::Value { type: valType, .. } = sym.data
1135
        else throw testing::TestError::Failed;
1136
    try testing::expect(valType == super::Type::I32);
1137
1138
    let bindingTy = super::typeFor(&a, loopNode.binding)
1139
        else throw testing::TestError::Failed;
1140
    try testing::expect(bindingTy == super::Type::I32);
1141
}
1142
1143
@test fn testResolveForIndexedLoopBindsIndex() throws (testing::TestError) {
1144
    let mut a = testResolver();
1145
    let program = "let xs: [bool; 3] = [true; 3]; for value, idx in xs { value; idx; }";
1146
    let result = try resolveProgramStr(&mut a, program);
1147
    try expectNoErrors(&result);
1148
1149
    let forStmt = try parser::tests::getBlockLastStmt(result.root);
1150
    let case ast::NodeValue::For(loopNode) = forStmt.value
1151
        else throw testing::TestError::Failed;
1152
1153
    let scope = super::scopeFor(&a, forStmt)
1154
        else throw testing::TestError::Failed;
1155
    let valueSym = super::findSymbolInScope(scope, "value")
1156
        else throw testing::TestError::Failed;
1157
    let case super::SymbolData::Value { type: valueValType, .. } = valueSym.data
1158
        else throw testing::TestError::Failed;
1159
    try testing::expect(valueValType == super::Type::Bool);
1160
    let indexSym = super::findSymbolInScope(scope, "idx")
1161
        else throw testing::TestError::Failed;
1162
    let case super::SymbolData::Value { type: indexValType, .. } = indexSym.data
1163
        else throw testing::TestError::Failed;
1164
    try testing::expect(indexValType == super::Type::U32);
1165
1166
    let indexNode = loopNode.index
1167
        else throw testing::TestError::Failed;
1168
    let indexTy = super::typeFor(&a, indexNode)
1169
        else throw testing::TestError::Failed;
1170
    try testing::expect(indexTy == super::Type::U32);
1171
}
1172
1173
@test fn testResolveForSliceIterable() throws (testing::TestError) {
1174
    let mut a = testResolver();
1175
    let program = "let xs: [i32; 3] = [1, 2, 3]; for x in &xs[..] { x; }";
1176
    let result = try resolveProgramStr(&mut a, program);
1177
    try expectNoErrors(&result);
1178
1179
    let forStmt = try parser::tests::getBlockLastStmt(result.root);
1180
    let case ast::NodeValue::For(loopNode) = forStmt.value
1181
        else throw testing::TestError::Failed;
1182
1183
    let bindingTy = super::typeFor(&a, loopNode.binding)
1184
        else throw testing::TestError::Failed;
1185
    try testing::expect(bindingTy == super::Type::I32);
1186
}
1187
1188
@test fn testResolveForRequiresIterable() throws (testing::TestError) {
1189
    let mut a = testResolver();
1190
    let result = try resolveProgramStr(&mut a, "for x in true { x; }");
1191
    try expectErrorKind(&result, super::ErrorKind::ExpectedIterable);
1192
}
1193
1194
@test fn testResolveForRangeBoundsMustNumeric() throws (testing::TestError) {
1195
    let mut a = testResolver();
1196
    let result = try resolveBlockStr(&mut a, "for i in 0..true { i; }");
1197
    try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
1198
}
1199
1200
@test fn testResolveMatchPatternTypeMismatch() throws (testing::TestError) {
1201
    let mut a = testResolver();
1202
    let program = "let val: i32 = 0; match val { case true => {} }";
1203
    let result = try resolveProgramStr(&mut a, program);
1204
    let err = try expectError(&result);
1205
    try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
1206
}
1207
1208
@test fn testResolveMatchUnionVariantTypeMismatch() throws (testing::TestError) {
1209
    let mut a = testResolver();
1210
    let program = "union First { A }  union Second { B } fn run(val: First) { match val { case Second::B => {} } }";
1211
    let result = try resolveProgramStr(&mut a, program);
1212
    let err = try expectError(&result);
1213
1214
    let firstTy = try getTypeInScopeOf(&a, result.root, "First");
1215
    let secondTy = try getTypeInScopeOf(&a, result.root, "Second");
1216
    try expectTypeMismatch(err, super::Type::Nominal(firstTy), super::Type::Nominal(secondTy));
1217
}
1218
1219
@test fn testResolveMatchUnionPayloadMissing() throws (testing::TestError) {
1220
    let mut a = testResolver();
1221
    let program = "union Opt { Some(i32) } fn run(val: Opt) { match val { case Opt::Some => {} } }";
1222
    let result = try resolveProgramStr(&mut a, program);
1223
    try expectErrorKind(&result, super::ErrorKind::UnionVariantPayloadMissing("Some"));
1224
}
1225
1226
@test fn testResolveMatchUnionVoidVariantExplicitDiscriminant() throws (testing::TestError) {
1227
    let mut a = testResolver();
1228
    let program = "union Opt { Some = 5 } fn run(val: Opt) { match val { case Opt::Some => {} } }";
1229
    let result = try resolveProgramStr(&mut a, program);
1230
    try expectNoErrors(&result);
1231
}
1232
1233
@test fn testResolveMatchUnionPayloadUnexpected() throws (testing::TestError) {
1234
    let mut a = testResolver();
1235
    let program = "union Opt { None } fn run(val: Opt) { match val { case Opt::None(x) => {} } }";
1236
    let result = try resolveProgramStr(&mut a, program);
1237
    try expectErrorKind(&result, super::ErrorKind::UnionVariantPayloadUnexpected("None"));
1238
}
1239
1240
@test fn testResolveMatchUnionUnknownVariant() throws (testing::TestError) {
1241
    let mut a = testResolver();
1242
    let program = "union Opt { Some, None } fn run(value: Opt) { match value { case Opt::Unknown => {} } }";
1243
    let result = try resolveProgramStr(&mut a, program);
1244
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
1245
}
1246
1247
@test fn testResolveMatchUnionNonExhaustive() throws (testing::TestError) {
1248
    {
1249
        let mut a = testResolver();
1250
        let program = "union Opt { Some, None } fn run(value: Opt) { match value { case Opt::Some => {} } }";
1251
        let result = try resolveProgramStr(&mut a, program);
1252
        try expectErrorKind(&result, super::ErrorKind::UnionMatchNonExhaustive("None"));
1253
    } {
1254
        let mut a = testResolver();
1255
        let program = "union Opt { Some, None } fn run(value: Opt) { match value { else => {} } }";
1256
        let result = try resolveProgramStr(&mut a, program);
1257
        try expectNoErrors(&result);
1258
    }
1259
}
1260
1261
@test fn testResolveMatchUnionNonExhaustiveExplicitDiscriminants() throws (testing::TestError) {
1262
    let mut a = testResolver();
1263
    let program = "union U { A = 3, B = 9 } fn run(value: U) { match value { case U::A => {}, case U::B => {} } }";
1264
    let result = try resolveProgramStr(&mut a, program);
1265
    try expectNoErrors(&result);
1266
}
1267
1268
@test fn testResolveMatchUnionBindingScope() throws (testing::TestError) {
1269
    let mut a = testResolver();
1270
    let program = "union Opt { Some(i32), None } fn f(value: Opt) { match value { case Opt::Some(x) if x > 0 => { x; } else => {} } }";
1271
    let result = try resolveProgramStr(&mut a, program);
1272
    try expectNoErrors(&result);
1273
1274
    let fnBlock = try getFnBody(&a, result.root, "f");
1275
    try testing::expect(fnBlock.statements.len > 0);
1276
1277
    let matchNode = fnBlock.statements[0];
1278
    let case ast::NodeValue::Match(sw) = matchNode.value
1279
        else throw testing::TestError::Failed;
1280
    let caseNode = sw.prongs[0];
1281
1282
    let scope = super::scopeFor(&a, caseNode)
1283
        else throw testing::TestError::Failed;
1284
    let payloadSym = super::findSymbolInScope(scope, "x")
1285
        else throw testing::TestError::Failed;
1286
    let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
1287
        else throw testing::TestError::Failed;
1288
    try testing::expect(payloadValType == super::Type::I32);
1289
}
1290
1291
@test fn testResolveMatchUnionPatternNonUnionType() throws (testing::TestError) {
1292
    let mut a = testResolver();
1293
    let program = "union Opt { Some, None } fn f(value: Opt) { match value { case true => {} } }";
1294
    let result = try resolveProgramStr(&mut a, program);
1295
    let err = try expectError(&result);
1296
    let optionTy = try getTypeInScopeOf(&a, result.root, "Opt");
1297
    try expectTypeMismatch(err, super::Type::Nominal(optionTy), super::Type::Bool);
1298
}
1299
1300
@test fn testResolveMatchGuardForms() throws (testing::TestError) {
1301
    let mut a = testResolver();
1302
    let program = "fn first(value: i32) { match value { case _ if true => {}, else => {} } }";
1303
    let result = try resolveProgramStr(&mut a, program);
1304
    try expectNoErrors(&result);
1305
}
1306
1307
/// Test that a binding prong binds the subject to the identifier.
1308
@test fn testResolveMatchBindingProng() throws (testing::TestError) {
1309
    let mut a = testResolver();
1310
    let program = "fn f(value: i32) -> i32 { match value { x => return x } }";
1311
    let result = try resolveProgramStr(&mut a, program);
1312
    try expectNoErrors(&result);
1313
}
1314
1315
/// Test that a binding prong with guard can use the bound variable.
1316
@test fn testResolveMatchBindingProngGuard() throws (testing::TestError) {
1317
    let mut a = testResolver();
1318
    let program = "fn f(value: i32) -> i32 { match value { x if x > 0 => return x, _ => return 0 } }";
1319
    let result = try resolveProgramStr(&mut a, program);
1320
    try expectNoErrors(&result);
1321
}
1322
1323
/// Test that a binding prong covers all union variants for exhaustiveness.
1324
@test fn testResolveMatchBindingProngExhaustive() throws (testing::TestError) {
1325
    let mut a = testResolver();
1326
    let program = "union U { A, B, C } fn f(u: U) -> i32 { match u { x => return 0 } }";
1327
    let result = try resolveProgramStr(&mut a, program);
1328
    try expectNoErrors(&result);
1329
}
1330
1331
/// Test that `case x =>` fails if `x` is not in scope, since bare identifiers
1332
/// in case patterns are values to compare against, not bindings.
1333
@test fn testResolveMatchCaseUndefinedIdent() throws (testing::TestError) {
1334
    let mut a = testResolver();
1335
    let program = "fn f(n: i32) -> i32 { match n { case x => return 0 } }";
1336
    let result = try resolveProgramStr(&mut a, program);
1337
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1338
}
1339
1340
/// Test matching on optionals: exhaustiveness and type unwrapping.
1341
@test fn testResolveMatchOptional() throws (testing::TestError) {
1342
    {
1343
        // Exhaustive: binding + nil case.
1344
        let mut a = testResolver();
1345
        let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {} } }";
1346
        let result = try resolveProgramStr(&mut a, program);
1347
        try expectNoErrors(&result);
1348
    } {
1349
        // Missing nil case.
1350
        let mut a = testResolver();
1351
        let program = "fn f(opt: ?i32) { match opt { v => {} } }";
1352
        let result = try resolveProgramStr(&mut a, program);
1353
        try expectErrorKind(&result, super::ErrorKind::OptionalMatchMissingNil);
1354
    } {
1355
        // Missing value case.
1356
        let mut a = testResolver();
1357
        let program = "fn f(opt: ?i32) { match opt { case nil => {} } }";
1358
        let result = try resolveProgramStr(&mut a, program);
1359
        try expectErrorKind(&result, super::ErrorKind::OptionalMatchMissingValue);
1360
    } {
1361
        // Else covers both cases.
1362
        let mut a = testResolver();
1363
        let program = "fn f(opt: ?i32) { match opt { else => {} } }";
1364
        let result = try resolveProgramStr(&mut a, program);
1365
        try expectNoErrors(&result);
1366
    } {
1367
        // Binding unwraps the inner type.
1368
        let mut a = testResolver();
1369
        let program = "fn f(opt: ?i32) -> i32 { match opt { v => return v + 1, case nil => return 0 } }";
1370
        let result = try resolveProgramStr(&mut a, program);
1371
        try expectNoErrors(&result);
1372
    }
1373
}
1374
1375
/// Test that match on non-union types requires exhaustiveness.
1376
@test fn testResolveMatchGenericExhaustive() throws (testing::TestError) {
1377
    {
1378
        // Match on i32 without catch-all should error.
1379
        let mut a = testResolver();
1380
        let program = "fn f(x: i32) { match x { case 1 => {} } }";
1381
        let result = try resolveProgramStr(&mut a, program);
1382
        try expectErrorKind(&result, super::ErrorKind::MatchNonExhaustive);
1383
    } {
1384
        // Match on i32 with else is fine.
1385
        let mut a = testResolver();
1386
        let program = "fn f(x: i32) { match x { case 1 => {}, else => {} } }";
1387
        let result = try resolveProgramStr(&mut a, program);
1388
        try expectNoErrors(&result);
1389
    } {
1390
        // Match on i32 with binding catch-all is fine.
1391
        let mut a = testResolver();
1392
        let program = "fn f(x: i32) { match x { y => {} } }";
1393
        let result = try resolveProgramStr(&mut a, program);
1394
        try expectNoErrors(&result);
1395
    } {
1396
        // Match on i32 with wildcard catch-all is fine.
1397
        let mut a = testResolver();
1398
        let program = "fn f(x: i32) { match x { case _ => {} } }";
1399
        let result = try resolveProgramStr(&mut a, program);
1400
        try expectNoErrors(&result);
1401
    }
1402
}
1403
1404
/// Test that match on bool requires both true and false cases.
1405
@test fn testResolveMatchBoolExhaustive() throws (testing::TestError) {
1406
    {
1407
        // Match on bool with both cases is fine.
1408
        let mut a = testResolver();
1409
        let program = "fn f(x: bool) { match x { case true => {}, case false => {} } }";
1410
        let result = try resolveProgramStr(&mut a, program);
1411
        try expectNoErrors(&result);
1412
    } {
1413
        // Match on bool missing true should error.
1414
        let mut a = testResolver();
1415
        let program = "fn f(x: bool) { match x { case false => {} } }";
1416
        let result = try resolveProgramStr(&mut a, program);
1417
        try expectErrorKind(&result, super::ErrorKind::BoolMatchMissing(true));
1418
    } {
1419
        // Match on bool missing false should error.
1420
        let mut a = testResolver();
1421
        let program = "fn f(x: bool) { match x { case true => {} } }";
1422
        let result = try resolveProgramStr(&mut a, program);
1423
        try expectErrorKind(&result, super::ErrorKind::BoolMatchMissing(false));
1424
    } {
1425
        // Match on bool with else is fine.
1426
        let mut a = testResolver();
1427
        let program = "fn f(x: bool) { match x { else => {} } }";
1428
        let result = try resolveProgramStr(&mut a, program);
1429
        try expectNoErrors(&result);
1430
    } {
1431
        // Match on bool with binding catch-all is fine.
1432
        let mut a = testResolver();
1433
        let program = "fn f(x: bool) { match x { b => {} } }";
1434
        let result = try resolveProgramStr(&mut a, program);
1435
        try expectNoErrors(&result);
1436
    }
1437
}
1438
1439
@test fn testResolveBreakRequiresLoop() throws (testing::TestError) {
1440
    {
1441
        let mut a = testResolver();
1442
        let result = try resolveProgramStr(&mut a, "break;");
1443
        try expectErrorKind(&result, super::ErrorKind::InvalidLoopControl);
1444
    } {
1445
        let mut a = testResolver();
1446
        let result = try resolveProgramStr(&mut a, "loop { break }");
1447
        try expectNoErrors(&result);
1448
    }
1449
}
1450
1451
@test fn testResolveContinueRequiresLoop() throws (testing::TestError) {
1452
    {
1453
        let mut a = testResolver();
1454
        let result = try resolveProgramStr(&mut a, "continue;");
1455
        try expectErrorKind(&result, super::ErrorKind::InvalidLoopControl);
1456
    } {
1457
        let mut a = testResolver();
1458
        let result = try resolveProgramStr(&mut a, "while true { continue }");
1459
        try expectNoErrors(&result);
1460
    }
1461
}
1462
1463
@test fn testResolveFnTypeVoidNoParams() throws (testing::TestError) {
1464
    let mut a = testResolver();
1465
    let result = try resolveProgramStr(&mut a, "fn f() {} f();");
1466
    try expectNoErrors(&result);
1467
1468
    let blockNode = result.root;
1469
    let case ast::NodeValue::Block(block) = blockNode.value
1470
        else throw testing::TestError::Failed;
1471
    let fnNode = try getBlockStmt(blockNode, 0);
1472
    let callStmt = try getBlockStmt(blockNode, 1);
1473
1474
    { // Verify the function symbol captures an empty parameter list and void return.
1475
        let sym = super::symbolFor(&a, fnNode)
1476
            else throw testing::TestError::Failed;
1477
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
1478
            else throw testing::TestError::Failed;
1479
        try testing::expect(fnTy.paramTypes.len == 0);
1480
        try testing::expect(*fnTy.returnType == super::Type::Void);
1481
    }
1482
    { // Checking that the type of the call matches the function return type.
1483
        let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
1484
1485
        let fnSym = super::symbolFor(&a, fnNode)
1486
            else throw testing::TestError::Failed;
1487
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
1488
            else throw testing::TestError::Failed;
1489
        try expectType(&a, callExpr, *fnTy.returnType);
1490
    }
1491
}
1492
1493
@test fn testResolveFnTypeReturnsValue() throws (testing::TestError) {
1494
    let mut a = testResolver();
1495
    let program = "fn f() -> i32 { return 1; } f();";
1496
    let result = try resolveProgramStr(&mut a, program);
1497
    try expectNoErrors(&result);
1498
1499
    let blockNode = result.root;
1500
    let case ast::NodeValue::Block(block) = blockNode.value
1501
        else throw testing::TestError::Failed;
1502
    let fnNode = try getBlockStmt(blockNode, 0);
1503
    let callStmt = try getBlockStmt(blockNode, 1);
1504
1505
    { // Function returns i32 with no parameters.
1506
        let sym = super::symbolFor(&a, fnNode)
1507
            else throw testing::TestError::Failed;
1508
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
1509
            else throw testing::TestError::Failed;
1510
        try testing::expect(fnTy.paramTypes.len == 0);
1511
        try testing::expect(*fnTy.returnType == super::Type::I32);
1512
    }
1513
    { // Call expression should inherit the function's return type.
1514
        let callExpr = try expectExprStmtType(&a, callStmt, super::Type::I32);
1515
1516
        let fnSym = super::symbolFor(&a, fnNode)
1517
            else throw testing::TestError::Failed;
1518
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
1519
            else throw testing::TestError::Failed;
1520
        try expectType(&a, callExpr, *fnTy.returnType);
1521
    }
1522
}
1523
1524
@test fn testResolveFnTypeSingleParam() throws (testing::TestError) {
1525
    let mut a = testResolver();
1526
    let program = "fn f(x: i8) {} let x: i8 = 1; f(x);";
1527
    let result = try resolveProgramStr(&mut a, program);
1528
    try expectNoErrors(&result);
1529
1530
    let blockNode = result.root;
1531
    let case ast::NodeValue::Block(block) = blockNode.value
1532
        else throw testing::TestError::Failed;
1533
    let fnNode = try getBlockStmt(blockNode, 0);
1534
    let callStmt = try getBlockStmt(blockNode, 2);
1535
1536
    { // Single parameter propagates nominal type onto the symbol and parameter node.
1537
        let sym = super::symbolFor(&a, fnNode)
1538
            else throw testing::TestError::Failed;
1539
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
1540
            else throw testing::TestError::Failed;
1541
        try testing::expect(fnTy.paramTypes.len == 1);
1542
        try testing::expect(*fnTy.paramTypes[0] == super::Type::I8);
1543
        try testing::expect(*fnTy.returnType == super::Type::Void);
1544
1545
        let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
1546
            else throw testing::TestError::Failed;
1547
        try testing::expect(fnDecl.sig.params.len == 1);
1548
1549
        let paramNode = fnDecl.sig.params[0];
1550
        try expectType(&a, paramNode, super::Type::I8);
1551
    }
1552
    { // Call should resolve to void, matching the function's return type.
1553
        let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
1554
        let fnSym = super::symbolFor(&a, fnNode)
1555
            else throw testing::TestError::Failed;
1556
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
1557
            else throw testing::TestError::Failed;
1558
        try expectType(&a, callExpr, *fnTy.returnType);
1559
    }
1560
}
1561
1562
@test fn testResolveFnTypeMultipleParams() throws (testing::TestError) {
1563
    let mut a = testResolver();
1564
    let program = "fn f(x: i8, y: i32) {} let x: i8 = 1; let y: i32 = 2; f(x, y);";
1565
    let result = try resolveProgramStr(&mut a, program);
1566
    try expectNoErrors(&result);
1567
1568
    let blockNode = result.root;
1569
    let case ast::NodeValue::Block(block) = blockNode.value
1570
        else throw testing::TestError::Failed;
1571
    let fnNode = try getBlockStmt(blockNode, 0);
1572
    let callStmt = try getBlockStmt(blockNode, 3);
1573
1574
    { // Ensure multi-parameter signatures record both argument types.
1575
        let sym = super::symbolFor(&a, fnNode)
1576
            else throw testing::TestError::Failed;
1577
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
1578
            else throw testing::TestError::Failed;
1579
        try testing::expect(fnTy.paramTypes.len == 2);
1580
        try testing::expect(*fnTy.paramTypes[0] == super::Type::I8);
1581
        try testing::expect(*fnTy.paramTypes[1] == super::Type::I32);
1582
        try testing::expect(*fnTy.returnType == super::Type::Void);
1583
1584
        let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
1585
            else throw testing::TestError::Failed;
1586
        try testing::expect(fnDecl.sig.params.len == 2);
1587
1588
        let firstParam = fnDecl.sig.params[0];
1589
        let secondParam = fnDecl.sig.params[1];
1590
        try expectType(&a, firstParam, super::Type::I8);
1591
        try expectType(&a, secondParam, super::Type::I32);
1592
    }
1593
    { // Call expression should again mirror the function return type.
1594
        let callExpr = try expectExprStmtType(&a, callStmt, super::Type::Void);
1595
        let fnSym = super::symbolFor(&a, fnNode)
1596
            else throw testing::TestError::Failed;
1597
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = fnSym.data
1598
            else throw testing::TestError::Failed;
1599
        try expectType(&a, callExpr, *fnTy.returnType);
1600
    }
1601
}
1602
1603
@test fn testResolveFnRecursiveCall() throws (testing::TestError) {
1604
    let mut a = testResolver();
1605
    let program = "fn flip(b: bool) -> bool { if b { return false; } return flip(false); }";
1606
    let result = try resolveProgramStr(&mut a, program);
1607
    try expectNoErrors(&result);
1608
1609
    let blockNode = result.root;
1610
    let case ast::NodeValue::Block(block) = blockNode.value
1611
        else throw testing::TestError::Failed;
1612
    let fnNode = try getBlockStmt(blockNode, 0);
1613
1614
    { // Function symbol should be visible for recursive calls within its own body.
1615
        let sym = super::symbolFor(&a, fnNode)
1616
            else throw testing::TestError::Failed;
1617
        let case super::SymbolData::Value { type: super::Type::Fn(fnTy), .. } = sym.data
1618
            else throw testing::TestError::Failed;
1619
        try testing::expect(fnTy.paramTypes.len == 1);
1620
        try testing::expect(*fnTy.paramTypes[0] == super::Type::Bool);
1621
        try testing::expect(*fnTy.returnType == super::Type::Bool);
1622
    }
1623
}
1624
1625
@test fn testResolveFnCallMissingArgument() throws (testing::TestError) {
1626
    let mut a = testResolver();
1627
    let program = "fn f(x: i8) {} f();";
1628
    let result = try resolveProgramStr(&mut a, program);
1629
    // Expect an error when a required parameter is omitted.
1630
    try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
1631
        expected: 1,
1632
        actual: 0,
1633
    }));
1634
}
1635
1636
@test fn testResolveFnCallExtraArgument() throws (testing::TestError) {
1637
    let mut a = testResolver();
1638
    let program = "fn f() {} f(1);";
1639
    let result = try resolveProgramStr(&mut a, program);
1640
    // Passing more arguments than declared should fail.
1641
    try expectErrorKind(&result, super::ErrorKind::FnArgCountMismatch(super::CountMismatch {
1642
        expected: 0,
1643
        actual: 1,
1644
    }));
1645
}
1646
1647
@test fn testResolveFnCallArgumentTypeMismatch() throws (testing::TestError) {
1648
    let mut a = testResolver();
1649
    let program = "fn f(x: i8) {} f(true);";
1650
    let result = try resolveProgramStr(&mut a, program);
1651
    let err = try expectError(&result);
1652
    // The argument type (bool) should not match the parameter type (i8).
1653
    try expectTypeMismatch(err, super::Type::I8, super::Type::Bool);
1654
}
1655
1656
@test fn testResolveFnReturnTypeMismatch() throws (testing::TestError) {
1657
    let mut a = testResolver();
1658
    let program = "fn f() -> i32 { return true; }";
1659
    let result = try resolveProgramStr(&mut a, program);
1660
    let err = try expectError(&result);
1661
    try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
1662
}
1663
1664
@test fn testResolveFnReturnVoid() throws (testing::TestError) {
1665
    {
1666
        let mut a = testResolver();
1667
        let result = try resolveProgramStr(&mut a, "fn f() { return; }");
1668
        try expectNoErrors(&result);
1669
    } {
1670
        let mut a = testResolver();
1671
        let result = try resolveProgramStr(&mut a, "fn g() -> i32 { return; }");
1672
        let err = try expectError(&result);
1673
        try expectTypeMismatch(err, super::Type::I32, super::Type::Void);
1674
    }
1675
}
1676
1677
@test fn testResolveFnMissingReturn() throws (testing::TestError) {
1678
    {
1679
        let mut a = testResolver();
1680
        let result = try resolveProgramStr(&mut a, "fn f() -> i32 {}");
1681
        try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
1682
    } {
1683
        let mut a = testResolver();
1684
        let program = "fn g(flag: bool) -> i32 { if flag { return 1; } 2; }";
1685
        let result = try resolveProgramStr(&mut a, program);
1686
        try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
1687
    }
1688
}
1689
1690
@test fn testResolveFnAllPathsReturn() throws (testing::TestError) {
1691
    let mut a = testResolver();
1692
    let program = "fn h(flag: bool) -> i32 { if flag { return 1; } else { return 2; } }";
1693
    let result = try resolveProgramStr(&mut a, program);
1694
    try expectNoErrors(&result);
1695
}
1696
1697
/// Test that match statements with returns in all branches don't require a
1698
/// return at the end of the function.
1699
@test fn testResolveFnMatchAllPathsReturn() throws (testing::TestError) {
1700
    {
1701
        // Union match with all variants returning.
1702
        let mut a = testResolver();
1703
        let program = "union E { A, B } fn f(e: E) -> i32 { match e { case E::A => return 1, case E::B => return 2 } }";
1704
        let result = try resolveProgramStr(&mut a, program);
1705
        try expectNoErrors(&result);
1706
    } {
1707
        // Match with default case where all branches return.
1708
        let mut a = testResolver();
1709
        let program = "fn f(x: i32) -> i32 { match x { case 1 => return 1, else => return 0, } }";
1710
        let result = try resolveProgramStr(&mut a, program);
1711
        try expectNoErrors(&result);
1712
    } {
1713
        // Match where not all branches return should error.
1714
        let mut a = testResolver();
1715
        let program = "union E { A, B } fn f(e: E) -> i32 { match e { case E::A => return 1, case E::B => {} } }";
1716
        let result = try resolveProgramStr(&mut a, program);
1717
        try expectErrorKind(&result, super::ErrorKind::FnMissingReturn);
1718
    }
1719
}
1720
1721
@test fn testResolveAssign() throws (testing::TestError) {
1722
    {
1723
        let mut a = testResolver();
1724
        let result = try resolveProgramStr(&mut a, "let mut x: i32 = 0; x = 1;");
1725
        try expectNoErrors(&result);
1726
    } {
1727
        let mut a = testResolver();
1728
        let result = try resolveProgramStr(&mut a, "let x: i32 = 0; x = 1;");
1729
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1730
    } {
1731
        let mut a = testResolver();
1732
        let result = try resolveProgramStr(&mut a, "let mut x: bool = false; x = 1;");
1733
        let err = try expectError(&result);
1734
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1735
    } {
1736
        let mut a = testResolver();
1737
        let result = try resolveProgramStr(&mut a, "x = 1;");
1738
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1739
    } {
1740
        let mut a = testResolver();
1741
        let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; x = 1;");
1742
        try expectNoErrors(&result);
1743
    } {
1744
        let mut a = testResolver();
1745
        let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; x = nil;");
1746
        try expectNoErrors(&result);
1747
    }
1748
}
1749
1750
@test fn testResolveAssignSubscript() throws (testing::TestError) {
1751
    {
1752
        let mut a = testResolver();
1753
        let program = "let mut xs: [u8; 2] = [0, 1]; xs[0] = 9;";
1754
        let result = try resolveProgramStr(&mut a, program);
1755
        try expectNoErrors(&result);
1756
    }
1757
    {
1758
        let mut a = testResolver();
1759
        let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *mut [u8] = &mut xs[..]; slice[0] = 1;";
1760
        let result = try resolveProgramStr(&mut a, program);
1761
        try expectNoErrors(&result);
1762
    }
1763
    {
1764
        let mut a = testResolver();
1765
        let program = "let mut xs: [u8; 2] = [0, 1]; let mut slice: *[u8] = &xs[..]; slice[0] = 1;";
1766
        let result = try resolveProgramStr(&mut a, program);
1767
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1768
    }
1769
    {
1770
        let mut a = testResolver();
1771
        let program = "let xs: [u8; 2] = [0, 1]; xs[0] = 9;";
1772
        let result = try resolveProgramStr(&mut a, program);
1773
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1774
    }
1775
    {
1776
        let mut a = testResolver();
1777
        let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *[u8] = &xs[..]; slice[0] = 1;";
1778
        let result = try resolveProgramStr(&mut a, program);
1779
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1780
    }
1781
}
1782
1783
@test fn testResolveAssignIntegerLits() throws (testing::TestError) {
1784
    try expectAnalyzeOk("let x: i8 = 127;");
1785
    try expectAnalyzeOk("let x: i8 = 0x7F;");
1786
    try expectAnalyzeOk("let x: i8 = -128;");
1787
    try expectAnalyzeOk("let x: u8 = 255;");
1788
    try expectAnalyzeOk("let x: u8 = 0b11111111;");
1789
    try expectAnalyzeOk("let x: i16 = 0x7FFF;");
1790
    try expectAnalyzeOk("let x: i16 = -32768;");
1791
    try expectAnalyzeOk("let x: u16 = 0xFFFF;");
1792
    try expectAnalyzeOk("let x: i32 = 2147483647;");
1793
    try expectAnalyzeOk("let x: i32 = -2147483648;");
1794
    try expectAnalyzeOk("let x: u32 = 0xFFFFFFFF;");
1795
1796
    try expectAnalyzeOk("const LIMIT: u8 = 0xFF;");
1797
1798
    try expectIntMismatch("let x: i8 = 128;", super::Type::I8);
1799
    try expectIntMismatch("let x: i8 = -129;", super::Type::I8);
1800
    try expectIntMismatch("let x: i8 = 0x80;", super::Type::I8);
1801
    try expectIntMismatch("let x: i8 = 0b10000000;", super::Type::I8);
1802
    try expectIntMismatch("let x: u8 = 256;", super::Type::U8);
1803
    try expectIntMismatch("let x: u8 = -1;", super::Type::U8);
1804
    try expectIntMismatch("let x: u8 = 0b100000000;", super::Type::U8);
1805
    try expectIntMismatch("let x: i16 = 32768;", super::Type::I16);
1806
    try expectIntMismatch("let x: i16 = -32769;", super::Type::I16);
1807
    try expectIntMismatch("let x: u16 = 65536;", super::Type::U16);
1808
    try expectIntMismatch("let x: u16 = -1;", super::Type::U16);
1809
    try expectIntMismatch("let x: i32 = 2147483648;", super::Type::I32);
1810
    try expectIntMismatch("let x: i32 = -2147483649;", super::Type::I32);
1811
    try expectIntMismatch("let x: i32 = 0xFFFFFFFF;", super::Type::I32);
1812
    try expectIntMismatch("let x: u32 = -1;", super::Type::U32);
1813
    try expectIntMismatch("let x: u32 = 0x100000000;", super::Type::U32);
1814
    try expectIntMismatch("const LIMIT: u8 = 512;", super::Type::U8);
1815
    try expectIntMismatch("const LIMIT: u8 = -5;", super::Type::U8);
1816
}
1817
1818
@test fn testNilCoercions() throws (testing::TestError) {
1819
    {
1820
        let mut a = testResolver();
1821
        let result = try resolveBlockStr(&mut a, "let opt: ?i32 = nil;");
1822
        try expectNoErrors(&result);
1823
    } {
1824
        let mut a = testResolver();
1825
        let program = "fn g(opt: ?i32) {} fn f() { g(nil); }";
1826
        let result = try resolveProgramStr(&mut a, program);
1827
        try expectNoErrors(&result);
1828
    } {
1829
        let mut a = testResolver();
1830
        let program = "fn make(flag: bool) -> ?i32 { if flag { return 1; } return nil; }";
1831
        let result = try resolveProgramStr(&mut a, program);
1832
        try expectNoErrors(&result);
1833
    }
1834
}
1835
1836
@test fn testOptionalComparedWithNil() throws (testing::TestError) {
1837
    let mut a = testResolver();
1838
    let program = "let opt: ?i32 = nil; opt == nil; nil == opt; opt == 1; 1 == opt; opt == opt; nil == nil;";
1839
    let result = try resolveBlockStr(&mut a, program);
1840
    try expectNoErrors(&result);
1841
1842
    for i in 1..7 {
1843
        let stmt = try getBlockStmt(result.root, i);
1844
        try expectExprStmtType(&a, stmt, super::Type::Bool);
1845
    }
1846
}
1847
1848
@test fn testResolveRecordLiteralAllFieldsSet() throws (testing::TestError) {
1849
    let mut a = testResolver();
1850
    let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1, y: 2 };";
1851
    let result = try resolveProgramStr(&mut a, program);
1852
    try expectNoErrors(&result);
1853
}
1854
1855
@test fn testResolveRecordLiteralMissingField() throws (testing::TestError) {
1856
    let mut a = testResolver();
1857
    let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1 };";
1858
    let result = try resolveProgramStr(&mut a, program);
1859
    try expectErrorKind(&result, super::ErrorKind::RecordFieldMissing("y"));
1860
}
1861
1862
@test fn testResolveRecordLiteralFieldTypeMismatch() throws (testing::TestError) {
1863
    let mut a = testResolver();
1864
    let program = "record Pt { x: i32, y: i32 } let p = Pt { x: true, y: 2 };";
1865
    let result = try resolveProgramStr(&mut a, program);
1866
    let err = try expectError(&result);
1867
    try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
1868
1869
    let errNode = err.node
1870
        else throw testing::TestError::Failed;
1871
    let case ast::NodeValue::Bool(_) = errNode.value
1872
        else throw testing::TestError::Failed;
1873
}
1874
1875
@test fn testResolveRecordLiteralExtraField() throws (testing::TestError) {
1876
    let mut a = testResolver();
1877
    let program = "record Pt { x: i32, y: i32 } let p = Pt { x: 1, z: 3, y: 2 };";
1878
    let result = try resolveProgramStr(&mut a, program);
1879
    let err = try expectError(&result);
1880
    let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
1881
        else throw testing::TestError::Failed;
1882
}
1883
1884
/// Test that anonymous record literals with labels can be passed to functions expecting named records.
1885
@test fn testResolveAnonRecordLabeledToNamedRecord() throws (testing::TestError) {
1886
    let mut a = testResolver();
1887
    let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) -> i32 { return p.x; } foo({ x: 1, y: 2 });";
1888
    let result = try resolveProgramStr(&mut a, program);
1889
    try expectNoErrors(&result);
1890
}
1891
1892
/// Test that anonymous record with wrong field name causes out of order error.
1893
@test fn testResolveAnonRecordWrongFieldName() throws (testing::TestError) {
1894
    let mut a = testResolver();
1895
    let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1, z: 2 });";
1896
    let result = try resolveProgramStr(&mut a, program);
1897
    let err = try expectError(&result);
1898
    let case super::ErrorKind::RecordFieldOutOfOrder { field: _, prev: _ } = err.kind
1899
        else throw testing::TestError::Failed;
1900
}
1901
1902
/// Test that anonymous record with wrong field type causes type mismatch.
1903
@test fn testResolveAnonRecordWrongFieldType() throws (testing::TestError) {
1904
    let mut a = testResolver();
1905
    let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: true, y: 2 });";
1906
    let result = try resolveProgramStr(&mut a, program);
1907
    let err = try expectError(&result);
1908
    let case super::ErrorKind::TypeMismatch(_) = err.kind
1909
        else throw testing::TestError::Failed;
1910
}
1911
1912
/// Test that anonymous record with missing field causes a missing field error.
1913
@test fn testResolveAnonRecordMissingField() throws (testing::TestError) {
1914
    let mut a = testResolver();
1915
    let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1 });";
1916
    let result = try resolveProgramStr(&mut a, program);
1917
    try expectErrorKind(&result, super::ErrorKind::RecordFieldMissing("y"));
1918
}
1919
1920
/// Test that anonymous record with extra field causes a count mismatch error.
1921
@test fn testResolveAnonRecordExtraField() throws (testing::TestError) {
1922
    let mut a = testResolver();
1923
    let program = "record Pt { x: i32, y: i32 } fn foo(p: Pt) {} foo({ x: 1, y: 2, z: 3 });";
1924
    let result = try resolveProgramStr(&mut a, program);
1925
    let err = try expectError(&result);
1926
    let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
1927
        else throw testing::TestError::Failed;
1928
}
1929
1930
/// Test that anonymous record fields can be coerced (e.g., i32 to optional).
1931
@test fn testResolveAnonRecordFieldCoercion() throws (testing::TestError) {
1932
    let mut a = testResolver();
1933
    let program = "record Opt { x: ?i32 } fn foo(p: Opt) {} foo({ x: 42 });";
1934
    let result = try resolveProgramStr(&mut a, program);
1935
    try expectNoErrors(&result);
1936
}
1937
1938
/// Test that arrays of anonymous records with labeled fields are allowed.
1939
@test fn testResolveAnonRecordArray() throws (testing::TestError) {
1940
    let mut a = testResolver();
1941
    let program = "record Pt { x: i32, y: i32 } const ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4 }];";
1942
    let result = try resolveProgramStr(&mut a, program);
1943
    try expectNoErrors(&result);
1944
}
1945
1946
/// Test that arrays of anonymous records with extra fields cause count mismatch.
1947
@test fn testResolveAnonRecordArrayMismatch() throws (testing::TestError) {
1948
    let mut a = testResolver();
1949
    let program = "record Pt { x: i32, y: i32 } const ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4, z: 5 }];";
1950
    let result = try resolveProgramStr(&mut a, program);
1951
    let err = try expectError(&result);
1952
    let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
1953
        else throw testing::TestError::Failed;
1954
}
1955
1956
/// Test that unlabeled record declarations are analyzed correctly.
1957
@test fn testResolveUnlabeledRecordDecl() throws (testing::TestError) {
1958
    let mut a = testResolver();
1959
    let program = "record R(i32, bool);";
1960
    let result = try resolveProgramStr(&mut a, program);
1961
    try expectNoErrors(&result);
1962
1963
    // Verify the type symbol was created with labeled=false.
1964
    let nominalTy = try getTypeInScopeOf(&a, result.root, "R");
1965
    let case super::NominalType::Record(recordType) = *nominalTy
1966
        else throw testing::TestError::Failed;
1967
    try testing::expect(not recordType.labeled);
1968
    try testing::expect(recordType.fields.len == 2);
1969
    try testing::expect(recordType.fields[0].name == nil);
1970
    try testing::expect(recordType.fields[1].name == nil);
1971
}
1972
1973
@test fn testResolveLabeledRecordDecl() throws (testing::TestError) {
1974
    let mut a = testResolver();
1975
    let program = "record R { x: i32, y: i32 }";
1976
    let result = try resolveProgramStr(&mut a, program);
1977
    try expectNoErrors(&result);
1978
1979
    let nominalTy = try getTypeInScopeOf(&a, result.root, "R");
1980
    let case super::NominalType::Record(recordType) = *nominalTy
1981
        else throw testing::TestError::Failed;
1982
    try testing::expect(recordType.labeled);
1983
    try testing::expect(recordType.fields.len == 2);
1984
    try testing::expect(recordType.fields[0].name != nil);
1985
    try testing::expect(recordType.fields[1].name != nil);
1986
}
1987
1988
@test fn testResolveRecordFieldAccessValid() throws (testing::TestError) {
1989
    let mut a = testResolver();
1990
    let program = "record Pt { x: i32, y: u8 } let p = Pt { x: 1, y: 2 }; p.y;";
1991
    let result = try resolveProgramStr(&mut a, program);
1992
    try expectNoErrors(&result);
1993
1994
    let fieldStmt = try getBlockStmt(result.root, 2);
1995
    try expectExprStmtType(&a, fieldStmt, super::Type::U8);
1996
}
1997
1998
@test fn testResolveRecordFieldAccessUnknownField() throws (testing::TestError) {
1999
    let mut a = testResolver();
2000
    let program = "record Pt { x: i32 } let p = Pt { x: 1 }; p.y;";
2001
    let result = try resolveProgramStr(&mut a, program);
2002
    try expectErrorKind(&result, super::ErrorKind::RecordFieldUnknown("y"));
2003
}
2004
2005
@test fn testResolveRecordFieldAccessOnFunctionReturn() throws (testing::TestError) {
2006
    let mut a = testResolver();
2007
    let program = "record Pt { x: i32, y: i32 } fn make() -> Pt { return Pt { x: 5, y: 10 }; } make().x;";
2008
    let result = try resolveProgramStr(&mut a, program);
2009
    try expectNoErrors(&result);
2010
2011
    let stmt = try getBlockStmt(result.root, 2);
2012
    try expectExprStmtType(&a, stmt, super::Type::I32);
2013
}
2014
2015
@test fn testResolveRecordFieldAccessChained() throws (testing::TestError) {
2016
    let mut a = testResolver();
2017
    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;";
2018
    let result = try resolveProgramStr(&mut a, program);
2019
    try expectNoErrors(&result);
2020
2021
    let stmt = try getBlockStmt(result.root, 4);
2022
    try expectExprStmtType(&a, stmt, super::Type::I32);
2023
}
2024
2025
@test fn testResolveRecordFieldAccessOnInteger() throws (testing::TestError) {
2026
    let mut a = testResolver();
2027
    let program = "let x: i32 = 42; x.field;";
2028
    let result = try resolveBlockStr(&mut a, program);
2029
    try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
2030
}
2031
2032
@test fn testResolveRecordFieldAccessOnArray() throws (testing::TestError) {
2033
    let mut a = testResolver();
2034
    let program = "let arr: [i32; 3] = [1, 2, 3]; arr.field;";
2035
    let result = try resolveProgramStr(&mut a, program);
2036
    try expectErrorKind(&result, super::ErrorKind::ArrayFieldUnknown("field"));
2037
}
2038
2039
@test fn testResolveRecordFieldAccessOnBool() throws (testing::TestError) {
2040
    let mut a = testResolver();
2041
    let program = "let b: bool = true; b.field;";
2042
    let result = try resolveProgramStr(&mut a, program);
2043
    try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
2044
}
2045
2046
@test fn testResolveRecordFieldAccessOnOptional() throws (testing::TestError) {
2047
    let mut a = testResolver();
2048
    let program = "record Pt { x: i32 } let opt: ?Pt = Pt { x: 5 }; opt.x;";
2049
    let result = try resolveProgramStr(&mut a, program);
2050
    try expectErrorKind(&result, super::ErrorKind::ExpectedRecord);
2051
}
2052
2053
/// Records may reference themselves through pointers without causing resolution errors.
2054
@test fn testResolveRecordSelfReferentialPointer() throws (testing::TestError) {
2055
    let mut a = testResolver();
2056
    let program = "record A { next: *A }";
2057
    let result = try resolveProgramStr(&mut a, program);
2058
    try expectNoErrors(&result);
2059
}
2060
2061
/// Mutually recursive records should resolve without infinite loops.
2062
@test fn testResolveRecordMutuallyRecursive() throws (testing::TestError) {
2063
    let mut a = testResolver();
2064
    let program = "record A { b: *B } record B { a: *A }";
2065
    let result = try resolveProgramStr(&mut a, program);
2066
    try expectNoErrors(&result);
2067
}
2068
2069
/// Unions may reference themselves through pointers without causing resolution errors.
2070
@test fn testResolveUnionSelfReferentialPointerAllowed() throws (testing::TestError) {
2071
    let mut a = testResolver();
2072
    let program = "union List { Cons(*List), Nil }";
2073
    let result = try resolveProgramStr(&mut a, program);
2074
    try expectNoErrors(&result);
2075
}
2076
2077
/// Mutually recursive unions should resolve without infinite loops.
2078
@test fn testResolveUnionMutuallyRecursive() throws (testing::TestError) {
2079
    let mut a = testResolver();
2080
    let program = "union A { HasB(*B), None } union B { HasA(*A), None }";
2081
    let result = try resolveProgramStr(&mut a, program);
2082
    try expectNoErrors(&result);
2083
}
2084
2085
/// Unions with record payloads containing slice references to self should resolve.
2086
/// This matches the pattern in sexpr.rad: `List { tail: *[Expr] }`.
2087
@test fn testResolveUnionRecordPayloadWithSliceSelfRef() throws (testing::TestError) {
2088
    let mut a = testResolver();
2089
    let program = "union Expr { Null, List { head: *[u8], tail: *[Expr] } }";
2090
    let result = try resolveProgramStr(&mut a, program);
2091
    try expectNoErrors(&result);
2092
}
2093
2094
@test fn testUndefinedCoercions() throws (testing::TestError) {
2095
    {
2096
        let mut a = testResolver();
2097
        let result = try resolveBlockStr(&mut a, "let count: i32 = undefined;");
2098
        try expectNoErrors(&result);
2099
    } {
2100
        let mut a = testResolver();
2101
        let program = "let mut value: i32 = 0; value = undefined;";
2102
        let result = try resolveProgramStr(&mut a, program);
2103
        try expectNoErrors(&result);
2104
    } {
2105
        let mut a = testResolver();
2106
        let program = "fn f(x: i32) {} fn g() { f(undefined); }";
2107
        let result = try resolveProgramStr(&mut a, program);
2108
        try expectNoErrors(&result);
2109
    } {
2110
        let mut a = testResolver();
2111
        let program = "fn fetch() -> i32 { return undefined; }";
2112
        let result = try resolveProgramStr(&mut a, program);
2113
        try expectNoErrors(&result);
2114
    }
2115
}
2116
2117
@test fn testResolveBlockVoid() throws (testing::TestError) {
2118
    let mut a = testResolver();
2119
    let result = try resolveProgramStr(&mut a, "{ 42; }");
2120
    try expectNoErrors(&result);
2121
2122
    let block = try getBlockStmt(result.root, 0);
2123
    try expectType(&a, block, super::Type::Void);
2124
}
2125
2126
@test fn testResolveBlockNever() throws (testing::TestError) {
2127
    let mut a = testResolver();
2128
    let result = try resolveProgramStr(&mut a, "{ panic; }");
2129
    try expectNoErrors(&result);
2130
2131
    let block = try getBlockStmt(result.root, 0);
2132
    try expectType(&a, block, super::Type::Never);
2133
}
2134
2135
@test fn testResolveIfAllBranchesNever() throws (testing::TestError) {
2136
    let mut a = testResolver();
2137
    let program = "if true { panic; } else { panic; }";
2138
    let result = try resolveProgramStr(&mut a, program);
2139
    try expectNoErrors(&result);
2140
2141
    let stmt = try getBlockStmt(result.root, 0);
2142
    try expectType(&a, stmt, super::Type::Never);
2143
}
2144
2145
@test fn testResolveIfMixedBranchesNotNever() throws (testing::TestError) {
2146
    let mut a = testResolver();
2147
    let program = "if true { panic; } else {}";
2148
    let result = try resolveProgramStr(&mut a, program);
2149
    try expectNoErrors(&result);
2150
2151
    let stmt = try getBlockStmt(result.root, 0);
2152
    try expectType(&a, stmt, super::Type::Void);
2153
}
2154
2155
@test fn testResolveLetElse() throws (testing::TestError) {
2156
    let mut a = testResolver();
2157
    let program = "let opt: ?i32 = 42; let value = opt else panic; value;";
2158
    let result = try resolveProgramStr(&mut a, program);
2159
    try expectNoErrors(&result);
2160
2161
    let blockNode = result.root;
2162
    let case ast::NodeValue::Block(block) = blockNode.value
2163
        else throw testing::TestError::Failed;
2164
    let letElseNode = try getBlockStmt(blockNode, 1);
2165
    let valueStmt = try getBlockStmt(blockNode, 2);
2166
2167
    { // Ensure the bound identifier receives the inner optional type.
2168
        let valueExpr = try expectExprStmtType(&a, valueStmt, super::Type::I32);
2169
2170
        let sym = super::symbolFor(&a, valueExpr)
2171
            else throw testing::TestError::Failed;
2172
        let case super::SymbolData::Value { type: valType, .. } = sym.data
2173
            else throw testing::TestError::Failed;
2174
        try testing::expect(valType == super::Type::I32);
2175
    }
2176
    // The let-else statement itself should be typed as void.
2177
    try expectType(&a, letElseNode, super::Type::Void);
2178
}
2179
2180
@test fn testResolveLetElseDefaultValue() throws (testing::TestError) {
2181
    let mut a = testResolver();
2182
    let program = "let opt: ?i32 = nil; let value = opt else 42; value;";
2183
    let result = try resolveProgramStr(&mut a, program);
2184
    try expectNoErrors(&result);
2185
}
2186
2187
@test fn testResolveLetElseRequiresDivergentElse() throws (testing::TestError) {
2188
    let mut a = testResolver();
2189
    let program = "let opt: ?i32 = nil; let value = opt else {}; value;";
2190
    let result = try resolveProgramStr(&mut a, program);
2191
    let err = try expectError(&result);
2192
    try expectTypeMismatch(err, super::Type::I32, super::Type::Void);
2193
}
2194
2195
@test fn testResolveLetElseRequiresOptional() throws (testing::TestError) {
2196
    let mut a = testResolver();
2197
    let program = "let x: i32 = 42; let value = x else panic;";
2198
    let result = try resolveProgramStr(&mut a, program);
2199
    try expectErrorKind(&result, super::ErrorKind::ExpectedOptional);
2200
}
2201
2202
/// Test that `if let mut` produces a mutable binding.
2203
@test fn testResolveIfLetMut() throws (testing::TestError) {
2204
    let mut a = testResolver();
2205
    let program = "let opt: ?i32 = 42; if let mut v = opt { v = v + 1; }";
2206
    let result = try resolveProgramStr(&mut a, program);
2207
    try expectNoErrors(&result);
2208
}
2209
2210
/// Test that `if let` (without mut) rejects assignment.
2211
@test fn testResolveIfLetImmutable() throws (testing::TestError) {
2212
    let mut a = testResolver();
2213
    let program = "let opt: ?i32 = 42; if let v = opt { v = 1; }";
2214
    let result = try resolveProgramStr(&mut a, program);
2215
    let err = try expectError(&result);
2216
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2217
}
2218
2219
/// Test that `let mut ... else` produces a mutable binding.
2220
@test fn testResolveLetMutElse() throws (testing::TestError) {
2221
    let mut a = testResolver();
2222
    let program = "let opt: ?i32 = 42; let mut v = opt else panic; v = v + 1;";
2223
    let result = try resolveProgramStr(&mut a, program);
2224
    try expectNoErrors(&result);
2225
}
2226
2227
/// Test that `let ... else` (without mut) rejects assignment.
2228
@test fn testResolveLetElseImmutable() throws (testing::TestError) {
2229
    let mut a = testResolver();
2230
    let program = "let opt: ?i32 = 42; let v = opt else panic; v = 1;";
2231
    let result = try resolveProgramStr(&mut a, program);
2232
    let err = try expectError(&result);
2233
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2234
}
2235
2236
@test fn testResolveLetCaseElse() throws (testing::TestError) {
2237
    {
2238
        let mut a = testResolver();
2239
        let program = "let case _ = 1 else panic;";
2240
        let result = try resolveProgramStr(&mut a, program);
2241
        try expectNoErrors(&result);
2242
    } {
2243
        let mut a = testResolver();
2244
        let program = "let case _ = true else false;";
2245
        let result = try resolveProgramStr(&mut a, program);
2246
        try expectNoErrors(&result);
2247
    }
2248
}
2249
2250
@test fn testResolveLetCaseElseRequiresDivergentElse() throws (testing::TestError) {
2251
    let mut a = testResolver();
2252
    let program = "let case _ = 1 else {};";
2253
    let result = try resolveProgramStr(&mut a, program);
2254
    let err = try expectError(&result);
2255
    try expectTypeMismatch(err, super::Type::Int, super::Type::Void);
2256
}
2257
2258
@test fn testResolveTryValidPropagation() throws (testing::TestError) {
2259
    let mut a = testResolver();
2260
    let program = "fn fallible() throws (i32) {} fn caller() throws (i32) { try fallible() }";
2261
    let result = try resolveProgramStr(&mut a, program);
2262
    try expectNoErrors(&result);
2263
}
2264
2265
@test fn testResolveTryRequiresThrowsClause() throws (testing::TestError) {
2266
    let mut a = testResolver();
2267
    let program = "fn fallible() throws (i32) {} fn caller() { try fallible() }";
2268
    let result = try resolveProgramStr(&mut a, program);
2269
    try expectErrorKind(&result, super::ErrorKind::TryRequiresThrows);
2270
}
2271
2272
@test fn testResolveTryIncompatibleError() throws (testing::TestError) {
2273
    let mut a = testResolver();
2274
    let program = "fn fallible() throws (i32) {} fn caller() throws (i8) { try fallible() }";
2275
    let result = try resolveProgramStr(&mut a, program);
2276
    try expectErrorKind(&result, super::ErrorKind::TryIncompatibleError);
2277
}
2278
2279
@test fn testResolveTryNonThrowing() throws (testing::TestError) {
2280
    let mut a = testResolver();
2281
    let program = "fn safe() {} fn caller() throws (i32) { try safe() }";
2282
    let result = try resolveProgramStr(&mut a, program);
2283
    try expectErrorKind(&result, super::ErrorKind::TryNonThrowing);
2284
}
2285
2286
@test fn testResolveTryCatchBlockMatchesResult() throws (testing::TestError) {
2287
    let mut a = testResolver();
2288
    let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { return 42; }; }";
2289
    let result = try resolveProgramStr(&mut a, program);
2290
    try expectNoErrors(&result);
2291
}
2292
2293
@test fn testResolveTryCatchBlockDiverges() throws (testing::TestError) {
2294
    let mut a = testResolver();
2295
    let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { return 7; }; }";
2296
    let result = try resolveProgramStr(&mut a, program);
2297
    try expectNoErrors(&result);
2298
}
2299
2300
@test fn testResolveTryCatchBlockMustDiverge() throws (testing::TestError) {
2301
    let mut a = testResolver();
2302
    let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; return 0; } fn caller() -> u32 { return try fallible() catch { 7; }; }";
2303
    let result = try resolveProgramStr(&mut a, program);
2304
    let err = try expectError(&result);
2305
    try expectTypeMismatch(err, super::Type::U32, super::Type::Void);
2306
}
2307
2308
@test fn testResolveCallMissingTry() throws (testing::TestError) {
2309
    let mut a = testResolver();
2310
    let program = "fn fallible() throws (i32) {} fn caller() { fallible() }";
2311
    let result = try resolveProgramStr(&mut a, program);
2312
    try expectErrorKind(&result, super::ErrorKind::MissingTry);
2313
}
2314
2315
/// Test that `try?` converts errors to optionals without requiring caller to throw.
2316
@test fn testResolveTryOptionalConvertsToOptional() throws (testing::TestError) {
2317
    // `try?` should wrap the return type in optional and not require caller to throw.
2318
    {
2319
        let mut a = testResolver();
2320
        let program = "record S {} fn fallible() -> *S throws (i32) { panic; } fn caller() -> ?*S { return try? fallible(); }";
2321
        let result = try resolveProgramStr(&mut a, program);
2322
        try expectNoErrors(&result);
2323
    }
2324
    // `try?` works in non-throwing function.
2325
    {
2326
        let mut a = testResolver();
2327
        let program = "fn fallible() -> i32 throws (i32) { panic; } fn caller() -> ?i32 { return try? fallible(); }";
2328
        let result = try resolveProgramStr(&mut a, program);
2329
        try expectNoErrors(&result);
2330
    }
2331
    // `try?` can be used in if-let patterns.
2332
    {
2333
        let mut a = testResolver();
2334
        let program = "fn fallible() -> i32 throws (i32) { panic; } fn caller() -> i32 { if let x = try? fallible() { return x; } return 0; }";
2335
        let result = try resolveProgramStr(&mut a, program);
2336
        try expectNoErrors(&result);
2337
    }
2338
}
2339
2340
@test fn testResolveThrowValid() throws (testing::TestError) {
2341
    let mut a = testResolver();
2342
    let program = "fn fail() throws (i32) { throw 1; }";
2343
    let result = try resolveProgramStr(&mut a, program);
2344
    try expectNoErrors(&result);
2345
}
2346
2347
@test fn testResolveThrowRequiresThrowsClause() throws (testing::TestError) {
2348
    let mut a = testResolver();
2349
    let program = "fn fail() { throw 1; }";
2350
    let result = try resolveProgramStr(&mut a, program);
2351
    try expectErrorKind(&result, super::ErrorKind::ThrowRequiresThrows);
2352
}
2353
2354
@test fn testResolveThrowIncompatibleError() throws (testing::TestError) {
2355
    let mut a = testResolver();
2356
    let program = "fn fail() throws (i32) { throw true; }";
2357
    let result = try resolveProgramStr(&mut a, program);
2358
    try expectErrorKind(&result, super::ErrorKind::ThrowIncompatibleError);
2359
}
2360
2361
// Binary operation tests //////////////////////////////////////////////////////
2362
2363
@test fn testResolveBinaryOpArithmetic() throws (testing::TestError) {
2364
    {
2365
        let mut a = testResolver();
2366
        let result = try resolveExprStr(&mut a, "4 + 4");
2367
        try expectNoErrors(&result);
2368
        try expectType(&a, result.root, super::Type::Int);
2369
    } {
2370
        let mut a = testResolver();
2371
        let result = try resolveExprStr(&mut a, "10 - 3");
2372
        try expectNoErrors(&result);
2373
        try expectType(&a, result.root, super::Type::Int);
2374
    } {
2375
        let mut a = testResolver();
2376
        let result = try resolveExprStr(&mut a, "5 * 6");
2377
        try expectNoErrors(&result);
2378
        try expectType(&a, result.root, super::Type::Int);
2379
    } {
2380
        let mut a = testResolver();
2381
        let result = try resolveExprStr(&mut a, "20 / 4");
2382
        try expectNoErrors(&result);
2383
        try expectType(&a, result.root, super::Type::Int);
2384
    } {
2385
        let mut a = testResolver();
2386
        let result = try resolveExprStr(&mut a, "17 % 5");
2387
        try expectNoErrors(&result);
2388
        try expectType(&a, result.root, super::Type::Int);
2389
    } {
2390
        let mut a = testResolver();
2391
        let result = try resolveBlockStr(&mut a, "let x: i32 = 4; let y: i32 = 5; x + y;");
2392
        try expectNoErrors(&result);
2393
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2394
        try expectExprStmtType(&a, stmt, super::Type::I32);
2395
    } {
2396
        let mut a = testResolver();
2397
        let result = try resolveExprStr(&mut a, "1 + (2 * 3) - 4");
2398
        try expectNoErrors(&result);
2399
        try expectType(&a, result.root, super::Type::Int);
2400
    } {
2401
        let mut a = testResolver();
2402
        let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n * 2;");
2403
        try expectNoErrors(&result);
2404
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2405
        try expectExprStmtType(&a, stmt, super::Type::I32);
2406
    } {
2407
        let mut a = testResolver();
2408
        let result = try resolveBlockStr(&mut a, "let n: i32 = 5; 2 * n;");
2409
        try expectNoErrors(&result);
2410
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2411
        try expectExprStmtType(&a, stmt, super::Type::I32);
2412
    } {
2413
        let mut a = testResolver();
2414
        let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n - 1;");
2415
        try expectNoErrors(&result);
2416
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2417
        try expectExprStmtType(&a, stmt, super::Type::I32);
2418
    }
2419
}
2420
2421
@test fn testResolveBinaryOpComparison() throws (testing::TestError) {
2422
    {
2423
        let mut a = testResolver();
2424
        let result = try resolveExprStr(&mut a, "5 == 5");
2425
        try expectNoErrors(&result);
2426
        try expectType(&a, result.root, super::Type::Bool);
2427
    } {
2428
        let mut a = testResolver();
2429
        let result = try resolveExprStr(&mut a, "5 != 10");
2430
        try expectNoErrors(&result);
2431
        try expectType(&a, result.root, super::Type::Bool);
2432
    } {
2433
        let mut a = testResolver();
2434
        let result = try resolveExprStr(&mut a, "5 < 10");
2435
        try expectNoErrors(&result);
2436
        try expectType(&a, result.root, super::Type::Bool);
2437
    } {
2438
        let mut a = testResolver();
2439
        let result = try resolveExprStr(&mut a, "10 > 5");
2440
        try expectNoErrors(&result);
2441
        try expectType(&a, result.root, super::Type::Bool);
2442
    } {
2443
        let mut a = testResolver();
2444
        let result = try resolveExprStr(&mut a, "5 <= 5");
2445
        try expectNoErrors(&result);
2446
        try expectType(&a, result.root, super::Type::Bool);
2447
    } {
2448
        let mut a = testResolver();
2449
        let result = try resolveExprStr(&mut a, "10 >= 5");
2450
        try expectNoErrors(&result);
2451
        try expectType(&a, result.root, super::Type::Bool);
2452
    } {
2453
        let mut a = testResolver();
2454
        let result = try resolveExprStr(&mut a, "true == false");
2455
        try expectNoErrors(&result);
2456
        try expectType(&a, result.root, super::Type::Bool);
2457
    } {
2458
        let mut a = testResolver();
2459
        let result = try resolveExprStr(&mut a, "5 + 3 > 10 - 4");
2460
        try expectNoErrors(&result);
2461
        try expectType(&a, result.root, super::Type::Bool);
2462
    } {
2463
        let mut a = testResolver();
2464
        let result = try resolveBlockStr(&mut a, "let n: i32 = 5; n == 1;");
2465
        try expectNoErrors(&result);
2466
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2467
        try expectExprStmtType(&a, stmt, super::Type::Bool);
2468
    } {
2469
        let mut a = testResolver();
2470
        let result = try resolveBlockStr(&mut a, "let n: i32 = 5; 1 == n;");
2471
        try expectNoErrors(&result);
2472
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2473
        try expectExprStmtType(&a, stmt, super::Type::Bool);
2474
    }
2475
}
2476
2477
@test fn testResolveBinaryOpLogical() throws (testing::TestError) {
2478
    {
2479
        let mut a = testResolver();
2480
        let result = try resolveBlockStr(&mut a, "let x: bool = true; let y: bool = false; x and y;");
2481
        try expectNoErrors(&result);
2482
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2483
        try expectExprStmtType(&a, stmt, super::Type::Bool);
2484
    } {
2485
        let mut a = testResolver();
2486
        let result = try resolveBlockStr(&mut a, "let x: bool = true; let y: bool = false; x or y;");
2487
        try expectNoErrors(&result);
2488
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2489
        try expectExprStmtType(&a, stmt, super::Type::Bool);
2490
    } {
2491
        let mut a = testResolver();
2492
        let result = try resolveExprStr(&mut a, "true and false");
2493
        try expectNoErrors(&result);
2494
        try expectType(&a, result.root, super::Type::Bool);
2495
    }
2496
}
2497
2498
@test fn testResolveBinaryOpArithmeticTypeMismatch() throws (testing::TestError) {
2499
    {
2500
        let mut a = testResolver();
2501
        let result = try resolveProgramStr(&mut a, "4 + true");
2502
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2503
    } {
2504
        let mut a = testResolver();
2505
        let result = try resolveBlockStr(&mut a, "let x: i32 = 4; let y: bool = false; x + y;");
2506
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2507
    } {
2508
        let mut a = testResolver();
2509
        let result = try resolveProgramStr(&mut a, "10 - false");
2510
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2511
    } {
2512
        let mut a = testResolver();
2513
        let result = try resolveProgramStr(&mut a, "5 * true");
2514
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2515
    } {
2516
        let mut a = testResolver();
2517
        let result = try resolveProgramStr(&mut a, "20 / false");
2518
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2519
    } {
2520
        let mut a = testResolver();
2521
        let result = try resolveProgramStr(&mut a, "17 % true");
2522
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2523
    } {
2524
        let mut a = testResolver();
2525
        let result = try resolveProgramStr(&mut a, "1 + (true * 3)");
2526
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2527
    }
2528
}
2529
2530
@test fn testResolveBinaryOpLogicalTypeMismatch() throws (testing::TestError) {
2531
    {
2532
        let mut a = testResolver();
2533
        let result = try resolveProgramStr(&mut a, "42 and true");
2534
        let err = try expectError(&result);
2535
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
2536
    } {
2537
        let mut a = testResolver();
2538
        let result = try resolveProgramStr(&mut a, "true or 5");
2539
        let err = try expectError(&result);
2540
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
2541
    } {
2542
        let mut a = testResolver();
2543
        let result = try resolveProgramStr(&mut a, "1 and 2");
2544
        let err = try expectError(&result);
2545
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
2546
    }
2547
}
2548
2549
@test fn testResolveBinaryOpComparisonTypeMismatch() throws (testing::TestError) {
2550
    let mut a = testResolver();
2551
    let result = try resolveProgramStr(&mut a, "true < false");
2552
    try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2553
}
2554
2555
// Unary operation tests ///////////////////////////////////////////////////////
2556
2557
@test fn testResolveUnaryOpNot() throws (testing::TestError) {
2558
    {
2559
        let mut a = testResolver();
2560
        let result = try resolveExprStr(&mut a, "not true");
2561
        try expectNoErrors(&result);
2562
        try expectType(&a, result.root, super::Type::Bool);
2563
    } {
2564
        let mut a = testResolver();
2565
        let result = try resolveBlockStr(&mut a, "let x: bool = true; not x;");
2566
        try expectNoErrors(&result);
2567
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2568
        try expectExprStmtType(&a, stmt, super::Type::Bool);
2569
    } {
2570
        let mut a = testResolver();
2571
        let result = try resolveExprStr(&mut a, "not (true and false)");
2572
        try expectNoErrors(&result);
2573
        try expectType(&a, result.root, super::Type::Bool);
2574
    } {
2575
        let mut a = testResolver();
2576
        let result = try resolveProgramStr(&mut a, "not 42");
2577
        let err = try expectError(&result);
2578
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
2579
    } {
2580
        let mut a = testResolver();
2581
        let result = try resolveBlockStr(&mut a, "let x: i32 = 5; not x;");
2582
        let err = try expectError(&result);
2583
        try expectTypeMismatch(err, super::Type::Bool, super::Type::I32);
2584
    }
2585
}
2586
2587
@test fn testResolveUnaryOpNeg() throws (testing::TestError) {
2588
    {
2589
        let mut a = testResolver();
2590
        let result = try resolveExprStr(&mut a, "-42");
2591
        try expectNoErrors(&result);
2592
        try expectType(&a, result.root, super::Type::Int);
2593
    } {
2594
        let mut a = testResolver();
2595
        let result = try resolveBlockStr(&mut a, "let x: i32 = 10; -x;");
2596
        try expectNoErrors(&result);
2597
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2598
        try expectExprStmtType(&a, stmt, super::Type::I32);
2599
    } {
2600
        let mut a = testResolver();
2601
        let result = try resolveExprStr(&mut a, "-(5 + 3)");
2602
        try expectNoErrors(&result);
2603
        try expectType(&a, result.root, super::Type::Int);
2604
    } {
2605
        let mut a = testResolver();
2606
        let result = try resolveBlockStr(&mut a, "let x: i8 = 5; -x;");
2607
        try expectNoErrors(&result);
2608
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2609
        try expectExprStmtType(&a, stmt, super::Type::I8);
2610
    } {
2611
        let mut a = testResolver();
2612
        let result = try resolveProgramStr(&mut a, "-true");
2613
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2614
    } {
2615
        let mut a = testResolver();
2616
        let result = try resolveBlockStr(&mut a, "let x: bool = false; -x;");
2617
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2618
    }
2619
}
2620
2621
@test fn testResolveUnaryOpBitNot() throws (testing::TestError) {
2622
    {
2623
        let mut a = testResolver();
2624
        let result = try resolveExprStr(&mut a, "~42");
2625
        try expectNoErrors(&result);
2626
        try expectType(&a, result.root, super::Type::Int);
2627
    } {
2628
        let mut a = testResolver();
2629
        let result = try resolveBlockStr(&mut a, "let x: u32 = 255; ~x;");
2630
        try expectNoErrors(&result);
2631
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2632
        try expectExprStmtType(&a, stmt, super::Type::U32);
2633
    } {
2634
        let mut a = testResolver();
2635
        let result = try resolveExprStr(&mut a, "~(0xFF)");
2636
        try expectNoErrors(&result);
2637
        try expectType(&a, result.root, super::Type::Int);
2638
    } {
2639
        let mut a = testResolver();
2640
        let result = try resolveBlockStr(&mut a, "let x: i8 = 5; ~x;");
2641
        try expectNoErrors(&result);
2642
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2643
        try expectExprStmtType(&a, stmt, super::Type::I8);
2644
    } {
2645
        let mut a = testResolver();
2646
        let result = try resolveProgramStr(&mut a, "~true");
2647
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2648
    } {
2649
        let mut a = testResolver();
2650
        let result = try resolveBlockStr(&mut a, "let x: bool = false; ~x;");
2651
        try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
2652
    }
2653
}
2654
2655
@test fn testResolveUnaryOpNested() throws (testing::TestError) {
2656
    {
2657
        let mut a = testResolver();
2658
        let result = try resolveExprStr(&mut a, "not not true");
2659
        try expectNoErrors(&result);
2660
        try expectType(&a, result.root, super::Type::Bool);
2661
    } {
2662
        let mut a = testResolver();
2663
        let result = try resolveExprStr(&mut a, "--42");
2664
        try expectNoErrors(&result);
2665
        try expectType(&a, result.root, super::Type::Int);
2666
    } {
2667
        let mut a = testResolver();
2668
        let result = try resolveExprStr(&mut a, "~~0xFF");
2669
        try expectNoErrors(&result);
2670
        try expectType(&a, result.root, super::Type::Int);
2671
    } {
2672
        let mut a = testResolver();
2673
        let result = try resolveExprStr(&mut a, "-(~42)");
2674
        try expectNoErrors(&result);
2675
        try expectType(&a, result.root, super::Type::Int);
2676
    }
2677
}
2678
2679
// test fn testNormalPointerArithmetic() throws (testing::TestError) {
2680
//     mut a = testResolver();
2681
//     let result = try resolveProgramStr(&mut a, "fn test() { let ptr: *i32 = undefined; let x = ptr + 1; }");
2682
//     try expectNoErrors(&result);
2683
// }
2684
2685
// Dereference tests //////////////////////////////////////////////////////////
2686
2687
@test fn testResolveDeref() throws (testing::TestError) {
2688
    {
2689
        let mut a = testResolver();
2690
        let result = try resolveBlockStr(&mut a, "let x: i32 = 42; let ptr: *i32 = &x; *ptr;");
2691
        try expectNoErrors(&result);
2692
        let stmt = try parser::tests::getBlockLastStmt(result.root);
2693
        try expectExprStmtType(&a, stmt, super::Type::I32);
2694
    } {
2695
        let mut a = testResolver();
2696
        let result = try resolveExprStr(&mut a, "*42");
2697
        try expectErrorKind(&result, super::ErrorKind::ExpectedPointer);
2698
    } {
2699
        let mut a = testResolver();
2700
        let result = try resolveBlockStr(&mut a, "let x: i32 = 5; *x;");
2701
        try expectErrorKind(&result, super::ErrorKind::ExpectedPointer);
2702
    }
2703
}
2704
2705
@test fn testResolveAssignDeref() throws (testing::TestError) {
2706
    {
2707
        let mut a = testResolver();
2708
        let program = "let mut x: i32 = 0; let ptr: *mut i32 = &mut x; *ptr = 42;";
2709
        let result = try resolveProgramStr(&mut a, program);
2710
        try expectNoErrors(&result);
2711
    } {
2712
        let mut a = testResolver();
2713
        let program = "let mut x: i32 = 0; let ptr: *i32 = &x; *ptr = 42;";
2714
        let result = try resolveProgramStr(&mut a, program);
2715
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2716
    } {
2717
        let mut a = testResolver();
2718
        let program = "let mut x: i32 = 0; let mut ptr: *i32 = &x; *ptr = 42;";
2719
        let result = try resolveProgramStr(&mut a, program);
2720
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2721
    } {
2722
        let mut a = testResolver();
2723
        let program = "let mut x: u8 = 0; let mut ptr: *mut u8 = &mut x; *ptr = 255;";
2724
        let result = try resolveProgramStr(&mut a, program);
2725
        try expectNoErrors(&result);
2726
    }
2727
}
2728
2729
// Type inference tests ///////////////////////////////////////////////////////
2730
2731
@test fn testResolveBasicTypeInference() throws (testing::TestError) {
2732
    {
2733
        // Boolean literals are unambiguous.
2734
        let mut a = testResolver();
2735
        let result = try resolveProgramStr(&mut a, "let x = true; x;");
2736
        try expectNoErrors(&result);
2737
2738
        let xStmt = try parser::tests::getBlockLastStmt(result.root);
2739
        try expectExprStmtType(&a, xStmt, super::Type::Bool);
2740
    } {
2741
        // Integer literals are ambiguous.
2742
        let mut a = testResolver();
2743
        let result = try resolveProgramStr(&mut a, "let x = 34;");
2744
        try expectErrorKind(&result, super::ErrorKind::CannotInferType);
2745
    }
2746
}
2747
2748
// Union tests /////////////////////////////////////////////////////////////////
2749
2750
@test fn testResolveUnionVariantWithoutPayload() throws (testing::TestError) {
2751
    let mut a = testResolver();
2752
    let program = "union Status { Ok, Error } Status::Ok;";
2753
    let result = try resolveProgramStr(&mut a, program);
2754
2755
    let ty = try getTypeInScopeOf(&a, result.root, "Status");
2756
    let case super::NominalType::Union(unionType) = *ty
2757
        else throw testing::TestError::Failed;
2758
    try testing::expect(unionType.variants.len == 2);
2759
    try testing::expect(mem::eq(unionType.variants[0].name, "Ok"));
2760
    try testing::expect(mem::eq(unionType.variants[1].name, "Error"));
2761
    if getUnionVariantPayload(ty, "Ok") != super::Type::Void {
2762
        throw testing::TestError::Failed;
2763
    }
2764
    let stmt = try getBlockStmt(result.root, 1);
2765
    try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
2766
    try expectNoErrors(&result);
2767
}
2768
2769
@test fn testResolveUnionVariantWithPayload() throws (testing::TestError) {
2770
    let mut a = testResolver();
2771
    let program = "union R { Ok(i32), Err(bool) } R::Ok(42);";
2772
    let result = try resolveProgramStr(&mut a, program);
2773
    try expectNoErrors(&result);
2774
2775
    let ty = try getTypeInScopeOf(&a, result.root, "R");
2776
2777
    let okPayload = getUnionVariantPayload(ty, "Ok");
2778
    try testing::expect(okPayload == super::Type::I32);
2779
2780
    let errPayload = getUnionVariantPayload(ty, "Err");
2781
    try testing::expect(errPayload == super::Type::Bool);
2782
2783
    let stmt = try getBlockStmt(result.root, 1);
2784
    try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
2785
2786
    // TODO: Test payload type.
2787
}
2788
2789
@test fn testResolveUnionVariantWithoutPayloadExplicitDiscriminant() throws (testing::TestError) {
2790
    let mut a = testResolver();
2791
    let program = "union R { Ok = 7, Err = 11 } R::Ok;";
2792
    let result = try resolveProgramStr(&mut a, program);
2793
    try expectNoErrors(&result);
2794
2795
    let ty = try getTypeInScopeOf(&a, result.root, "R");
2796
    let stmt = try getBlockStmt(result.root, 1);
2797
    try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
2798
}
2799
2800
@test fn testResolveUnionVariantPayloadTypeMismatch() throws (testing::TestError) {
2801
    let mut a = testResolver();
2802
    let program = "union R { Ok(i32), Error(bool) } R::Ok(true);";
2803
    let result = try resolveProgramStr(&mut a, program);
2804
    let err = try expectError(&result);
2805
    try expectTypeMismatch(err, super::Type::I32, super::Type::Bool);
2806
2807
    let ty = try getTypeInScopeOf(&a, result.root, "R");
2808
    let payload = getUnionVariantPayload(ty, "Ok");
2809
    try testing::expect(payload == super::Type::I32);
2810
2811
    let errNode = err.node
2812
        else throw testing::TestError::Failed;
2813
    let case ast::NodeValue::Bool(_) = errNode.value
2814
        else throw testing::TestError::Failed;
2815
}
2816
2817
@test fn testResolveUnionVariantUnexpectedPayload() throws (testing::TestError) {
2818
    let mut a = testResolver();
2819
    let program = "union Status { Ok, Error } Status::Ok(42);";
2820
    let result = try resolveProgramStr(&mut a, program);
2821
    let err = try expectError(&result);
2822
2823
    let case super::ErrorKind::UnionVariantPayloadUnexpected(_) = err.kind
2824
        else throw testing::TestError::Failed;
2825
    let node = err.node
2826
        else throw testing::TestError::Failed;
2827
    let case ast::NodeValue::Call(_) = node.value
2828
        else throw testing::TestError::Failed;
2829
}
2830
2831
@test fn testResolveUnionVariantUnknown() throws (testing::TestError) {
2832
    let mut a = testResolver();
2833
    let program = "union Status { Ok, Error } Status::Unknown;";
2834
    let result = try resolveProgramStr(&mut a, program);
2835
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
2836
}
2837
2838
@test fn testResolveScopeAccessUndefinedType() throws (testing::TestError) {
2839
    let mut a = testResolver();
2840
    let result = try resolveProgramStr(&mut a, "Unknown::X;");
2841
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Unknown"));
2842
}
2843
2844
@test fn testResolveUnionVariantVoidPayload() throws (testing::TestError) {
2845
    let mut a = testResolver();
2846
    let program = "union R { Success(i32), Pending } R::Pending;";
2847
    let result = try resolveProgramStr(&mut a, program);
2848
    try expectNoErrors(&result);
2849
2850
    let ty = try getTypeInScopeOf(&a, result.root, "R");
2851
    let payload = getUnionVariantPayload(ty, "Pending");
2852
    try testing::expect(payload == super::Type::Void);
2853
2854
    let stmt = try getBlockStmt(result.root, 1);
2855
    try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
2856
}
2857
2858
@test fn testResolveUnionVariantRecordPayload() throws (testing::TestError) {
2859
    let mut a = testResolver();
2860
    let program = "record P { x: i32, y: i32 } union S { Point(P), Num(u32) } S::Point(P { x: 10, y: 20 });";
2861
    let result = try resolveProgramStr(&mut a, program);
2862
    try expectNoErrors(&result);
2863
2864
    let ty = try getTypeInScopeOf(&a, result.root, "S");
2865
    let stmt = try getBlockStmt(result.root, 2);
2866
    try expectExprStmtType(&a, stmt, super::Type::Nominal(ty));
2867
}
2868
2869
@test fn testResolveBuiltinSizeOf() throws (testing::TestError) {
2870
    try resolveAndExpectConstExpr("@sizeOf(u8)", 1);
2871
    try resolveAndExpectConstExpr("@sizeOf(u16)", 2);
2872
    try resolveAndExpectConstExpr("@sizeOf(u32)", 4);
2873
    try resolveAndExpectConstExpr("@sizeOf(i32)", 4);
2874
    try resolveAndExpectConstExpr("@sizeOf(bool)", 1);
2875
    try resolveAndExpectConstExpr("@sizeOf(*u32)", 8);
2876
    try resolveAndExpectConstExpr("@sizeOf([u8; 10])", 10);
2877
    try resolveAndExpectConstExpr("@sizeOf(*[u32])", 16);
2878
    try resolveAndExpectConstExpr("@sizeOf(?u8)", 2);
2879
    try resolveAndExpectConstExpr("@sizeOf(?u16)", 4);
2880
    try resolveAndExpectConstExpr("@sizeOf(?u32)", 8);
2881
    try resolveAndExpectConstExpr("@sizeOf(*opaque)", 8);
2882
    try resolveAndExpectConstStmt("record T { x: u8 } @sizeOf(T);", 1);
2883
    try resolveAndExpectConstStmt("record T { x: i32 } @sizeOf(T);", 4);
2884
    try resolveAndExpectConstStmt("record T { x: i32, y: i8 } @sizeOf(T);", 8);
2885
    try resolveAndExpectConstStmt("record T { x: i8, y: i32 } @sizeOf(T);", 8);
2886
    try resolveAndExpectConstStmt("record T { x: i8, y: i32 } @sizeOf(T);", 8);
2887
    try resolveAndExpectConstStmt("record T { x: u32, y: u8, z: u8 }; @sizeOf(T);", 8);
2888
    try resolveAndExpectConstStmt("record T { x: u8, y: u32, z: u8 }; @sizeOf(T);", 12);
2889
    try resolveAndExpectConstStmt("union T { A, B, C }; @sizeOf(T);", 1);
2890
    try resolveAndExpectConstStmt("union T { A, B(u32), C }; @sizeOf(T);", 8);
2891
    try resolveAndExpectConstStmt("union T { A, B(u16), C }; @sizeOf(T);", 4);
2892
    try resolveAndExpectConstStmt("union T { A(u32), B(u16), C(u16) }; @sizeOf(T);", 8);
2893
    try resolveAndExpectConstStmt("union T { A(u32), B(u16), C([u8; 16]) }; @sizeOf(T);", 20);
2894
}
2895
2896
@test fn testResolveBuiltinAlignOf() throws (testing::TestError) {
2897
    try resolveAndExpectConstExpr("@alignOf(u8)", 1);
2898
    try resolveAndExpectConstExpr("@alignOf(u16)", 2);
2899
    try resolveAndExpectConstExpr("@alignOf(u32)", 4);
2900
    try resolveAndExpectConstExpr("@alignOf(i32)", 4);
2901
    try resolveAndExpectConstExpr("@alignOf(bool)", 1);
2902
    try resolveAndExpectConstExpr("@alignOf(*u8)", 8);
2903
    try resolveAndExpectConstExpr("@alignOf(*u16)", 8);
2904
    try resolveAndExpectConstExpr("@alignOf(*u32)", 8);
2905
    try resolveAndExpectConstExpr("@alignOf(*opaque)", 8);
2906
    try resolveAndExpectConstExpr("@alignOf([u8; 8])", 1);
2907
    try resolveAndExpectConstExpr("@alignOf([u16; 8])", 2);
2908
    try resolveAndExpectConstExpr("@alignOf([u32; 8])", 4);
2909
    try resolveAndExpectConstExpr("@alignOf(*[u32])", 8);
2910
    try resolveAndExpectConstExpr("@alignOf(?u8)", 1);
2911
    try resolveAndExpectConstExpr("@alignOf(?u16)", 2);
2912
    try resolveAndExpectConstExpr("@alignOf(?u32)", 4);
2913
    try resolveAndExpectConstStmt("record T { x: u8, y: u16 }; @alignOf(T);", 2);
2914
    try resolveAndExpectConstStmt("record T { x: u8, y: u32, z: u8 }; @alignOf(T);", 4);
2915
    try resolveAndExpectConstStmt("record T { x: u32, y: u8, z: u8 }; @alignOf(T);", 4);
2916
    try resolveAndExpectConstStmt("union T { A, B, C }; @alignOf(T);", 1);
2917
    try resolveAndExpectConstStmt("union T { A, B(u32), C }; @alignOf(T);", 4);
2918
}
2919
2920
@test fn testResolveBuiltinSizeOfRecord() throws (testing::TestError) {
2921
    let mut a = testResolver();
2922
    let program = "record T { x: u8, y: u32 } @sizeOf(T);";
2923
    let result = try resolveProgramStr(&mut a, program);
2924
    try expectNoErrors(&result);
2925
2926
    let stmt = try getBlockStmt(result.root, 1);
2927
    let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
2928
    try expectConstInt(&a, expr, 8);
2929
}
2930
2931
@test fn testResolveBuiltinSizeOfUnion() throws (testing::TestError) {
2932
    let mut a = testResolver();
2933
    let program = "union Result { Ok(u32), Err(u8) } @sizeOf(Result);";
2934
    let result = try resolveProgramStr(&mut a, program);
2935
    try expectNoErrors(&result);
2936
2937
    let stmt = try getBlockStmt(result.root, 1);
2938
    let expr = try expectExprStmtType(&a, stmt, super::Type::U32);
2939
    try expectConstInt(&a, expr, 8);
2940
}
2941
2942
@test fn testResolveAlignAnnotation() throws (testing::TestError) {
2943
    {
2944
        let mut a = testResolver();
2945
        let result = try resolveBlockStr(&mut a, "let x: u8 align(8) = 0;");
2946
        try expectNoErrors(&result);
2947
2948
        let stmt = try getBlockStmt(result.root, 0);
2949
        let sym = super::symbolFor(&a, stmt)
2950
            else throw testing::TestError::Failed;
2951
        let case super::SymbolData::Value { type: valType, .. } = sym.data
2952
            else throw testing::TestError::Failed;
2953
        let layout = super::getLayout(&a, sym.node, valType);
2954
        try testing::expect(layout.alignment == 8);
2955
    } {
2956
        let mut a = testResolver();
2957
        let result = try resolveProgramStr(&mut a, "let x: u32 align(3) = 0;");
2958
        let err = try expectError(&result);
2959
        let case super::ErrorKind::InvalidAlignmentValue(val) = err.kind
2960
            else throw testing::TestError::Failed;
2961
        try testing::expect(val == 3);
2962
    } {
2963
        let mut a = testResolver();
2964
        let result = try resolveProgramStr(&mut a, "let x: u32 align(7) = 0;");
2965
        let err = try expectError(&result);
2966
        let case super::ErrorKind::InvalidAlignmentValue(val) = err.kind
2967
            else throw testing::TestError::Failed;
2968
        try testing::expect(val == 7);
2969
    }
2970
}
2971
2972
@test fn testResolveVoidAssignmentError() throws (testing::TestError) {
2973
    {
2974
        let mut a = testResolver();
2975
        let program = "fn voidFn() {} let _ = voidFn();";
2976
        let result = try resolveProgramStr(&mut a, program);
2977
        try expectErrorKind(&result, super::ErrorKind::CannotAssignVoid);
2978
    } {
2979
        let mut a = testResolver();
2980
        let program = "fn voidFn() {} let x = voidFn();";
2981
        let result = try resolveProgramStr(&mut a, program);
2982
        try expectErrorKind(&result, super::ErrorKind::CannotAssignVoid);
2983
    }
2984
}
2985
2986
//
2987
// Module Declaration Tests
2988
//
2989
2990
@test fn testResolveEmptyMod() throws (testing::TestError) {
2991
    let mut a = testResolver();
2992
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
2993
    let mut graph = &mut MODULE_GRAPH;
2994
2995
    let rootId = try registerModule(graph, nil, "root", "mod child;", &mut arena);
2996
    let childId = try registerModule(graph, rootId, "child", "{}", &mut arena);
2997
    let result = try resolveModuleTree(&mut a, rootId);
2998
    try expectNoErrors(&result);
2999
}
3000
3001
@test fn testResolveModuleCannotAccessParentScope() throws (testing::TestError) {
3002
    let mut a = testResolver();
3003
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3004
3005
    // Register root and util modules.
3006
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod util; pub fn helper() {}", &mut arena);
3007
    let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "fn main() { helper(); }", &mut arena);
3008
3009
    // Resolve should fail: the parent module is not in scope.
3010
    let result = try resolveModuleTree(&mut a, rootId);
3011
    let err = try expectError(&result);
3012
    let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
3013
        else throw testing::TestError::Failed;
3014
    try testing::expect(mem::eq(name, "helper"));
3015
}
3016
3017
@test fn testResolveModuleAccessPrivateSubModule() throws (testing::TestError) {
3018
    let mut a = testResolver();
3019
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3020
3021
    // Register root and util modules.
3022
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod util; fn main() { util::helper(); }", &mut arena);
3023
    let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "pub fn helper() {}", &mut arena);
3024
3025
    // Resolve should succeed: parent can access child.
3026
    let result = try resolveModuleTree(&mut a, rootId);
3027
    try expectNoErrors(&result);
3028
}
3029
3030
@test fn testResolveSiblingModulesCannotAccessDirectly() throws (testing::TestError) {
3031
    let mut a = testResolver();
3032
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3033
3034
    // Register root with two sibling modules.
3035
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod paul; pub mod patrick;", &mut arena);
3036
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "paul", "fn main() { patrick::helper(); }", &mut arena);
3037
    let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "patrick", "pub fn helper() -> i32 { return 42; }", &mut arena);
3038
3039
    // Resolve should fail: siblings can't access each other directly.
3040
    let result = try resolveModuleTree(&mut a, rootId);
3041
    let err = try expectError(&result);
3042
    let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
3043
        else throw testing::TestError::Failed;
3044
    try testing::expect(mem::eq(name, "patrick"));
3045
}
3046
3047
@test fn testResolveSiblingModulesViaRoot() throws (testing::TestError) {
3048
    let mut a = testResolver();
3049
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3050
3051
    // Register root with two sibling modules.
3052
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod paul; pub mod patrick;", &mut arena);
3053
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "paul", "use root::patrick; fn main() -> i32 { return patrick::helper(); }", &mut arena);
3054
    let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "patrick", "pub fn helper() -> i32 { return 42; }", &mut arena);
3055
3056
    // Resolve should succeed: siblings can access each other via root.
3057
    let result = try resolveModuleTree(&mut a, rootId);
3058
    try expectNoErrors(&result);
3059
}
3060
3061
@test fn testResolveModuleMutualRecursion() throws (testing::TestError) {
3062
    let mut a = testResolver();
3063
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3064
3065
    // Register root with two sibling modules that call each other.
3066
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod left; pub mod right;", &mut arena);
3067
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "left", "use root::right; pub fn leftHelper() -> i32 { return right::rightHelper(); }", &mut arena);
3068
    let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "right", "use root::left; pub fn rightHelper() -> i32 { return left::leftHelper(); }", &mut arena);
3069
3070
    // Resolve should succeed: cyclic use is allowed.
3071
    let result = try resolveModuleTree(&mut a, rootId);
3072
    try expectNoErrors(&result);
3073
}
3074
3075
@test fn testResolveAccessModuleType() throws (testing::TestError) {
3076
    let mut a = testResolver();
3077
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3078
3079
    // Register root with types module containing a record.
3080
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod types; mod app;", &mut arena);
3081
    let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "pub record Point { x: i32, y: i32 }", &mut arena);
3082
    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);
3083
3084
    // Resolve should succeed: types can be accessed.
3085
    let result = try resolveModuleTree(&mut a, rootId);
3086
    try expectNoErrors(&result);
3087
}
3088
3089
@test fn testResolveAccessModuleConstant() throws (testing::TestError) {
3090
    let mut a = testResolver();
3091
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3092
3093
    // Register root with constants module.
3094
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod consts; mod app;", &mut arena);
3095
    let constantsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "pub const MAX_SIZE: i32 = 100;", &mut arena);
3096
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() -> i32 { return consts::MAX_SIZE; }", &mut arena);
3097
3098
    // Resolve should succeed: constants can be accessed.
3099
    let result = try resolveModuleTree(&mut a, rootId);
3100
    try expectNoErrors(&result);
3101
}
3102
3103
@test fn testResolveRootSymbolMustBeImported() throws (testing::TestError) {
3104
    let mut a = testResolver();
3105
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3106
3107
    // Register deeply nested modules: `root::app::services::auth`.
3108
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; pub fn helper() -> i32 { return 42; }", &mut arena);
3109
    let mainId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "fn run() -> i32 { return root::helper(); }", &mut arena);
3110
3111
    // Resolve should fail: the `root` module must be imported.
3112
    let result = try resolveModuleTree(&mut a, rootId);
3113
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("root"));
3114
}
3115
3116
@test fn testResolveUseImportsNestedSymbol() throws (testing::TestError) {
3117
    let mut a = testResolver();
3118
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3119
3120
    // Register deeply nested modules: `root::app::services::auth`.
3121
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod app; mod main;", &mut arena);
3122
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "pub mod services;", &mut arena);
3123
    let servicesId = try registerModule(&mut MODULE_GRAPH, appId, "services", "pub mod auth;", &mut arena);
3124
    let authId = try registerModule(&mut MODULE_GRAPH, servicesId, "auth", "pub fn login() -> i32 { return 1; }", &mut arena);
3125
    let mainId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::app::services::auth; fn run() -> i32 { return auth::login(); }", &mut arena);
3126
    let otherId = try registerModule(&mut MODULE_GRAPH, rootId, "other", "use root; fn run() -> i32 { return root::app::services::auth::login(); }", &mut arena);
3127
3128
    // Resolve should succeed: use imports the module symbol.
3129
    let result = try resolveModuleTree(&mut a, rootId);
3130
    try expectNoErrors(&result);
3131
}
3132
3133
@test fn testResolveUseNonExistentModule() throws (testing::TestError) {
3134
    let mut a = testResolver();
3135
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3136
3137
    // Register root with app trying to use a non-existent module.
3138
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod app;", &mut arena);
3139
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::unknown;", &mut arena);
3140
3141
    // Resolve should fail: module doesn't exist.
3142
    let result = try resolveModuleTree(&mut a, rootId);
3143
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("unknown"));
3144
}
3145
3146
@test fn testResolveUsePrivateFn() throws (testing::TestError) {
3147
    let mut a = testResolver();
3148
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3149
3150
    // Register root with util module containing a private function.
3151
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod util; mod app;", &mut arena);
3152
    let utilId = try registerModule(&mut MODULE_GRAPH, rootId, "util", "fn private() -> i32 { return 42; }", &mut arena);
3153
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::util; fn main() -> i32 { return util::private(); }", &mut arena);
3154
3155
    // Resolve should fail: function is not public.
3156
    let result = try resolveModuleTree(&mut a, rootId);
3157
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
3158
}
3159
3160
@test fn testResolveUsePrivateMod() throws (testing::TestError) {
3161
    let mut a = testResolver();
3162
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3163
3164
    // Register root with public and private child modules.
3165
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; mod private;", &mut arena);
3166
    let privateId = try registerModule(&mut MODULE_GRAPH, rootId, "private", "{}", &mut arena);
3167
    let publicId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::private;", &mut arena);
3168
3169
    // Resolve should fail: module is not public.
3170
    let result = try resolveModuleTree(&mut a, rootId);
3171
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
3172
}
3173
3174
@test fn testResolveUsePublicMod() throws (testing::TestError) {
3175
    let mut a = testResolver();
3176
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3177
3178
    // Register root with public and private child modules.
3179
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod main; pub mod public;", &mut arena);
3180
    let privateId = try registerModule(&mut MODULE_GRAPH, rootId, "public", "{}", &mut arena);
3181
    let publicId = try registerModule(&mut MODULE_GRAPH, rootId, "main", "use root::public;", &mut arena);
3182
3183
    // Resolve should succeed: module is public.
3184
    let result = try resolveModuleTree(&mut a, rootId);
3185
    try expectNoErrors(&result);
3186
}
3187
3188
@test fn testResolveUseNonPublicType() throws (testing::TestError) {
3189
    let mut a = testResolver();
3190
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3191
3192
    // Register root with types module containing a private record.
3193
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod types; mod app;", &mut arena);
3194
    let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "record Priv { x: i32 }", &mut arena);
3195
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> types::Priv { return types::Priv { x: 1 }; }", &mut arena);
3196
3197
    // Resolve should fail: record is not public.
3198
    let result = try resolveModuleTree(&mut a, rootId);
3199
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Priv"));
3200
}
3201
3202
@test fn testResolveImportPublicType() throws (testing::TestError) {
3203
    let mut a = testResolver();
3204
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3205
3206
    // Register root with types module containing a public record.
3207
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod types; mod app;", &mut arena);
3208
    let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "pub record Pub { x: i32 }", &mut arena);
3209
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::types; fn main() -> types::Pub { return types::Pub { x: 1 }; }", &mut arena);
3210
3211
    // Resolve should succeed: record is public.
3212
    let result = try resolveModuleTree(&mut a, rootId);
3213
    try expectNoErrors(&result);
3214
}
3215
3216
@test fn testResolveUseNonPublicStatic() throws (testing::TestError) {
3217
    let mut a = testResolver();
3218
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3219
3220
    // Register root with statics module containing a private static.
3221
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod statics; mod app;", &mut arena);
3222
    let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "static PRIVATE: i32 = 42;", &mut arena);
3223
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() -> i32 { return statics::PRIVATE; }", &mut arena);
3224
3225
    // Resolve should fail: static is not public.
3226
    let result = try resolveModuleTree(&mut a, rootId);
3227
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("PRIVATE"));
3228
}
3229
3230
@test fn testResolveImportPublicStatic() throws (testing::TestError) {
3231
    let mut a = testResolver();
3232
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3233
3234
    // Register root with statics module containing a public static.
3235
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod statics; mod app;", &mut arena);
3236
    let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "pub static PUBLIC: i32 = 42;", &mut arena);
3237
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() -> i32 { return statics::PUBLIC; }", &mut arena);
3238
3239
    // Resolve should succeed: static is public.
3240
    let result = try resolveModuleTree(&mut a, rootId);
3241
    try expectNoErrors(&result);
3242
}
3243
3244
@test fn testResolveAccessSuper() throws (testing::TestError) {
3245
    {
3246
        let mut a = testResolver();
3247
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3248
3249
        // Test function access.
3250
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; pub fn parentFn() -> i32 { return 42; }", &mut arena);
3251
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "fn main() -> i32 { return super::parentFn(); }", &mut arena);
3252
        let result = try resolveModuleTree(&mut a, rootId);
3253
        try expectNoErrors(&result);
3254
    } {
3255
        let mut a = testResolver();
3256
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3257
3258
        // Test type access.
3259
        let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; pub record Point { x: i32, y: i32 }", &mut arena);
3260
        let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "fn make() -> super::Point { return super::Point { x: 1, y: 2 }; }", &mut arena);
3261
        let result = try resolveModuleTree(&mut a, rootId);
3262
        try expectNoErrors(&result);
3263
    }
3264
}
3265
3266
/// Test nested super access to union variants (e.g. `super::E::A`).
3267
@test fn testResolveSuperUnionVariant() throws (testing::TestError) {
3268
    let mut a = testResolver();
3269
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3270
3271
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod c; pub union E { A, B }", &mut arena);
3272
    let childId = try registerModule(&mut MODULE_GRAPH, rootId, "c",
3273
        "fn f(x: super::E) { match x { case super::E::A => {}, case super::E::B => {} } }",
3274
        &mut arena);
3275
    let result = try resolveModuleTree(&mut a, rootId);
3276
    try expectNoErrors(&result);
3277
}
3278
3279
@test fn testResolveUseSuper() throws (testing::TestError) {
3280
    let mut a = testResolver();
3281
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3282
3283
    // Register root with a function, and a child module that uses super to access it.
3284
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod joe; pub mod kate;", &mut arena);
3285
    let kateId = try registerModule(&mut MODULE_GRAPH, rootId, "kate", "pub fn run() {}", &mut arena);
3286
    let joeId = try registerModule(&mut MODULE_GRAPH, rootId, "joe", "use super::kate; fn main() { kate::run(); }", &mut arena);
3287
3288
    // Resolve should succeed - super allows accessing parent module.
3289
    let result = try resolveModuleTree(&mut a, rootId);
3290
    try expectNoErrors(&result);
3291
}
3292
3293
@test fn testResolveModNotFound() throws (testing::TestError) {
3294
    let mut a = testResolver();
3295
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3296
3297
    // Register root that declares a module that doesn't exist.
3298
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod unknown;", &mut arena);
3299
3300
    // Resolve should fail: module doesn't exist.
3301
    let result = try resolveModuleTree(&mut a, rootId);
3302
    let err = try expectError(&result);
3303
    let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
3304
        else throw testing::TestError::Failed;
3305
    try testing::expect(mem::eq(name, "unknown"));
3306
}
3307
3308
@test fn testResolveDuplicateSubModule() throws (testing::TestError) {
3309
    let mut a = testResolver();
3310
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3311
3312
    // Register root that declares a module twice.
3313
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; mod child;", &mut arena);
3314
    let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "{}", &mut arena);
3315
3316
    // Resolve should fail: can't declare the same module twice.
3317
    let result = try resolveModuleTree(&mut a, rootId);
3318
    let err = try expectError(&result);
3319
    try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("child"));
3320
}
3321
3322
@test fn testResolveUseSubModule() throws (testing::TestError) {
3323
    let mut a = testResolver();
3324
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3325
3326
    // Register root that declares and imports the same module.
3327
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child; use child;", &mut arena);
3328
    let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "{}", &mut arena);
3329
3330
    // Resolve should fail: Both `mod` and `use` are trying to create the same binding.
3331
    let result = try resolveModuleTree(&mut a, rootId);
3332
    let err = try expectError(&result);
3333
    try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("child"));
3334
}
3335
3336
@test fn testResolveDuplicateUse() throws (testing::TestError) {
3337
    let mut a = testResolver();
3338
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3339
3340
    // Register a module that imports the same module twice.
3341
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod child", &mut arena);
3342
    let childId = try registerModule(&mut MODULE_GRAPH, rootId, "child", "use root; use root;", &mut arena);
3343
3344
    // Resolve should fail.
3345
    let result = try resolveModuleTree(&mut a, rootId);
3346
    let err = try expectError(&result);
3347
    try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("root"));
3348
}
3349
3350
/// Test that opaque pointers are allowed in record fields.
3351
@test fn testOpaquePointerInRecordField() throws (testing::TestError) {
3352
    let mut a = testResolver();
3353
    let result = try resolveProgramStr(&mut a, "record T { x: *opaque }");
3354
    try expectNoErrors(&result);
3355
}
3356
3357
/// You cannot use `@sizeOf` or `@alignOf` on opaque type.
3358
@test fn testOpaqueTypeNoSizeOfAlignOf() throws (testing::TestError) {
3359
    let mut a = testResolver();
3360
3361
    let result1 = try resolveExprStr(&mut a, "@sizeOf(opaque)");
3362
    let err1 = try expectError(&result1);
3363
    try expectErrorKind(&result1, super::ErrorKind::OpaqueTypeNotAllowed);
3364
3365
    let result2 = try resolveExprStr(&mut a, "@alignOf(opaque)");
3366
    let err2 = try expectError(&result2);
3367
    try expectErrorKind(&result2, super::ErrorKind::OpaqueTypeNotAllowed);
3368
}
3369
3370
/// Test that immutable slice/pointer parameters cannot be borrowed mutably.
3371
@test fn testMutableBorrowFromImmutablePointer() throws (testing::TestError) {
3372
    let mut a = testResolver();
3373
    let program = "fn f(p: *i32) { let x = &mut *p; }";
3374
    let result = try resolveProgramStr(&mut a, program);
3375
    let err = try expectError(&result);
3376
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3377
}
3378
3379
/// Test that immutable slice parameters cannot be borrowed mutably.
3380
@test fn testMutableBorrowFromImmutableSlice() throws (testing::TestError) {
3381
    let mut a = testResolver();
3382
    let program = "fn f(s: *[i32]) { let x: *mut i32 = &mut s[0]; }";
3383
    let result = try resolveProgramStr(&mut a, program);
3384
    let err = try expectError(&result);
3385
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3386
}
3387
3388
/// Test that mutable pointer parameters can be borrowed mutably.
3389
@test fn testMutableBorrowFromMutablePointer() throws (testing::TestError) {
3390
    let mut a = testResolver();
3391
    let program = "fn f(p: *mut i32) { let x: *mut i32 = &mut *p; }";
3392
    let result = try resolveProgramStr(&mut a, program);
3393
    try expectNoErrors(&result);
3394
}
3395
3396
/// Test that mutable slice parameters can be borrowed mutably.
3397
@test fn testMutableBorrowFromMutableSlice() throws (testing::TestError) {
3398
    let mut a = testResolver();
3399
    let program = "fn f(s: *mut [i32]) { let x: *mut i32 = &mut s[0]; }";
3400
    let result = try resolveProgramStr(&mut a, program);
3401
    try expectNoErrors(&result);
3402
}
3403
3404
/// Test that mutable bindings of immutable pointers cannot borrow mutably through the pointer.
3405
@test fn testMutableBorrowFromMutableBindingOfPointer() throws (testing::TestError) {
3406
    let mut a = testResolver();
3407
    let program = "fn f() { let mut x: i32 = 1; let p: *i32 = &x; let y = &mut *p; }";
3408
    let result = try resolveProgramStr(&mut a, program);
3409
    let err = try expectError(&result);
3410
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3411
}
3412
3413
/// Test that mutable pointer to immutable slice cannot be assigned through index.
3414
/// This tests the case where we have `*mut *[T]`; the outer pointer is mutable but
3415
/// the inner slice is immutable, so we shouldn't be able to mutate the elements.
3416
@test fn testAssignThroughMutablePointerToImmutableSlice() throws (testing::TestError) {
3417
    let mut a = testResolver();
3418
    let program = "fn f(slice: *[i32]) { let p: *mut *[i32] = &mut slice; p[0] = 1; }";
3419
    let result = try resolveProgramStr(&mut a, program);
3420
3421
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3422
}
3423
3424
/// Test that mutable slice parameters can be assigned through index.
3425
@test fn testAssignThroughMutableSliceParam() throws (testing::TestError) {
3426
    {
3427
        // Mutable slice param: direct assignment should work
3428
        let mut a = testResolver();
3429
        let program = "fn f(slice: *mut [i32]) { slice[0] = 1; }";
3430
        let result = try resolveProgramStr(&mut a, program);
3431
        try expectNoErrors(&result);
3432
    } {
3433
        // Immutable slice param: direct assignment should fail
3434
        let mut a = testResolver();
3435
        let program = "fn f(slice: *[i32]) { slice[0] = 1; }";
3436
        let result = try resolveProgramStr(&mut a, program);
3437
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3438
    }
3439
}
3440
3441
/// Test range end type coercion with assignable types.
3442
@test fn testRangeEndTypeCoercion() throws (testing::TestError) {
3443
    {
3444
        let mut a = testResolver();
3445
        let program = "fn f(end: u32) { for i in 0..end {} }";
3446
        let result = try resolveProgramStr(&mut a, program);
3447
        try expectNoErrors(&result);
3448
    } {
3449
        let mut a = testResolver();
3450
        let program = "fn f(start: u32) { for i in start..9 {} }";
3451
        let result = try resolveProgramStr(&mut a, program);
3452
        try expectNoErrors(&result);
3453
    }
3454
}
3455
3456
/// Mixed-width range bounds require an explicit cast.
3457
@test fn testRangeEndTypeSubType() throws (testing::TestError) {
3458
    {
3459
        let mut a = testResolver();
3460
        let program = "fn f(start: i8, end: u32) { for i in start..end {} }";
3461
        let result = try resolveProgramStr(&mut a, program);
3462
        let err = try expectError(&result);
3463
        try expectTypeMismatch(err, super::Type::I8, super::Type::U32);
3464
    } {
3465
        let mut a = testResolver();
3466
        let program = "fn f(start: i8, end: u32) { for i in (start as u32)..end {} }";
3467
        let result = try resolveProgramStr(&mut a, program);
3468
        try expectNoErrors(&result);
3469
    }
3470
}
3471
3472
/// Test that try-catch expressions in statement context accept mismatched types.
3473
@test fn testTryCatchInStatementContextTypeMismatchOk() throws (testing::TestError) {
3474
    let mut a = testResolver();
3475
    let program = "fn f() { try g() catch {}; } fn g() -> bool throws (i32) { panic; }";
3476
    let result = try resolveProgramStr(&mut a, program);
3477
    try expectNoErrors(&result);
3478
}
3479
3480
/// Test that try-catch blocks in value context require divergence or void.
3481
@test fn testTryCatchInValueContextTypeMismatch() throws (testing::TestError) {
3482
    let mut a = testResolver();
3483
    let program = "fn f() -> bool { return try g() catch {}; } fn g() -> bool throws (i32) { panic; }";
3484
    let result = try resolveProgramStr(&mut a, program);
3485
    let err = try expectError(&result);
3486
    try expectTypeMismatch(err, super::Type::Bool, super::Type::Void);
3487
}
3488
3489
/// Test that try-catch blocks in value context work when they diverge.
3490
@test fn testTryCatchInValueContextDiverges() throws (testing::TestError) {
3491
    let mut a = testResolver();
3492
    let program = "fn f() -> bool { return try g() catch { return false; }; } fn g() -> bool throws (i32) { panic; }";
3493
    let result = try resolveProgramStr(&mut a, program);
3494
    try expectNoErrors(&result);
3495
}
3496
3497
/// Test that `try?` lifts result type to optional.
3498
@test fn testTryOptionalLiftsToOptional() throws (testing::TestError) {
3499
    let mut a = testResolver();
3500
    let program = "record S {} fn f() -> ?*S { return try? g(); } fn g() -> *S throws (i32) { panic; }";
3501
    let result = try resolveProgramStr(&mut a, program);
3502
    try expectNoErrors(&result);
3503
}
3504
3505
/// Test that record fields can be assigned if the record binding is mutable.
3506
@test fn testMutableAssignToMutableRecordBinding() throws (testing::TestError) {
3507
    let mut a = testResolver();
3508
    let program = "record S { x: i32 } fn f() { let mut s = S { x: 1 }; s.x = 2; }";
3509
    let result = try resolveProgramStr(&mut a, program);
3510
    try expectNoErrors(&result);
3511
}
3512
3513
/// Test that record fields cannot be assigned if the record binding is immutable.
3514
@test fn testMutableAssignToImmutableRecordBinding() throws (testing::TestError) {
3515
    let mut a = testResolver();
3516
    let program = "record S { x: i32 } fn f() { let s = S { x: 1 }; s.x = 2; }";
3517
    let result = try resolveProgramStr(&mut a, program);
3518
    let err = try expectError(&result);
3519
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3520
}
3521
3522
/// Test that record fields can be assigned through a mutable pointer.
3523
@test fn testMutableAssignToMutablePointerToRecord() throws (testing::TestError) {
3524
    let mut a = testResolver();
3525
    let program = "record S { x: i32 } fn f(p: *mut S) { p.x = 2; }";
3526
    let result = try resolveProgramStr(&mut a, program);
3527
    try expectNoErrors(&result);
3528
}
3529
3530
/// Test that record fields cannot be assigned through an immutable pointer.
3531
@test fn testMutableAssignToImmutablePointerToRecord() throws (testing::TestError) {
3532
    let mut a = testResolver();
3533
    let program = "record S { x: i32 } fn f(p: *S) { p.x = 2; }";
3534
    let result = try resolveProgramStr(&mut a, program);
3535
    let err = try expectError(&result);
3536
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3537
}
3538
3539
// Opaque pointer tests.
3540
3541
/// You can assign any pointer (*T) to an opaque pointer (*opaque) without a cast.
3542
@test fn testOpaquePointerAutoCoercion() throws (testing::TestError) {
3543
    let mut a = testResolver();
3544
    let result = try resolveProgramStr(&mut a, "fn f(x: i32) { let mut ptr: *i32 = &x; let o: *opaque = ptr; ptr = o as *i32; }");
3545
    try expectNoErrors(&result);
3546
}
3547
3548
/// You cannot assign an opaque pointer to a non-opaque pointer without a cast.
3549
@test fn testOpaquePointerNoReverseCoercion() throws (testing::TestError) {
3550
    let mut a = testResolver();
3551
    let result = try resolveProgramStr(&mut a, "fn f(a: i32) { let o: *opaque = &a; let ptr: *i32 = o; }");
3552
    let err = try expectError(&result);
3553
    let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
3554
        else throw testing::TestError::Failed;
3555
    let case super::Type::Pointer { target: expectedTarget, .. } = mismatch.expected
3556
        else throw testing::TestError::Failed;
3557
    let case super::Type::Pointer { target: actualTarget, .. } = mismatch.actual
3558
        else throw testing::TestError::Failed;
3559
3560
    try testing::expect(*expectedTarget == super::Type::I32);
3561
    try testing::expect(*actualTarget == super::Type::Opaque);
3562
}
3563
3564
/// You cannot have a value of type `opaque` (function parameter).
3565
@test fn testOpaqueValue() throws (testing::TestError) {
3566
    {
3567
        let mut a = testResolver();
3568
        let result = try resolveProgramStr(&mut a, "fn f(x: opaque) {}");
3569
        let err = try expectError(&result);
3570
        try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
3571
    } {
3572
        let mut a = testResolver();
3573
        let result = try resolveProgramStr(&mut a, "fn f() { let x: opaque = undefined; }");
3574
        let err = try expectError(&result);
3575
        try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
3576
    } {
3577
        let mut a = testResolver();
3578
        let result = try resolveProgramStr(&mut a, "record R { x: opaque }");
3579
        let err = try expectError(&result);
3580
        try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed);
3581
    }
3582
}
3583
3584
/// You cannot dereference an opaque pointer, you have to cast it first.
3585
@test fn testOpaquePointerNoDereference() throws (testing::TestError) {
3586
    let mut a = testResolver();
3587
    let result = try resolveProgramStr(&mut a, "fn f(a: i32) { let o: *opaque = &a; let x = *o; }");
3588
    let err = try expectError(&result);
3589
    try expectErrorKind(&result, super::ErrorKind::OpaqueTypeDeref);
3590
}
3591
3592
/// Test that you can dereference after casting.
3593
@test fn testOpaquePointerDereferenceAfterCast() throws (testing::TestError) {
3594
    let mut a = testResolver();
3595
    let result = try resolveProgramStr(&mut a, "fn f() { let o: *opaque = undefined; let x = *(o as *i32); }");
3596
    try expectNoErrors(&result);
3597
}
3598
3599
/// You cannot do pointer arithmetic with an opaque pointer.
3600
@test fn testOpaquePointerNoArithmetic() throws (testing::TestError) {
3601
    {
3602
        let mut a = testResolver();
3603
        let result = try resolveProgramStr(&mut a, "fn f(a: i32) { let o: *opaque = &a; let x = o + 1; }");
3604
        let err = try expectError(&result);
3605
        try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
3606
    } {
3607
        let mut a = testResolver();
3608
        let result = try resolveProgramStr(&mut a, "fn f(a: i32) { let o: *opaque = &a; let x = 1 + o; }");
3609
        let err = try expectError(&result);
3610
        try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
3611
    } {
3612
        let mut a = testResolver();
3613
        let result = try resolveProgramStr(&mut a, "fn f(a: i32) { let o: *opaque = &a; let x = o - 1; }");
3614
        let err = try expectError(&result);
3615
        try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
3616
    } {
3617
        let mut a = testResolver();
3618
        let result = try resolveProgramStr(&mut a, "fn f(a: i32) { let o: *opaque = &a; let x = 1 - o; }");
3619
        let err = try expectError(&result);
3620
        try expectErrorKind(&result, super::ErrorKind::OpaquePointerArithmetic);
3621
    }
3622
}
3623
3624
// Wildcard import/reexport tests.
3625
3626
/// Test transitive re-export.
3627
@test fn testWildcardReexportTransitive() throws (testing::TestError) {
3628
    let mut a = testResolver();
3629
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3630
3631
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod a; pub mod b;", &mut arena);
3632
    let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b; fn main() -> i32 { return b::helper() + b::MAX; }", &mut arena);
3633
    let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "mod c; pub use c::*;", &mut arena);
3634
    let cId = try registerModule(&mut MODULE_GRAPH, bId, "c", "mod d; pub use d::*; pub fn helper() -> i32 { return 42; }", &mut arena);
3635
    let dId = try registerModule(&mut MODULE_GRAPH, cId, "d", "pub const MAX: i32 = 100;", &mut arena);
3636
3637
    let result = try resolveModuleTree(&mut a, rootId);
3638
    try expectNoErrors(&result);
3639
}
3640
3641
/// Test that wildcard import can access public symbols.
3642
@test fn testWildcardImportPublicOnly() throws (testing::TestError) {
3643
    let mut a = testResolver();
3644
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3645
3646
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod b; mod a;", &mut arena);
3647
    let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "pub fn public() -> i32 { return 1; } fn private() -> i32 { return 2; }", &mut arena);
3648
    let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b::*; fn main() -> i32 { return public(); }", &mut arena);
3649
3650
    let result = try resolveModuleTree(&mut a, rootId);
3651
    try expectNoErrors(&result);
3652
}
3653
3654
/// Test that wildcard import cannot access private symbols.
3655
@test fn testWildcardImportSkipsPrivate() throws (testing::TestError) {
3656
    let mut a = testResolver();
3657
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3658
3659
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod b; mod a;", &mut arena);
3660
    let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "pub fn public() -> i32 { return 1; } fn private() -> i32 { return 2; }", &mut arena);
3661
    let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b::*; fn main() -> i32 { return private(); }", &mut arena);
3662
3663
    let result = try resolveModuleTree(&mut a, rootId);
3664
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("private"));
3665
}
3666
3667
/// Test that a constant array can use another constant as its length.
3668
@test fn testConstArrayWithConstLength() throws (testing::TestError) {
3669
    let mut a = testResolver();
3670
    let program = "const LEN: u32 = 3; const ARR: [i32; LEN] = [1, 2, 3];";
3671
    let result = try resolveProgramStr(&mut a, program);
3672
    try expectNoErrors(&result);
3673
3674
    // Verify the array constant has the correct type with length 3.
3675
    let arrStmt = try getBlockStmt(result.root, 1);
3676
    let sym = super::symbolFor(&a, arrStmt)
3677
        else throw testing::TestError::Failed;
3678
    let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
3679
        else throw testing::TestError::Failed;
3680
    try testing::expect(arrType.length == 3);
3681
}
3682
3683
/// Test that a record field can use a constant as its array length.
3684
@test fn testRecordFieldWithConstArrayLength() throws (testing::TestError) {
3685
    let mut a = testResolver();
3686
    let program = "const SIZE: u32 = 4; record Buffer { data: [i32; SIZE], }";
3687
    let result = try resolveProgramStr(&mut a, program);
3688
    try expectNoErrors(&result);
3689
}
3690
3691
/// Test that a constant can have a record literal value (lazy record body resolution).
3692
@test fn testConstWithRecordLiteral() throws (testing::TestError) {
3693
    let mut a = testResolver();
3694
    let program = "record Point { x: i32, y: i32 } const ORIGIN: Point = Point { x: 0, y: 0 };";
3695
    let result = try resolveProgramStr(&mut a, program);
3696
    try expectNoErrors(&result);
3697
}
3698
3699
/// Test that a constant can have a union variant value (lazy union body resolution).
3700
@test fn testConstWithUnionVariant() throws (testing::TestError) {
3701
    let mut a = testResolver();
3702
    let program = "union Color { Red, Green, Blue } const DEFAULT: Color = Color::Red;";
3703
    let result = try resolveProgramStr(&mut a, program);
3704
    try expectNoErrors(&result);
3705
}
3706
3707
/// Test that record field types can reference imported types.
3708
///
3709
/// This tests that `use` statements are processed before record body resolution,
3710
/// allowing record fields to use types from imported modules.
3711
@test fn testRecordFieldUsesImportedType() throws (testing::TestError) {
3712
    let mut a = testResolver();
3713
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3714
3715
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod types; mod scanner;", &mut arena);
3716
    let typesId = try registerModule(&mut MODULE_GRAPH, rootId, "types", "pub record Pool { count: u32 }", &mut arena);
3717
    let scannerId = try registerModule(&mut MODULE_GRAPH, rootId, "scanner", "use root::types; record Scanner { pool: *types::Pool }", &mut arena);
3718
3719
    let result = try resolveModuleTree(&mut a, rootId);
3720
    try expectNoErrors(&result);
3721
}
3722
3723
/// Test that imported constants can be used in array size expressions.
3724
///
3725
/// This tests that constant values are propagated through scope access expressions,
3726
/// enabling compile-time evaluation of array sizes using imported constants.
3727
@test fn testImportedConstantInArraySize() throws (testing::TestError) {
3728
    let mut a = testResolver();
3729
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3730
3731
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod consts; mod app;", &mut arena);
3732
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "pub const SIZE: u32 = 8;", &mut arena);
3733
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; static BUFFER: [u8; consts::SIZE] = undefined;", &mut arena);
3734
3735
    let result = try resolveModuleTree(&mut a, rootId);
3736
    try expectNoErrors(&result);
3737
}
3738
3739
/// Test that `if let case` binds payload variables in the then branch.
3740
///
3741
/// When using `if let case Union::Variant(x) = expr { ... }`, the variable `x` should
3742
/// be bound to the payload value within the then branch scope.
3743
@test fn testResolveIfCaseBindsPayload() throws (testing::TestError) {
3744
    let mut a = testResolver();
3745
    let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { if let case Opt::Some(x) = value { return x; } return 0; }";
3746
    let result = try resolveProgramStr(&mut a, program);
3747
    try expectNoErrors(&result);
3748
}
3749
3750
/// Test that `if let case` payload binding is scoped to the then branch.
3751
///
3752
/// The payload variable should not be accessible outside the then branch.
3753
@test fn testResolveIfCasePayloadScopeError() throws (testing::TestError) {
3754
    let mut a = testResolver();
3755
    let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { if let case Opt::Some(x) = value {} return x; }";
3756
    let result = try resolveProgramStr(&mut a, program);
3757
    let err = try expectError(&result);
3758
    let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
3759
        else throw testing::TestError::Failed;
3760
    try testing::expect(mem::eq(name, "x"));
3761
}
3762
3763
/// Test that `let case` binds payload variables in the current scope.
3764
///
3765
/// When using `let case Union::Variant(x) = expr else { ... }`, the variable `x`
3766
/// should be bound in the scope after the statement.
3767
@test fn testResolveLetCaseElseBindsPayload() throws (testing::TestError) {
3768
    let mut a = testResolver();
3769
    let program = "union Opt { Some(i32), None } fn f(value: Opt) -> i32 { let case Opt::Some(x) = value else panic; return x; }";
3770
    let result = try resolveProgramStr(&mut a, program);
3771
    try expectNoErrors(&result);
3772
}
3773
3774
/// Test that function pointers with identical signatures are assignable.
3775
///
3776
/// Two function types with the same parameters, return type, and throw list
3777
/// should be considered structurally equal, even if they are separate allocations.
3778
@test fn testFnPointerAssignability() throws (testing::TestError) {
3779
    let mut a = testResolver();
3780
    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);";
3781
    let result = try resolveProgramStr(&mut a, program);
3782
    try expectNoErrors(&result);
3783
}
3784
3785
/// Test that function pointers with different parameter types are not assignable.
3786
@test fn testFnPointerParamMismatch() throws (testing::TestError) {
3787
    let mut a = testResolver();
3788
    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);";
3789
    let result = try resolveProgramStr(&mut a, program);
3790
    let err = try expectError(&result);
3791
    let case super::ErrorKind::TypeMismatch(_) = err.kind
3792
        else throw testing::TestError::Failed;
3793
}
3794
3795
/// Test that function pointers with different return types are not assignable.
3796
@test fn testFnPointerReturnMismatch() throws (testing::TestError) {
3797
    let mut a = testResolver();
3798
    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);";
3799
    let result = try resolveProgramStr(&mut a, program);
3800
    let err = try expectError(&result);
3801
    let case super::ErrorKind::TypeMismatch(_) = err.kind
3802
        else throw testing::TestError::Failed;
3803
}
3804
3805
/// Test that named records use nominal typing, not structural.
3806
///
3807
/// Two different named record types with identical fields should NOT be
3808
/// assignable to each other, because they are distinct nominal types.
3809
@test fn testNamedRecordNominalTyping() throws (testing::TestError) {
3810
    let mut a = testResolver();
3811
    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);";
3812
    let result = try resolveProgramStr(&mut a, program);
3813
    let err = try expectError(&result);
3814
    let case super::ErrorKind::TypeMismatch(_) = err.kind
3815
        else throw testing::TestError::Failed;
3816
}
3817
3818
/// Test that union variants with labeled record payloads can be constructed.
3819
@test fn testUnionVariantAnonRecordPayload() throws (testing::TestError) {
3820
    let mut a = testResolver();
3821
    let program = "union Event { Click { x: i32, y: i32 }, Key { code: u32 } } let e = Event::Click { x: 10, y: 20 };";
3822
    let result = try resolveProgramStr(&mut a, program);
3823
    try expectNoErrors(&result);
3824
}
3825
3826
/// Test that unlabeled record literals with positional fields work correctly.
3827
///
3828
/// When a record is declared with positional fields (e.g., `record R(i32, bool)`),
3829
/// the literal must use constructor call syntax with positional arguments.
3830
@test fn testResolveUnlabeledRecordLitValid() throws (testing::TestError) {
3831
    let mut a = testResolver();
3832
    let program = "record R(i32, bool); let r: R = R(1, true);";
3833
    let result = try resolveProgramStr(&mut a, program);
3834
    try expectNoErrors(&result);
3835
}
3836
3837
/// Test that using brace syntax for an unlabeled record causes an error.
3838
@test fn testResolveUnlabeledRecordLitStyleMismatch() throws (testing::TestError) {
3839
    let mut a = testResolver();
3840
    let program = "record R(i32); let r = R { x: 1 };";
3841
    let result = try resolveProgramStr(&mut a, program);
3842
    try expectErrorKind(&result, super::ErrorKind::RecordFieldStyleMismatch);
3843
}
3844
3845
/// Test that providing too many fields for an unlabeled record causes count mismatch.
3846
@test fn testResolveUnlabeledRecordLitTooManyFields() throws (testing::TestError) {
3847
    let mut a = testResolver();
3848
    let program = "record R(i32, bool); let r = R(1, true, 3);";
3849
    let result = try resolveProgramStr(&mut a, program);
3850
    let err = try expectError(&result);
3851
    let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
3852
        else throw testing::TestError::Failed;
3853
}
3854
3855
/// Test that match pattern with wrong number of bindings causes count mismatch.
3856
@test fn testResolveMatchPatternWrongBindingCount() throws (testing::TestError) {
3857
    let mut a = testResolver();
3858
    let program = "union Event { Click { x: i32, y: i32 } } fn f(e: Event) { match e { case Event::Click(a) => {} } }";
3859
    let result = try resolveProgramStr(&mut a, program);
3860
    let err = try expectError(&result);
3861
    let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
3862
        else throw testing::TestError::Failed;
3863
}
3864
3865
/// Test that shorthand field syntax works in record literals.
3866
/// `Point { x, y }` should be equivalent to `Point { x: x, y: y }`.
3867
@test fn testResolveRecordLiteralShorthand() throws (testing::TestError) {
3868
    let mut a = testResolver();
3869
    let program = "record Point { x: i32, y: i32 } fn f() { let x: i32 = 1; let y: i32 = 2; let p = Point { x, y }; }";
3870
    let result = try resolveProgramStr(&mut a, program);
3871
    try expectNoErrors(&result);
3872
}
3873
3874
/// Test shorthand field syntax with mixed explicit and shorthand fields.
3875
@test fn testResolveRecordLiteralMixedShorthand() throws (testing::TestError) {
3876
    let mut a = testResolver();
3877
    let program = "record Point { x: i32, y: i32 } fn f() { let x: i32 = 5; let p = Point { x, y: 10 }; }";
3878
    let result = try resolveProgramStr(&mut a, program);
3879
    try expectNoErrors(&result);
3880
}
3881
3882
/// Test record-style union variant patterns with shorthand syntax.
3883
@test fn testResolveMatchRecordPatternShorthand() throws (testing::TestError) {
3884
    let mut a = testResolver();
3885
    let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { width, height } => return width + height } }";
3886
    let result = try resolveProgramStr(&mut a, program);
3887
    try expectNoErrors(&result);
3888
}
3889
3890
/// Test record pattern with mixed shorthand and explicit labels.
3891
@test fn testResolveMatchRecordPatternMixed() throws (testing::TestError) {
3892
    let mut a = testResolver();
3893
    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 } }";
3894
    let result = try resolveProgramStr(&mut a, program);
3895
    try expectNoErrors(&result);
3896
}
3897
3898
/// Test record pattern with fields in reverse order.
3899
@test fn testResolveMatchRecordPatternReversed() throws (testing::TestError) {
3900
    let mut a = testResolver();
3901
    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 } }";
3902
    let result = try resolveProgramStr(&mut a, program);
3903
    try expectNoErrors(&result);
3904
}
3905
3906
/// Test record pattern with shorthand syntax in reverse order.
3907
/// Pattern `{ height, width }` binds all fields using shorthand, but not in definition order.
3908
@test fn testResolveMatchRecordPatternShorthandReversed() throws (testing::TestError) {
3909
    let mut a = testResolver();
3910
    let program = "union Shape { Rect { width: i32, height: i32 } } fn f(s: Shape) -> i32 { match s { case Shape::Rect { height, width } => return width + height } }";
3911
    let result = try resolveProgramStr(&mut a, program);
3912
    try expectNoErrors(&result);
3913
}
3914
3915
/// Test record pattern with `..` ignoring fields.
3916
@test fn testResolveMatchRecordPatternIgnoreRest() throws (testing::TestError) {
3917
    {
3918
        let mut a = testResolver();
3919
        let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { x, .. } => return x } }";
3920
        let result = try resolveProgramStr(&mut a, program);
3921
        try expectNoErrors(&result);
3922
    } {
3923
        let mut a = testResolver();
3924
        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 } }";
3925
        let result = try resolveProgramStr(&mut a, program);
3926
        try expectNoErrors(&result);
3927
    } {
3928
        let mut a = testResolver();
3929
        let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> i32 { match g { case G::Point { z, .. } => return z } }";
3930
        let result = try resolveProgramStr(&mut a, program);
3931
        try expectNoErrors(&result);
3932
    } {
3933
        let mut a = testResolver();
3934
        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 } }";
3935
        let result = try resolveProgramStr(&mut a, program);
3936
        try expectNoErrors(&result);
3937
    } {
3938
        let mut a = testResolver();
3939
        let program = "union G { Point { x: i32, y: i32, z: i32 } } fn f(g: G) -> bool { match g { case G::Point { .. } => return true } }";
3940
        let result = try resolveProgramStr(&mut a, program);
3941
        try expectNoErrors(&result);
3942
    }
3943
}
3944
3945
/// Test standalone record pattern matching with unlabeled patterns.
3946
@test fn testResolveMatchStandaloneRecordUnlabeledPattern() throws (testing::TestError) {
3947
    let mut a = testResolver();
3948
    let program = "record S(i32); fn f(s: S) -> i32 { match s { case S(x) => return x, else => return 0 } }";
3949
    let result = try resolveProgramStr(&mut a, program);
3950
    try expectNoErrors(&result);
3951
}
3952
3953
/// Test standalone record pattern matching with labeled patterns.
3954
/// Pattern syntax: `T { x }` matches a named record and binds x to the field.
3955
@test fn testResolveMatchStandaloneRecordLabeledPattern() throws (testing::TestError) {
3956
    let mut a = testResolver();
3957
    let program = "record T { x: i32 } fn f(t: T) -> i32 { match t { case T { x } => return x, else => return 0 } }";
3958
    let result = try resolveProgramStr(&mut a, program);
3959
    try expectNoErrors(&result);
3960
}
3961
3962
/// Test standalone record pattern with multiple fields.
3963
/// Pattern syntax: `R(a, b)` matches an unlabeled record with multiple fields.
3964
@test fn testResolveMatchStandaloneRecordMultipleFields() throws (testing::TestError) {
3965
    let mut a = testResolver();
3966
    let program = "record R(bool, u8); fn f(r: R) -> u8 { match r { case R(_, x) => return x, else => return 0 } }";
3967
    let result = try resolveProgramStr(&mut a, program);
3968
    try expectNoErrors(&result);
3969
}
3970
3971
/// Test standalone record pattern with wrong field count.
3972
/// Pattern `S(x, y)` should fail for a single-field record.
3973
@test fn testResolveMatchStandaloneRecordWrongFieldCount() throws (testing::TestError) {
3974
    let mut a = testResolver();
3975
    let program = "record S(i32); fn f(s: S) -> i32 { match s { case S(x, y) => return x + y, else => return 0 } }";
3976
    let result = try resolveProgramStr(&mut a, program);
3977
    let err = try expectError(&result);
3978
    let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
3979
        else throw testing::TestError::Failed;
3980
}
3981
3982
/// Test array pattern matching with element bindings.
3983
/// Pattern syntax: `[x, y]` matches an array and binds elements.
3984
@test fn testResolveMatchArrayPattern() throws (testing::TestError) {
3985
    let mut a = testResolver();
3986
    let program = "fn f(arr: [i32; 2]) -> i32 { match arr { case [x, y] => return x + y } }";
3987
    let result = try resolveProgramStr(&mut a, program);
3988
    try expectNoErrors(&result);
3989
}
3990
3991
/// Test array pattern with placeholder elements.
3992
/// Pattern syntax: `[_, y]` ignores first element.
3993
@test fn testResolveMatchArrayPatternPlaceholder() throws (testing::TestError) {
3994
    let mut a = testResolver();
3995
    let program = "fn f(arr: [i32; 2]) -> i32 { match arr { case [_, y] => return y } }";
3996
    let result = try resolveProgramStr(&mut a, program);
3997
    try expectNoErrors(&result);
3998
}
3999
4000
/// Test identifier pattern that binds the whole value.
4001
/// Pattern syntax: `x` matches any value and binds it.
4002
@test fn testResolveMatchIdentPattern() throws (testing::TestError) {
4003
    let mut a = testResolver();
4004
    let program = "fn f(val: i32) -> i32 { match val { x => return x } }";
4005
    let result = try resolveProgramStr(&mut a, program);
4006
    try expectNoErrors(&result);
4007
}
4008
4009
/// Test numeric literal pattern matching.
4010
@test fn testResolveMatchNumericLiteralPattern() throws (testing::TestError) {
4011
    let mut a = testResolver();
4012
    let program = "fn f(val: i32) -> i32 { match val { case 42 => return 1, else => return 0 } }";
4013
    let result = try resolveProgramStr(&mut a, program);
4014
    try expectNoErrors(&result);
4015
}
4016
4017
/// Test string literal pattern matching.
4018
@test fn testResolveMatchStringLiteralPattern() throws (testing::TestError) {
4019
    let mut a = testResolver();
4020
    let program = "fn f(val: *[u8]) -> i32 { match val { case \"hello\" => return 1, else => return 0 } }";
4021
    let result = try resolveProgramStr(&mut a, program);
4022
    try expectNoErrors(&result);
4023
}
4024
4025
/// Test boolean literal pattern matching.
4026
@test fn testResolveMatchBoolLiteralPattern() throws (testing::TestError) {
4027
    let mut a = testResolver();
4028
    let program = "fn f(val: bool) -> i32 { match val { case true => return 1, case false => return 0 } }";
4029
    let result = try resolveProgramStr(&mut a, program);
4030
    try expectNoErrors(&result);
4031
}
4032
4033
/// Test @sliceOf with correct arguments succeeds.
4034
@test fn testResolveSliceOfCorrect() throws (testing::TestError) {
4035
    // Immutable pointer.
4036
    {
4037
        let mut a = testResolver();
4038
        let program = "fn f(ptr: *u8, len: u32) -> *[u8] { return @sliceOf(ptr, len); }";
4039
        let result = try resolveProgramStr(&mut a, program);
4040
        try expectNoErrors(&result);
4041
    }
4042
    // Mutable pointer produces mutable slice.
4043
    {
4044
        let mut a = testResolver();
4045
        let program = "fn f(ptr: *mut u8, len: u32) -> *mut [u8] { return @sliceOf(ptr, len); }";
4046
        let result = try resolveProgramStr(&mut a, program);
4047
        try expectNoErrors(&result);
4048
    }
4049
}
4050
4051
/// Test @sliceOf with wrong argument count produces an error.
4052
@test fn testResolveSliceOfWrongArgCount() throws (testing::TestError) {
4053
    // No arguments.
4054
    {
4055
        let mut a = testResolver();
4056
        let program = "fn f() -> *[u8] { return @sliceOf(); }";
4057
        let result = try resolveProgramStr(&mut a, program);
4058
        let err = try expectError(&result);
4059
        let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
4060
            else throw testing::TestError::Failed;
4061
        try testing::expect(mismatch.expected == 2);
4062
        try testing::expect(mismatch.actual == 0);
4063
    }
4064
    // Too few arguments.
4065
    {
4066
        let mut a = testResolver();
4067
        let program = "fn f(ptr: *u8) -> *[u8] { return @sliceOf(ptr); }";
4068
        let result = try resolveProgramStr(&mut a, program);
4069
        let err = try expectError(&result);
4070
        let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
4071
            else throw testing::TestError::Failed;
4072
        try testing::expect(mismatch.expected == 2);
4073
        try testing::expect(mismatch.actual == 1);
4074
    }
4075
    // Too many arguments.
4076
    {
4077
        let mut a = testResolver();
4078
        let program = "fn f(ptr: *u8, len: u32, cap: u32, extra: u32) -> *[u8] { return @sliceOf(ptr, len, cap, extra); }";
4079
        let result = try resolveProgramStr(&mut a, program);
4080
        let err = try expectError(&result);
4081
        let case super::ErrorKind::BuiltinArgCountMismatch(mismatch) = err.kind
4082
            else throw testing::TestError::Failed;
4083
        try testing::expect(mismatch.expected == 2);
4084
        try testing::expect(mismatch.actual == 4);
4085
    }
4086
}
4087
4088
/// Test @sliceOf with wrong argument types produces errors.
4089
@test fn testResolveSliceOfWrongArgTypes() throws (testing::TestError) {
4090
    // Non-pointer first argument.
4091
    {
4092
        let mut a = testResolver();
4093
        let program = "fn f(val: u32, len: u32) -> *[u8] { return @sliceOf(val, len); }";
4094
        let result = try resolveProgramStr(&mut a, program);
4095
        let err = try expectError(&result);
4096
        let case super::ErrorKind::ExpectedPointer = err.kind
4097
            else throw testing::TestError::Failed;
4098
    }
4099
    // Array instead of pointer.
4100
    {
4101
        let mut a = testResolver();
4102
        let program = "fn f(arr: [u8; 4], len: u32) -> *[u8] { return @sliceOf(arr, len); }";
4103
        let result = try resolveProgramStr(&mut a, program);
4104
        let err = try expectError(&result);
4105
        let case super::ErrorKind::ExpectedPointer = err.kind
4106
            else throw testing::TestError::Failed;
4107
    }
4108
    // Non-numeric second argument.
4109
    {
4110
        let mut a = testResolver();
4111
        let program = "fn f(ptr: *u8, len: bool) -> *[u8] { return @sliceOf(ptr, len); }";
4112
        let result = try resolveProgramStr(&mut a, program);
4113
        let err = try expectError(&result);
4114
        let case super::ErrorKind::TypeMismatch(_) = err.kind
4115
            else throw testing::TestError::Failed;
4116
    }
4117
    // Pointer second argument.
4118
    {
4119
        let mut a = testResolver();
4120
        let program = "fn f(ptr: *u8, len: *u32) -> *[u8] { return @sliceOf(ptr, len); }";
4121
        let result = try resolveProgramStr(&mut a, program);
4122
        let err = try expectError(&result);
4123
        let case super::ErrorKind::TypeMismatch(_) = err.kind
4124
            else throw testing::TestError::Failed;
4125
    }
4126
}
4127
4128
/// Test @sliceOf with 3 arguments (ptr, len, cap) succeeds.
4129
@test fn testResolveSliceOfWithCap() throws (testing::TestError) {
4130
    {
4131
        let mut a = testResolver();
4132
        let program = "fn f(ptr: *u8, len: u32, cap: u32) -> *[u8] { return @sliceOf(ptr, len, cap); }";
4133
        let result = try resolveProgramStr(&mut a, program);
4134
        try expectNoErrors(&result);
4135
    }
4136
    // Mutable pointer produces mutable slice.
4137
    {
4138
        let mut a = testResolver();
4139
        let program = "fn f(ptr: *mut u8, len: u32, cap: u32) -> *mut [u8] { return @sliceOf(ptr, len, cap); }";
4140
        let result = try resolveProgramStr(&mut a, program);
4141
        try expectNoErrors(&result);
4142
    }
4143
}
4144
4145
/// Test @sliceOf with 3 arguments but wrong cap type.
4146
@test fn testResolveSliceOfCapWrongType() throws (testing::TestError) {
4147
    let mut a = testResolver();
4148
    let program = "fn f(ptr: *u8, len: u32, cap: bool) -> *[u8] { return @sliceOf(ptr, len, cap); }";
4149
    let result = try resolveProgramStr(&mut a, program);
4150
    let err = try expectError(&result);
4151
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4152
        else throw testing::TestError::Failed;
4153
}
4154
4155
/// Test .cap field access on slices resolves to u32.
4156
@test fn testResolveSliceCapField() throws (testing::TestError) {
4157
    let mut a = testResolver();
4158
    let program = "fn f(s: *[u8]) -> u32 { return s.cap; }";
4159
    let result = try resolveProgramStr(&mut a, program);
4160
    try expectNoErrors(&result);
4161
}
4162
4163
/// Test `.append()` on immutable slice produces an error.
4164
@test fn testResolveSliceAppendImmutable() throws (testing::TestError) {
4165
    let mut a = testResolver();
4166
    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); }";
4167
    let result = try resolveProgramStr(&mut a, program);
4168
    let err = try expectError(&result);
4169
    let case super::ErrorKind::ImmutableBinding = err.kind
4170
        else throw testing::TestError::Failed;
4171
}
4172
4173
/// Test `.append()` with wrong argument count produces an error.
4174
@test fn testResolveSliceAppendWrongArgCount() throws (testing::TestError) {
4175
    // Too few arguments.
4176
    {
4177
        let mut a = testResolver();
4178
        let program = "fn f(s: *mut [i32]) { s.append(1); }";
4179
        let result = try resolveProgramStr(&mut a, program);
4180
        let err = try expectError(&result);
4181
        let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
4182
            else throw testing::TestError::Failed;
4183
        try testing::expect(m.expected == 2);
4184
        try testing::expect(m.actual == 1);
4185
    }
4186
    // Too many arguments.
4187
    {
4188
        let mut a = testResolver();
4189
        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); }";
4190
        let result = try resolveProgramStr(&mut a, program);
4191
        let err = try expectError(&result);
4192
        let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
4193
            else throw testing::TestError::Failed;
4194
        try testing::expect(m.expected == 2);
4195
        try testing::expect(m.actual == 3);
4196
    }
4197
}
4198
4199
/// Test `.append()` with correct arguments succeeds.
4200
@test fn testResolveSliceAppendCorrect() throws (testing::TestError) {
4201
    let mut a = testResolver();
4202
    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); }";
4203
    let result = try resolveProgramStr(&mut a, program);
4204
    try expectNoErrors(&result);
4205
}
4206
4207
/// Test `.append()` with wrong element type produces an error.
4208
@test fn testResolveSliceAppendWrongElemType() throws (testing::TestError) {
4209
    let mut a = testResolver();
4210
    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); }";
4211
    let result = try resolveProgramStr(&mut a, program);
4212
    let err = try expectError(&result);
4213
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4214
        else throw testing::TestError::Failed;
4215
}
4216
4217
/// Test `.delete()` on immutable slice produces an error.
4218
@test fn testResolveSliceDeleteImmutable() throws (testing::TestError) {
4219
    let mut a = testResolver();
4220
    let program = "fn f(s: *[i32]) { s.delete(0); }";
4221
    let result = try resolveProgramStr(&mut a, program);
4222
    let err = try expectError(&result);
4223
    let case super::ErrorKind::ImmutableBinding = err.kind
4224
        else throw testing::TestError::Failed;
4225
}
4226
4227
/// Test `.delete()` with wrong argument count produces an error.
4228
@test fn testResolveSliceDeleteWrongArgCount() throws (testing::TestError) {
4229
    // No arguments.
4230
    {
4231
        let mut a = testResolver();
4232
        let program = "fn f(s: *mut [i32]) { s.delete(); }";
4233
        let result = try resolveProgramStr(&mut a, program);
4234
        let err = try expectError(&result);
4235
        let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
4236
            else throw testing::TestError::Failed;
4237
        try testing::expect(m.expected == 1);
4238
        try testing::expect(m.actual == 0);
4239
    }
4240
    // Too many arguments.
4241
    {
4242
        let mut a = testResolver();
4243
        let program = "fn f(s: *mut [i32]) { s.delete(0, 1); }";
4244
        let result = try resolveProgramStr(&mut a, program);
4245
        let err = try expectError(&result);
4246
        let case super::ErrorKind::FnArgCountMismatch(m) = err.kind
4247
            else throw testing::TestError::Failed;
4248
        try testing::expect(m.expected == 1);
4249
        try testing::expect(m.actual == 2);
4250
    }
4251
}
4252
4253
/// Test `.delete()` with correct arguments succeeds.
4254
@test fn testResolveSliceDeleteCorrect() throws (testing::TestError) {
4255
    let mut a = testResolver();
4256
    let program = "fn f(s: *mut [i32]) { s.delete(0); }";
4257
    let result = try resolveProgramStr(&mut a, program);
4258
    try expectNoErrors(&result);
4259
}
4260
4261
/// Test `.delete()` with wrong argument type produces an error.
4262
@test fn testResolveSliceDeleteWrongArgType() throws (testing::TestError) {
4263
    let mut a = testResolver();
4264
    let program = "fn f(s: *mut [i32]) { s.delete(true); }";
4265
    let result = try resolveProgramStr(&mut a, program);
4266
    let err = try expectError(&result);
4267
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4268
        else throw testing::TestError::Failed;
4269
}
4270
4271
/// Test `match &opt` produces immutable pointer bindings.
4272
@test fn testResolveMatchRefUnionBinding() throws (testing::TestError) {
4273
    let mut a = testResolver();
4274
    let program = "union Opt { Some(i32), None } fn f() { let opt = Opt::Some(42); match &opt { case Opt::Some(x) => { *x; } else => {} } }";
4275
    let result = try resolveProgramStr(&mut a, program);
4276
    try expectNoErrors(&result);
4277
4278
    let fnBlock = try getFnBody(&a, result.root, "f");
4279
    let matchNode = fnBlock.statements[1];
4280
    let case ast::NodeValue::Match(sw) = matchNode.value
4281
        else throw testing::TestError::Failed;
4282
    let caseNode = sw.prongs[0];
4283
4284
    let scope = super::scopeFor(&a, caseNode)
4285
        else throw testing::TestError::Failed;
4286
    let payloadSym = super::findSymbolInScope(scope, "x")
4287
        else throw testing::TestError::Failed;
4288
    let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
4289
        else throw testing::TestError::Failed;
4290
    let target = try expectPointerType(payloadValType, false);
4291
    try testing::expect(target == super::Type::I32);
4292
}
4293
4294
/// Test `match &mut opt` produces mutable pointer bindings.
4295
@test fn testResolveMatchMutRefUnionBinding() throws (testing::TestError) {
4296
    let mut a = testResolver();
4297
    let program = "union Opt { Some(i32), None } fn f() { let mut opt = Opt::Some(42); match &mut opt { case Opt::Some(x) => { *x; } else => {} } }";
4298
    let result = try resolveProgramStr(&mut a, program);
4299
    try expectNoErrors(&result);
4300
4301
    let fnBlock = try getFnBody(&a, result.root, "f");
4302
    let matchNode = fnBlock.statements[1];
4303
    let case ast::NodeValue::Match(sw) = matchNode.value
4304
        else throw testing::TestError::Failed;
4305
    let caseNode = sw.prongs[0];
4306
4307
    let scope = super::scopeFor(&a, caseNode)
4308
        else throw testing::TestError::Failed;
4309
    let payloadSym = super::findSymbolInScope(scope, "x")
4310
        else throw testing::TestError::Failed;
4311
    let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
4312
        else throw testing::TestError::Failed;
4313
    let target = try expectPointerType(payloadValType, true);
4314
    try testing::expect(target == super::Type::I32);
4315
}
4316
4317
/// Non-constant integer widening must use an explicit cast.
4318
@test fn testResolveIntegerWideningRequiresCast() throws (testing::TestError) {
4319
    {
4320
        let mut a = testResolver();
4321
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = x;");
4322
        let err = try expectError(&result);
4323
        try expectTypeMismatch(err, super::Type::U32, super::Type::U8);
4324
    } {
4325
        let mut a = testResolver();
4326
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u16 = x;");
4327
        let err = try expectError(&result);
4328
        try expectTypeMismatch(err, super::Type::U16, super::Type::U8);
4329
    } {
4330
        let mut a = testResolver();
4331
        let result = try resolveBlockStr(&mut a, "let x: u16 = 1; let y: u32 = x;");
4332
        let err = try expectError(&result);
4333
        try expectTypeMismatch(err, super::Type::U32, super::Type::U16);
4334
    } {
4335
        let mut a = testResolver();
4336
        let result = try resolveBlockStr(&mut a, "let x: i8 = 1; let y: i32 = x;");
4337
        let err = try expectError(&result);
4338
        try expectTypeMismatch(err, super::Type::I32, super::Type::I8);
4339
    } {
4340
        let mut a = testResolver();
4341
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = x as u32;");
4342
        try expectNoErrors(&result);
4343
    } {
4344
        let mut a = testResolver();
4345
        let result = try resolveBlockStr(&mut a, "let x: i8 = 1; let y: i32 = x as i32;");
4346
        try expectNoErrors(&result);
4347
    }
4348
}
4349
4350
/// Mixed-width integer binary ops require an explicit cast.
4351
@test fn testResolveIntegerWideningBinOpRequiresCast() throws (testing::TestError) {
4352
    {
4353
        let mut a = testResolver();
4354
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = x | y;");
4355
        let err = try expectError(&result);
4356
        try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
4357
    } {
4358
        let mut a = testResolver();
4359
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 0xFF; let z: u32 = x & y;");
4360
        let err = try expectError(&result);
4361
        try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
4362
    } {
4363
        let mut a = testResolver();
4364
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = x + y;");
4365
        let err = try expectError(&result);
4366
        try expectTypeMismatch(err, super::Type::U8, super::Type::U32);
4367
    } {
4368
        let mut a = testResolver();
4369
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u8 = x << 2;");
4370
        try expectNoErrors(&result);
4371
    } {
4372
        let mut a = testResolver();
4373
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = (x as u32) | y;");
4374
        try expectNoErrors(&result);
4375
    } {
4376
        let mut a = testResolver();
4377
        let result = try resolveBlockStr(&mut a, "let x: u8 = 1; let y: u32 = 2; let z: u32 = (x as u32) + y;");
4378
        try expectNoErrors(&result);
4379
    }
4380
}
4381
4382
/// A mutable slice pointer should be assignable to an immutable slice pointer.
4383
@test fn testResolveMutSliceAssignableToImmutSlice() throws (testing::TestError) {
4384
    let mut a = testResolver();
4385
    let result = try resolveBlockStr(&mut a, "let mut arr: [i32; 3] = [1, 2, 3]; let p: *mut [i32] = &mut arr[..]; let q: *[i32] = p;");
4386
    try expectNoErrors(&result);
4387
}
4388
4389
/// Comprehensive tests for `as` cast expressions.
4390
@test fn testResolveAsCasts() throws (testing::TestError) {
4391
    { // Pointer to numeric.
4392
        let mut a = testResolver();
4393
        let result = try resolveBlockStr(&mut a, "let x: i32 = 0; let p = &x; p as u32;");
4394
        try expectNoErrors(&result);
4395
    } { // Function pointer to numeric.
4396
        let mut a = testResolver();
4397
        let result = try resolveBlockStr(&mut a, "let f: fn() = undefined; f as u32;");
4398
        try expectNoErrors(&result);
4399
    } { // *u8 to *i32 (u8 to i32 is valid).
4400
        let mut a = testResolver();
4401
        let result = try resolveBlockStr(&mut a, "let p: *u8 = undefined; p as *i32;");
4402
        try expectNoErrors(&result);
4403
    } { // **u8 to **i32 (*u8 to *i32 is valid).
4404
        let mut a = testResolver();
4405
        let result = try resolveBlockStr(&mut a, "let p: **u8 = undefined; p as **i32;");
4406
        try expectNoErrors(&result);
4407
    }
4408
4409
    { // *[i32] to *[opaque].
4410
        let mut a = testResolver();
4411
        let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as *[opaque];");
4412
        try expectNoErrors(&result);
4413
    } { // *[opaque] to *[i32].
4414
        let mut a = testResolver();
4415
        let result = try resolveBlockStr(&mut a, "let s: *[opaque] = undefined; s as *[i32];");
4416
        try expectNoErrors(&result);
4417
    }
4418
4419
    { // *[i32] to *[u8].
4420
        let mut a = testResolver();
4421
        let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as *[u8];");
4422
        try expectNoErrors(&result);
4423
    } { // *[record] to *[u8].
4424
        let mut a = testResolver();
4425
        let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(s: *[R]) { s as *[u8]; }");
4426
        try expectNoErrors(&result);
4427
    }
4428
4429
    { // *[u8] to *[i32].
4430
        let mut a = testResolver();
4431
        let result = try resolveBlockStr(&mut a, "let s: *[u8] = undefined; s as *[i32];");
4432
        try expectNoErrors(&result);
4433
    } { // *[*u8] to *[*i32]
4434
        let mut a = testResolver();
4435
        let result = try resolveBlockStr(&mut a, "let s: *[*u8] = undefined; s as *[*i32];");
4436
        try expectNoErrors(&result);
4437
    }
4438
4439
    { // Identity cast: *mut [i32] to *mut [i32].
4440
        let mut a = testResolver();
4441
        let result = try resolveBlockStr(&mut a, "let s: *mut [i32] = undefined; s as *mut [i32];");
4442
        try expectNoErrors(&result);
4443
    } { // Identity cast: *i32 to *i32.
4444
        let mut a = testResolver();
4445
        let result = try resolveBlockStr(&mut a, "let p: *i32 = undefined; p as *i32;");
4446
        try expectNoErrors(&result);
4447
    } { // Identity cast: i32 to i32.
4448
        let mut a = testResolver();
4449
        let result = try resolveBlockStr(&mut a, "let x: i32 = 0; x as i32;");
4450
        try expectNoErrors(&result);
4451
    }
4452
}
4453
4454
/// Tests for invalid `as` casts that should be rejected.
4455
@test fn testResolveAsCastsInvalid() throws (testing::TestError) {
4456
    { // Pointer to slice is invalid.
4457
        let mut a = testResolver();
4458
        let result = try resolveBlockStr(&mut a, "let p: *i32 = undefined; p as *[i32];");
4459
        let err = try expectError(&result);
4460
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
4461
            else throw testing::TestError::Failed;
4462
    } { // Slice to pointer is invalid.
4463
        let mut a = testResolver();
4464
        let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as *i32;");
4465
        let err = try expectError(&result);
4466
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
4467
            else throw testing::TestError::Failed;
4468
    } { // *T to *i32 is invalid.
4469
        let mut a = testResolver();
4470
        let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(p: *R) { p as *i32; }");
4471
        let err = try expectError(&result);
4472
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
4473
            else throw testing::TestError::Failed;
4474
    } { // *[T] to *[i32] is invalid.
4475
        let mut a = testResolver();
4476
        let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(s: *[R]) { s as *[i32]; }");
4477
        let err = try expectError(&result);
4478
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
4479
            else throw testing::TestError::Failed;
4480
    } { // Slice to numeric is invalid.
4481
        let mut a = testResolver();
4482
        let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as u32;");
4483
        let err = try expectError(&result);
4484
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
4485
            else throw testing::TestError::Failed;
4486
    } { // *record to *u8 is invalid.
4487
        let mut a = testResolver();
4488
        let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(p: *R) { p as *u8; }");
4489
        let err = try expectError(&result);
4490
        let case super::ErrorKind::InvalidAsCast(_) = err.kind
4491
            else throw testing::TestError::Failed;
4492
    }
4493
}
4494
4495
/// Test that catch binding is available in catch block scope.
4496
@test fn testResolveTryCatchBinding() throws (testing::TestError) {
4497
    {
4498
        let mut a = testResolver();
4499
        let program = "union Error { Fail } fn fallible() -> u32 throws (Error) { throw Error::Fail; } fn caller() -> u32 { return try fallible() catch err { return 0; }; }";
4500
        let result = try resolveProgramStr(&mut a, program);
4501
        try expectNoErrors(&result);
4502
    } {
4503
        let mut a = testResolver();
4504
        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; } }; }";
4505
        let result = try resolveProgramStr(&mut a, program);
4506
        try expectNoErrors(&result);
4507
    } {
4508
        let mut a = testResolver();
4509
        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; }; }";
4510
        let result = try resolveProgramStr(&mut a, program);
4511
        try expectNoErrors(&result);
4512
    } {
4513
        let mut a = testResolver();
4514
        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, } }; }";
4515
        let result = try resolveProgramStr(&mut a, program);
4516
        try expectNoErrors(&result);
4517
    }
4518
}
4519
4520
/// Test that duplicate union variant patterns are detected.
4521
@test fn testResolveMatchDuplicateUnionPattern() throws (testing::TestError) {
4522
    {
4523
        let mut a = testResolver();
4524
        let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::A => {}, else => {} } }";
4525
        let result = try resolveProgramStr(&mut a, program);
4526
        try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
4527
    } {
4528
        // No duplicate: distinct variants are fine.
4529
        let mut a = testResolver();
4530
        let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::B => {} } }";
4531
        let result = try resolveProgramStr(&mut a, program);
4532
        try expectNoErrors(&result);
4533
    }
4534
}
4535
4536
/// Test that duplicate bool patterns are detected.
4537
@test fn testResolveMatchDuplicateBoolPattern() throws (testing::TestError) {
4538
    {
4539
        let mut a = testResolver();
4540
        let program = "fn f(x: bool) { match x { case true => {}, case true => {}, else => {} } }";
4541
        let result = try resolveProgramStr(&mut a, program);
4542
        try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
4543
    } {
4544
        let mut a = testResolver();
4545
        let program = "fn f(x: bool) { match x { case false => {}, case false => {}, else => {} } }";
4546
        let result = try resolveProgramStr(&mut a, program);
4547
        try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
4548
    }
4549
}
4550
4551
/// Test that duplicate nil patterns in optional match are detected.
4552
@test fn testResolveMatchDuplicateOptionalPattern() throws (testing::TestError) {
4553
    {
4554
        let mut a = testResolver();
4555
        let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {}, case nil => {} } }";
4556
        let result = try resolveProgramStr(&mut a, program);
4557
        try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
4558
    } {
4559
        // Duplicate value binding.
4560
        let mut a = testResolver();
4561
        let program = "fn f(opt: ?i32) { match opt { v => {}, w => {}, case nil => {} } }";
4562
        let result = try resolveProgramStr(&mut a, program);
4563
        try expectErrorKind(&result, super::ErrorKind::DuplicateMatchPattern);
4564
    }
4565
}
4566
4567
/// Test that guarded match arms are not considered duplicates.
4568
@test fn testResolveMatchGuardedNotDuplicate() throws (testing::TestError) {
4569
    {
4570
        // Guarded union variant followed by same variant is fine.
4571
        let mut a = testResolver();
4572
        let program = "union U { A, B } fn f(u: U) { match u { case U::A if true => {}, case U::A => {}, case U::B => {} } }";
4573
        let result = try resolveProgramStr(&mut a, program);
4574
        try expectNoErrors(&result);
4575
    } {
4576
        // Guarded bool pattern followed by same bool is fine.
4577
        let mut a = testResolver();
4578
        let program = "fn f(x: bool) { match x { case true if true => {}, case true => {}, case false => {} } }";
4579
        let result = try resolveProgramStr(&mut a, program);
4580
        try expectNoErrors(&result);
4581
    } {
4582
        // Guarded nil pattern followed by nil is fine.
4583
        let mut a = testResolver();
4584
        let program = "fn f(opt: ?i32) { match opt { case nil if true => {}, case nil => {}, v => {} } }";
4585
        let result = try resolveProgramStr(&mut a, program);
4586
        try expectNoErrors(&result);
4587
    } {
4588
        // Guarded value binding followed by another binding is fine.
4589
        let mut a = testResolver();
4590
        let program = "fn f(opt: ?i32) { match opt { v if true => {}, w => {}, case nil => {} } }";
4591
        let result = try resolveProgramStr(&mut a, program);
4592
        try expectNoErrors(&result);
4593
    }
4594
}
4595
4596
/// Test that unreachable else is detected when all union variants are covered.
4597
@test fn testResolveMatchUnreachableElseUnion() throws (testing::TestError) {
4598
    {
4599
        let mut a = testResolver();
4600
        let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, case U::B => {}, else => {} } }";
4601
        let result = try resolveProgramStr(&mut a, program);
4602
        try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
4603
    } {
4604
        // Partial coverage with else is fine.
4605
        let mut a = testResolver();
4606
        let program = "union U { A, B } fn f(u: U) { match u { case U::A => {}, else => {} } }";
4607
        let result = try resolveProgramStr(&mut a, program);
4608
        try expectNoErrors(&result);
4609
    }
4610
}
4611
4612
/// Test that unreachable else is detected when both bool cases are covered.
4613
@test fn testResolveMatchUnreachableElseBool() throws (testing::TestError) {
4614
    {
4615
        let mut a = testResolver();
4616
        let program = "fn f(x: bool) { match x { case true => {}, case false => {}, else => {} } }";
4617
        let result = try resolveProgramStr(&mut a, program);
4618
        try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
4619
    } {
4620
        // Only one case with else is fine.
4621
        let mut a = testResolver();
4622
        let program = "fn f(x: bool) { match x { case true => {}, else => {} } }";
4623
        let result = try resolveProgramStr(&mut a, program);
4624
        try expectNoErrors(&result);
4625
    }
4626
}
4627
4628
/// Test that unreachable else is detected when both optional cases are covered.
4629
@test fn testResolveMatchUnreachableElseOptional() throws (testing::TestError) {
4630
    {
4631
        let mut a = testResolver();
4632
        let program = "fn f(opt: ?i32) { match opt { v => {}, case nil => {}, else => {} } }";
4633
        let result = try resolveProgramStr(&mut a, program);
4634
        try expectErrorKind(&result, super::ErrorKind::UnreachableElse);
4635
    } {
4636
        // Only value binding with else is fine.
4637
        let mut a = testResolver();
4638
        let program = "fn f(opt: ?i32) { match opt { v => {}, else => {} } }";
4639
        let result = try resolveProgramStr(&mut a, program);
4640
        try expectNoErrors(&result);
4641
    }
4642
}
4643
4644
// --- Multi-error typed catch tests ---
4645
4646
@test fn testTypedCatchExhaustive() throws (testing::TestError) {
4647
    let mut a = testResolver();
4648
    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; }; }";
4649
    let result = try resolveProgramStr(&mut a, program);
4650
    try expectNoErrors(&result);
4651
}
4652
4653
@test fn testTypedCatchNonExhaustive() throws (testing::TestError) {
4654
    let mut a = testResolver();
4655
    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; }; }";
4656
    let result = try resolveProgramStr(&mut a, program);
4657
    try expectErrorKind(&result, super::ErrorKind::TryCatchNonExhaustive);
4658
}
4659
4660
@test fn testTypedCatchDuplicate() throws (testing::TestError) {
4661
    let mut a = testResolver();
4662
    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; }; }";
4663
    let result = try resolveProgramStr(&mut a, program);
4664
    try expectErrorKind(&result, super::ErrorKind::TryCatchDuplicateType);
4665
}
4666
4667
@test fn testTypedCatchWithCatchAll() throws (testing::TestError) {
4668
    let mut a = testResolver();
4669
    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; }; }";
4670
    let result = try resolveProgramStr(&mut a, program);
4671
    try expectNoErrors(&result);
4672
}
4673
4674
@test fn testTypedCatchWrongType() throws (testing::TestError) {
4675
    let mut a = testResolver();
4676
    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; }; }";
4677
    let result = try resolveProgramStr(&mut a, program);
4678
    try expectErrorKind(&result, super::ErrorKind::TryIncompatibleError);
4679
}
4680
4681
@test fn testInferredCatchMultiError() throws (testing::TestError) {
4682
    let mut a = testResolver();
4683
    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; }; }";
4684
    let result = try resolveProgramStr(&mut a, program);
4685
    try expectErrorKind(&result, super::ErrorKind::TryCatchMultiError);
4686
}
4687
4688
@test fn testResolveInstanceMissingMethod() throws (testing::TestError) {
4689
    let mut a = testResolver();
4690
    let program = "trait S { fn (*S) f() -> i32; } record R { x: i32 } instance S for R {}";
4691
    let result = try resolveProgramStr(&mut a, program);
4692
    try expectErrorKind(&result, super::ErrorKind::MissingTraitMethod("f"));
4693
}
4694
4695
@test fn testResolveInstanceUnknownMethod() throws (testing::TestError) {
4696
    let mut a = testResolver();
4697
    let program = "trait S { fn (*S) f() -> i32; } record R { x: i32 } instance S for R { fn (self: *R) x() -> i32 { return 0; } }";
4698
    let result = try resolveProgramStr(&mut a, program);
4699
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
4700
}
4701
4702
@test fn testResolveTraitDuplicateMethodRejected() throws (testing::TestError) {
4703
    let mut a = testResolver();
4704
    let program = "trait Adder { fn (*mut Adder) add(n: i32) -> i32; fn (*mut Adder) add(n: i32) -> i32; }";
4705
    let result = try resolveProgramStr(&mut a, program);
4706
    try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("add"));
4707
}
4708
4709
@test fn testResolveInstanceReceiverTypeMustMatchTarget() throws (testing::TestError) {
4710
    let mut a = testResolver();
4711
    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; } }";
4712
    let result = try resolveProgramStr(&mut a, program);
4713
    let err = try expectError(&result);
4714
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4715
        else throw testing::TestError::Failed;
4716
}
4717
4718
@test fn testResolveTraitMethodThrowsRequireTry() throws (testing::TestError) {
4719
    let mut a = testResolver();
4720
    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); }";
4721
    let result = try resolveProgramStr(&mut a, program);
4722
    try expectErrorKind(&result, super::ErrorKind::MissingTry);
4723
}
4724
4725
/// Trait declares immutable receiver (*Trait) but instance uses mutable (*mut Type).
4726
/// The instance method could mutate through what was originally an immutable pointer.
4727
@test fn testResolveInstanceMutReceiverOnImmutableTrait() throws (testing::TestError) {
4728
    let mut a = testResolver();
4729
    let program = "record Counter { value: i32 } trait Reader { fn (*Reader) read() -> i32; } instance Reader for Counter { fn (c: *mut Counter) read() -> i32 { c.value = c.value + 1; return c.value; } }";
4730
    let result = try resolveProgramStr(&mut a, program);
4731
    // Should reject: instance declares *mut receiver but trait only requires immutable.
4732
    try expectErrorKind(&result, super::ErrorKind::ReceiverMutabilityMismatch);
4733
}
4734
4735
/// Instance method declares different parameter types than the trait.
4736
/// The resolver should reject the mismatch rather than silently using the trait's types.
4737
@test fn testResolveInstanceParamTypeMismatch() throws (testing::TestError) {
4738
    let mut a = testResolver();
4739
    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 { a.value = a.value + n as i32; return a.value; } }";
4740
    let result = try resolveProgramStr(&mut a, program);
4741
    // Should reject: instance param type u8 doesn't match trait param type i32.
4742
    let err = try expectError(&result);
4743
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4744
        else throw testing::TestError::Failed;
4745
}
4746
4747
/// Duplicate instance declarations for the same (trait, type) pair should be rejected.
4748
@test fn testResolveInstanceDuplicateRejected() throws (testing::TestError) {
4749
    let mut a = testResolver();
4750
    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 { c.value = c.value + n; return c.value; } } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n + 100; return c.value; } }";
4751
    let result = try resolveProgramStr(&mut a, program);
4752
    // Should reject: duplicate instance for (Adder, Counter).
4753
    try expectErrorKind(&result, super::ErrorKind::DuplicateInstance);
4754
}
4755
4756
/// Trait method receiver must point to the declaring trait type.
4757
@test fn testResolveTraitReceiverMismatch() throws (testing::TestError) {
4758
    let mut a = testResolver();
4759
    let program = "record Other { x: i32 } trait Foo { fn (*mut Other) bar() -> i32; }";
4760
    let result = try resolveProgramStr(&mut a, program);
4761
    try expectErrorKind(&result, super::ErrorKind::TraitReceiverMismatch);
4762
}
4763
4764
/// Using a trait name as a value expression should be rejected.
4765
@test fn testResolveTraitNameAsValueRejected() throws (testing::TestError) {
4766
    let mut a = testResolver();
4767
    let program = "trait Foo { fn (*Foo) bar() -> i32; } fn test() -> i32 { let x = Foo; return 0; }";
4768
    let result = try resolveProgramStr(&mut a, program);
4769
    try expectErrorKind(&result, super::ErrorKind::UnexpectedTraitName);
4770
}
4771
4772
/// Cross-module trait: coerce to trait object and dispatch from a different module.
4773
@test fn testResolveTraitCrossModuleCoercion() throws (testing::TestError) {
4774
    let mut a = testResolver();
4775
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4776
4777
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod defs; mod app;", &mut arena);
4778
    let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "pub record Counter { value: i32 } pub trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } }", &mut arena);
4779
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::defs; fn test() -> i32 { let mut c = defs::Counter { value: 10 }; let a: *mut opaque defs::Adder = &mut c; return a.add(5); }", &mut arena);
4780
4781
    let result = try resolveModuleTree(&mut a, rootId);
4782
    try expectNoErrors(&result);
4783
}
4784
4785
/// Instance in a different module from trait and type.
4786
@test fn testResolveInstanceCrossModule() throws (testing::TestError) {
4787
    let mut a = testResolver();
4788
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4789
4790
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod defs; pub mod impls; mod app;", &mut arena);
4791
    let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "pub record Counter { value: i32 } pub trait Adder { fn (*mut Adder) add(n: i32) -> i32; }", &mut arena);
4792
    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 { c.value = c.value + n; return c.value; } }", &mut arena);
4793
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::defs; fn test() -> i32 { let mut c = defs::Counter { value: 10 }; let a: *mut opaque defs::Adder = &mut c; return a.add(5); }", &mut arena);
4794
4795
    let result = try resolveModuleTree(&mut a, rootId);
4796
    try expectNoErrors(&result);
4797
}
4798
4799
/// Calling a mutable-receiver trait method on an immutable trait object
4800
/// must be rejected.
4801
@test fn testResolveTraitMutMethodOnImmutableObject() throws (testing::TestError) {
4802
    let mut a = testResolver();
4803
    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 { c.value = c.value + n; return c.value; } } fn caller(a: *opaque Adder) -> i32 { return a.add(1); }";
4804
    let result = try resolveProgramStr(&mut a, program);
4805
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4806
}
4807
4808
/// Immutable methods on an immutable trait object should be accepted.
4809
@test fn testResolveTraitImmutableMethodOnImmutableObject() throws (testing::TestError) {
4810
    let mut a = testResolver();
4811
    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(); }";
4812
    let result = try resolveProgramStr(&mut a, program);
4813
    try expectNoErrors(&result);
4814
}
4815
4816
/// Both mutable and immutable methods on a mutable trait object should work.
4817
@test fn testResolveTraitMixedMethodsOnMutableObject() throws (testing::TestError) {
4818
    let mut a = testResolver();
4819
    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() { 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(); }";
4820
    let result = try resolveProgramStr(&mut a, program);
4821
    try expectNoErrors(&result);
4822
}
4823
4824
/// Instance method body type must match the trait return type.
4825
/// The trait declares `-> i32` but the body returns `bool`.
4826
@test fn testResolveInstanceReturnTypeMismatch() throws (testing::TestError) {
4827
    let mut a = testResolver();
4828
    let program = "record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() -> bool { return true; } }";
4829
    let result = try resolveProgramStr(&mut a, program);
4830
    let err = try expectError(&result);
4831
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4832
        else throw testing::TestError::Failed;
4833
}
4834
4835
/// Diamond supertrait inheritance: traits B and C both extend A.
4836
/// Declaring them independently should work fine.
4837
@test fn testResolveTraitDiamondSupertrait() throws (testing::TestError) {
4838
    let mut a = testResolver();
4839
    let program = "trait A { fn (*A) f() -> i32; } trait B: A { fn (*B) g() -> i32; } trait C: A { fn (*C) h() -> i32; }";
4840
    let result = try resolveProgramStr(&mut a, program);
4841
    try expectNoErrors(&result);
4842
}
4843
4844
/// Diamond supertrait with a combined trait that would cause duplicate
4845
/// method names should be detected.
4846
@test fn testResolveTraitDiamondDuplicateMethod() throws (testing::TestError) {
4847
    let mut a = testResolver();
4848
    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; }";
4849
    let result = try resolveProgramStr(&mut a, program);
4850
    // B inherits `f` from A, C inherits `f` from A. D: B + C sees duplicate `f`.
4851
    try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("f"));
4852
}
4853
4854
/// Supertrait instance must exist when declaring a combined trait instance.
4855
@test fn testResolveInstanceMissingSupertraitInstance() throws (testing::TestError) {
4856
    let mut a = testResolver();
4857
    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; } }";
4858
    let result = try resolveProgramStr(&mut a, program);
4859
    try expectErrorKind(&result, super::ErrorKind::MissingSupertraitInstance("Base"));
4860
}
4861
4862
/// Instance method omits return type when the trait declares `-> i32`.
4863
/// This is rejected -- the return type must be stated explicitly.
4864
@test fn testResolveInstanceReturnTypeOmitted() throws (testing::TestError) {
4865
    let mut a = testResolver();
4866
    let program = "record R { x: i32 } trait T { fn (*T) get() -> i32; } instance T for R { fn (r: *R) get() { } }";
4867
    let result = try resolveProgramStr(&mut a, program);
4868
    let err = try expectError(&result);
4869
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4870
        else throw testing::TestError::Failed;
4871
}
4872
4873
/// Instance method declares throws but the trait method does not throw.
4874
@test fn testResolveInstanceThrowsMismatchExtra() throws (testing::TestError) {
4875
    let mut a = testResolver();
4876
    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; } }";
4877
    let result = try resolveProgramStr(&mut a, program);
4878
    let err = try expectError(&result);
4879
    let case super::ErrorKind::FnThrowCountMismatch(_) = err.kind
4880
        else throw testing::TestError::Failed;
4881
}
4882
4883
/// Instance method declares a different throws type than the trait.
4884
@test fn testResolveInstanceThrowsMismatchWrongType() throws (testing::TestError) {
4885
    let mut a = testResolver();
4886
    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; } }";
4887
    let result = try resolveProgramStr(&mut a, program);
4888
    let err = try expectError(&result);
4889
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4890
        else throw testing::TestError::Failed;
4891
}
4892
4893
/// Instance method omits throws clause when trait declares throws.
4894
/// This is rejected -- the throws clause must match exactly.
4895
@test fn testResolveInstanceThrowsOmitted() throws (testing::TestError) {
4896
    let mut a = testResolver();
4897
    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; } }";
4898
    let result = try resolveProgramStr(&mut a, program);
4899
    let err = try expectError(&result);
4900
    let case super::ErrorKind::FnThrowCountMismatch(_) = err.kind
4901
        else throw testing::TestError::Failed;
4902
}
4903
4904
/// Instance method correctly matches the trait's throws clause.
4905
@test fn testResolveInstanceThrowsMatch() throws (testing::TestError) {
4906
    let mut a = testResolver();
4907
    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; } }";
4908
    let result = try resolveProgramStr(&mut a, program);
4909
    try expectNoErrors(&result);
4910
}
4911
4912
// Constant expression folding tests //////////////////////////////////////////
4913
4914
/// Resolve a program and verify that the constant at the given statement index
4915
/// has the expected integer magnitude.
4916
fn expectConstFold(program: *[u8], stmtIdx: u32, expected: u64)
4917
    throws (testing::TestError)
4918
{
4919
    let mut a = testResolver();
4920
    let result = try resolveProgramStr(&mut a, program);
4921
    try expectNoErrors(&result);
4922
4923
    let stmt = try getBlockStmt(result.root, stmtIdx);
4924
    let sym = super::symbolFor(&a, stmt)
4925
        else throw testing::TestError::Failed;
4926
    let case super::SymbolData::Constant { value, .. } = sym.data
4927
        else throw testing::TestError::Failed;
4928
    let val = value else throw testing::TestError::Failed;
4929
    let case super::ConstValue::Int(intVal) = val
4930
        else throw testing::TestError::Failed;
4931
    try testing::expect(intVal.magnitude == expected);
4932
}
4933
4934
/// Test arithmetic constant folding: add, sub, mul, div.
4935
@test fn testConstExprArithmetic() throws (testing::TestError) {
4936
    try expectConstFold("const A: i32 = 10; const B: i32 = 20; const C: i32 = A + B;", 2, 30);
4937
    try expectConstFold("const A: i32 = 50; const B: i32 = 20; const C: i32 = A - B;", 2, 30);
4938
    try expectConstFold("const A: i32 = 6; const B: i32 = 7; const C: i32 = A * B;", 2, 42);
4939
    try expectConstFold("const A: i32 = 100; const B: i32 = 5; const C: i32 = A / B;", 2, 20);
4940
}
4941
4942
/// Test bitwise constant folding: and, or, xor.
4943
@test fn testConstExprBitwise() throws (testing::TestError) {
4944
    try expectConstFold("const A: i32 = 0xFF; const B: i32 = 0x0F; const C: i32 = A & B;", 2, 0x0F);
4945
    try expectConstFold("const A: i32 = 0xF0; const B: i32 = 0x0F; const C: i32 = A | B;", 2, 0xFF);
4946
    try expectConstFold("const A: i32 = 0xFF; const B: i32 = 0x0F; const C: i32 = A ^ B;", 2, 0xF0);
4947
}
4948
4949
/// Test shift constant folding.
4950
@test fn testConstExprShift() throws (testing::TestError) {
4951
    try expectConstFold("const A: i32 = 1; const B: i32 = A << 4;", 1, 16);
4952
    try expectConstFold("const A: i32 = 32; const B: i32 = A >> 2;", 1, 8);
4953
}
4954
4955
/// Test chained constant expressions (C depends on A + B, D depends on C).
4956
@test fn testConstExprChained() throws (testing::TestError) {
4957
    try expectConstFold("const A: i32 = 10; const B: i32 = 20; const C: i32 = A + B; const D: i32 = C * 2;", 3, 60);
4958
}
4959
4960
/// Test constant expression used as array size.
4961
@test fn testConstExprAsArraySize() throws (testing::TestError) {
4962
    let mut a = testResolver();
4963
    let program = "const A: u32 = 2; const B: u32 = 3; const SIZE: u32 = A + B; const ARR: [i32; SIZE] = [1, 2, 3, 4, 5];";
4964
    let result = try resolveProgramStr(&mut a, program);
4965
    try expectNoErrors(&result);
4966
4967
    let arrStmt = try getBlockStmt(result.root, 3);
4968
    let sym = super::symbolFor(&a, arrStmt)
4969
        else throw testing::TestError::Failed;
4970
    let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
4971
        else throw testing::TestError::Failed;
4972
    try testing::expect(arrType.length == 5);
4973
}
4974
4975
/// Test cross-module constant expression: a constant in one module references
4976
/// a constant from another module via scope access.
4977
@test fn testCrossModuleConstExpr() throws (testing::TestError) {
4978
    let mut a = testResolver();
4979
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4980
4981
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod consts; mod app;", &mut arena);
4982
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "pub const BASE: i32 = 100;", &mut arena);
4983
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; const DERIVED: i32 = consts::BASE + 50;", &mut arena);
4984
4985
    let result = try resolveModuleTree(&mut a, rootId);
4986
    try expectNoErrors(&result);
4987
}
4988
4989
/// Test cross-module constant expression used as array size.
4990
@test fn testCrossModuleConstExprArraySize() throws (testing::TestError) {
4991
    let mut a = testResolver();
4992
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4993
4994
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "pub mod consts; mod app;", &mut arena);
4995
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "pub const WIDTH: u32 = 8; pub const HEIGHT: u32 = 4;", &mut arena);
4996
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; const TOTAL: u32 = consts::WIDTH * consts::HEIGHT; static BUF: [u8; TOTAL] = undefined;", &mut arena);
4997
4998
    let result = try resolveModuleTree(&mut a, rootId);
4999
    try expectNoErrors(&result);
5000
}
5001
5002
/// Test that non-constant expressions in const declarations are still rejected.
5003
@test fn testConstExprNonConstRejected() throws (testing::TestError) {
5004
    let mut a = testResolver();
5005
    let program = "fn value() -> i32 { return 1; } const BAD: i32 = value() + 1;";
5006
    let result = try resolveProgramStr(&mut a, program);
5007
    let err = try expectError(&result);
5008
    let case super::ErrorKind::ConstExprRequired = err.kind
5009
        else throw testing::TestError::Failed;
5010
}
5011
5012
/// Test unary negation in constant expressions.
5013
@test fn testConstExprUnaryNeg() throws (testing::TestError) {
5014
    let mut a = testResolver();
5015
    let program = "const A: i32 = 10; const B: i32 = -A;";
5016
    let result = try resolveProgramStr(&mut a, program);
5017
    try expectNoErrors(&result);
5018
}
5019
5020
/// Test unary not in constant expressions.
5021
@test fn testConstExprUnaryNot() throws (testing::TestError) {
5022
    let mut a = testResolver();
5023
    let program = "const A: bool = true; const B: bool = not A;";
5024
    let result = try resolveProgramStr(&mut a, program);
5025
    try expectNoErrors(&result);
5026
}
5027
5028
/// Test `as` casts in constant expressions: widening, narrowing, sign changes, chaining.
5029
@test fn testConstExprCast() throws (testing::TestError) {
5030
    try expectConstFold("const A: i32 = 42; const B: u64 = A as u64;", 1, 42);
5031
    try expectConstFold("const A: u64 = 10; const B: u8 = A as u8;", 1, 10);
5032
    try expectConstFold("const A: i32 = 7; const B: u32 = A as u32;", 1, 7);
5033
    try expectConstFold("const A: u32 = 100; const B: i32 = A as i32;", 1, 100);
5034
    try expectConstFold("const A: u8 = 5; const B: u64 = (A as u32) as u64;", 1, 5);
5035
    try expectConstFold("const A: u8 = 3; const B: u8 = 4; const C: i32 = (A as i32) + (B as i32);", 2, 7);
5036
    // Cast of unsuffixed literal arithmetic.
5037
    try expectConstFold("const A: u32 = (3 + 4) as u32;", 0, 7);
5038
    try expectConstFold("const A: u32 = ((3 + 4) as u64) as u32;", 0, 7);
5039
    try expectConstFold("const A: u32 = (3 + 4) as u32 + 1;", 0, 8);
5040
    try expectConstFold("const A: i32 = (2 as i32) * (3 + 4);", 0, 14);
5041
}
5042
5043
/// Test `as` cast in constant expressions used as array size.
5044
@test fn testConstExprCastAsArraySize() throws (testing::TestError) {
5045
    let mut a = testResolver();
5046
    let program = "const LEN: u64 = 4; const SIZE: u32 = LEN as u32; const ARR: [i32; SIZE] = [1, 2, 3, 4];";
5047
    let result = try resolveProgramStr(&mut a, program);
5048
    try expectNoErrors(&result);
5049
5050
    let arrStmt = try getBlockStmt(result.root, 2);
5051
    let sym = super::symbolFor(&a, arrStmt)
5052
        else throw testing::TestError::Failed;
5053
    let case super::SymbolData::Constant { type: super::Type::Array(arrType), .. } = sym.data
5054
        else throw testing::TestError::Failed;
5055
    try testing::expect(arrType.length == 4);
5056
}
5057
5058
/// Test unsuffixed integer literals in constant expressions.
5059
@test fn testConstExprUnsuffixedLiterals() throws (testing::TestError) {
5060
    try expectConstFold("const A: u32 = 4 * 4;", 0, 16);
5061
    try expectConstFold("const B: u32 = 10; const C: u32 = B * 2;", 1, 20);
5062
    try expectConstFold("const D: u32 = 3 + 7;", 0, 10);
5063
    try expectConstFold("const E: u32 = 2 * 3 + 4;", 0, 10);
5064
    try expectConstFold("const F: i32 = -(3 + 4);", 0, 7);
5065
}