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