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