lang: Implement explicit generics

28caf3e98df50e8d372eefa8cd54e7a4ea25cb68d9695da0f4a0b4046eef9cc0
Alexis Sellier committed ago 1 parent c7ed103c
compiler/radiance.rad +33 -29
33 33
/// Maximum number of test functions we can discover.
34 34
constant MAX_TESTS: u32 = 1024;
35 35
/// Maximum number of assembly source paths we can load per package.
36 36
constant MAX_ASM_MODULES: u32 = 64;
37 37
38 -
/// AST arena size (32 MB) - retains parsed nodes throughout compilation.
39 -
constant TEMP_ARENA_SIZE: u32 = 33554432;
38 +
/// AST arena size (40 MB) - retains parsed nodes throughout compilation.
39 +
constant TEMP_ARENA_SIZE: u32 = 41943040;
40 40
/// Per-function lowering and register-allocation arena size (16 MB).
41 41
constant FN_ARENA_SIZE: u32 = 16777216;
42 42
/// Main arena size (96 MB) - lives throughout compilation.
43 -
/// Used for: resolver data, types, symbols, global IL data, and codegen output.
43 +
/// Resolution owns the prefix it consumes; later phases own the remaining slice.
44 44
constant MAIN_ARENA_SIZE: u32 = 100663296;
45 45
46 46
/// AST storage arena.
47 47
static TEMP_ARENA: [u8; TEMP_ARENA_SIZE] = undefined;
48 48
/// Scratch storage reclaimed after each generated function.
494 494
495 495
/// Lower all packages into a single IL program.
496 496
/// Dependencies are lowered first, then the entry package.
497 497
fn lowerAllPackages(
498 498
    ctx: *mut CompileContext,
499 -
    res: *mut resolver::Resolver
499 +
    res: *resolver::Resolver,
500 +
    arena: *mut alloc::Arena,
500 501
) -> il::Program throws (Error) {
501 502
    let entryIdx = ctx.entryPkgIdx else {
502 503
        panic "lowerAllPackages: no entry package";
503 504
    };
504 505
    let entryPkg = &ctx.packages[entryIdx];
505 506
506 507
    // Create the lowerer accumulator using entry package's name.
507 508
    let options = lower::LowerOptions { debug: ctx.debug, buildTest: ctx.config.buildTest };
508 509
    let mut low = lower::lowerer(
509 -
        res, &ctx.graph, entryPkg.name, &mut res.arena, &mut res.arena, options
510 +
        res, &ctx.graph, entryPkg.name, arena, arena, options
510 511
    );
511 -
    try lowerAllPackagesInto(ctx, res, &mut low);
512 +
    try lowerAllPackagesInto(ctx, &mut low);
512 513
513 514
    // Finalize and return the unified program.
514 515
    return lower::finalize(&low);
515 516
}
516 517
517 518
/// Lower all packages into an existing lowerer.
518 519
fn lowerAllPackagesInto(
519 520
    ctx: *mut CompileContext,
520 -
    res: *mut resolver::Resolver,
521 -
    low: *mut lower::Lowerer
521 +
    low: *mut lower::Lowerer,
522 522
) throws (Error) {
523 523
    let entryIdx = ctx.entryPkgIdx else {
524 524
        panic "lowerAllPackagesInto: no entry package";
525 525
    };
526 526
    // Lower all packages except entry.
527 527
    for i in 0..ctx.packageCount {
528 528
        if i <> entryIdx {
529 -
            try lowerPackage(ctx, res, low, &mut ctx.packages[i], false);
529 +
            try lowerPackage(ctx, low, &mut ctx.packages[i], false);
530 530
        }
531 531
    }
532 532
    // Lower entry package.
533 -
    try lowerPackage(ctx, res, low, &mut ctx.packages[entryIdx], true);
533 +
    try lowerPackage(ctx, low, &mut ctx.packages[entryIdx], true);
534 534
}
535 535
536 536
/// Lower all modules in a package into the lowerer accumulator.
537 537
fn lowerPackage(
538 538
    ctx: *CompileContext,
539 -
    res: *mut resolver::Resolver,
540 539
    low: *mut lower::Lowerer,
541 540
    pkg: *mut package::Package,
542 541
    isEntry: bool
543 542
) throws (Error) {
544 543
    let rootId = pkg.rootModuleId else {
755 754
    let attrNode = ast::synthNode(arena, ast::NodeValue::Attribute(ast::Attribute::Default));
756 755
    let attrList = ast::nodeSlice(arena, 1).append(attrNode, a);
757 756
    let fnAttrs = ast::Attributes { list: attrList };
758 757
759 758
    return ast::synthNode(arena, ast::NodeValue::FnDecl(ast::FnDecl {
760 -
        name: fnName, sig: fnSig, body: fnBody, attrs: fnAttrs,
759 +
        name: fnName, params: ast::nodeSlice(arena, 0), sig: fnSig, body: fnBody, attrs: fnAttrs,
761 760
    }));
762 761
}
763 762
764 763
/// Append a declaration to a block node's statement list.
765 764
fn injectIntoBlock(
972 971
}
973 972
974 973
/// Lower all packages while streaming each lowered function into RV64 codegen.
975 974
fn lowerAndGenerateAllPackages(
976 975
    ctx: *mut CompileContext,
977 -
    res: *mut resolver::Resolver,
976 +
    res: *resolver::Resolver,
977 +
    arena: *mut alloc::Arena,
978 978
    fnArena: *mut alloc::Arena,
979 979
    codegenOptions: CodegenOptions
980 980
) -> rv64::Program throws (Error) {
981 981
    let entryIdx = ctx.entryPkgIdx else {
982 982
        panic "lowerAndGenerateAllPackages: no entry package";
995 995
        }
996 996
        else => {}
997 997
    }
998 998
    let mut generator = rv64::beginProgram(
999 999
        rv64::ProgramOptions { entryPatch, debug: codegenOptions.debug },
1000 -
        &mut res.arena
1000 +
        arena
1001 1001
    );
1002 1002
    let mut codegenCtx = CodegenSinkContext {
1003 1003
        generator: &mut generator,
1004 1004
        fnArena,
1005 1005
    };
1006 1006
    let mut low = lower::lowerer(
1007 -
        res, &ctx.graph, entryPkg.name, &mut res.arena, fnArena, options
1007 +
        res, &ctx.graph, entryPkg.name, arena, fnArena, options
1008 1008
    );
1009 1009
    set low.output = lower::FnOutput::Stream(lower::FnSink {
1010 1010
        ctx: &mut codegenCtx as *mut opaque,
1011 1011
        emitFn: generateLoweredFn,
1012 1012
    });
1013 1013
    let mut asmDataLen: u32 = 0;
1014 1014
    if let path = startupPath {
1015 -
        try assembleAsmModule(&mut generator, entryPkg, path, &mut asmDataLen, &mut res.arena);
1015 +
        try assembleAsmModule(&mut generator, entryPkg, path, &mut asmDataLen, arena);
1016 1016
    }
1017 -
    try lowerAllPackagesInto(ctx, res, &mut low);
1018 -
    let asmData = try assembleAsmInputs(ctx, &mut generator, &mut asmDataLen, &mut res.arena);
1017 +
    try lowerAllPackagesInto(ctx, &mut low);
1018 +
    let asmData = try assembleAsmInputs(ctx, &mut generator, &mut asmDataLen, arena);
1019 1019
1020 1020
    match generator.entryPatch {
1021 1021
        case rv64::EntryPatch::Reserved(targetName) => {
1022 1022
            if targetName == nil {
1023 1023
                throw error(&["fatal:", "no default function found"]);
1032 1032
}
1033 1033
1034 1034
/// Lower, optionally dump, and optionally generate binary output.
1035 1035
fn compile(
1036 1036
    ctx: *mut CompileContext,
1037 -
    res: *mut resolver::Resolver,
1038 -
    fnArena: *mut alloc::Arena
1037 +
    res: *resolver::Resolver,
1038 +
    arena: *mut alloc::Arena,
1039 +
    fnArena: *mut alloc::Arena,
1039 1040
) throws (Error) {
1040 1041
    let entryPkg = try getEntryPackage(ctx);
1041 1042
    let mut out = sexpr::Output::Stdout;
1042 1043
1043 1044
    if ctx.dump == Dump::Il {
1044 1045
        // Lower all packages into a single unified IL program for dumping.
1045 -
        let program = try lowerAllPackages(ctx, res);
1046 -
        il::printer::printProgram(&mut out, &mut res.arena, &program);
1046 +
        let program = try lowerAllPackages(ctx, res, arena);
1047 +
        il::printer::printProgram(&mut out, arena, &program);
1047 1048
        io::print("\n");
1048 1049
        return;
1049 1050
    }
1050 1051
    if ctx.dump == Dump::Asm {
1051 -
        let result = try lowerAndGenerateAllPackages(ctx, res, fnArena, CodegenOptions {
1052 +
        let result = try lowerAndGenerateAllPackages(ctx, res, arena, fnArena, CodegenOptions {
1052 1053
            logPath: nil,
1053 1054
            debug: false,
1054 1055
            entryMode: CodegenEntryMode::None,
1055 1056
        });
1056 -
        printer::printCodeTo(&mut out, entryPkg.name, result.code, result.funcs, &mut res.arena);
1057 +
        printer::printCodeTo(&mut out, entryPkg.name, result.code, result.funcs, arena);
1057 1058
        io::print("\n");
1058 1059
1059 1060
        return;
1060 1061
    }
1061 1062
    // Generate binary output if path specified.
1062 1063
    let outPath = ctx.outputPath else {
1063 -
        try lowerAllPackages(ctx, res);
1064 +
        try lowerAllPackages(ctx, res, arena);
1064 1065
        return;
1065 1066
    };
1066 1067
    let startupPath = getEntryStartupPath(ctx);
1067 -
    let result = try lowerAndGenerateAllPackages(ctx, res, fnArena, CodegenOptions {
1068 +
    let result = try lowerAndGenerateAllPackages(ctx, res, arena, fnArena, CodegenOptions {
1068 1069
        logPath: outPath,
1069 1070
        debug: ctx.debug,
1070 1071
        entryMode: CodegenEntryMode::None
1071 1072
            if startupPath <> nil
1072 1073
            else CodegenEntryMode::DefaultEntry,
1081 1082
        throw error(&["fatal:", "failed to write output file"]);
1082 1083
    }
1083 1084
1084 1085
    // Write debug info file if enabled.
1085 1086
    if ctx.debug {
1086 -
        try writeDebugInfo(result.debugEntries, &ctx.graph, outPath, &mut res.arena);
1087 +
        try writeDebugInfo(result.debugEntries, &ctx.graph, outPath, arena);
1087 1088
    }
1088 1089
    pkgLog(entryPkg, &["ok", "(", outPath, ")"]);
1089 1090
}
1090 1091
1091 1092
@default fn main(env: *sys::Env) -> i32 {
1111 1112
        try generateTestRunner(&mut ctx, &mut arena) catch {
1112 1113
            return 1;
1113 1114
        };
1114 1115
    }
1115 1116
    // Run resolution phase.
1116 -
    let mut res = try runResolver(&mut ctx, arena.nextId) catch {
1117 +
    let res = try runResolver(&mut ctx, arena.nextId) catch {
1117 1118
        return 1;
1118 1119
    };
1120 +
    // Continue from the resolver's final arena cursor through a phase-owned
1121 +
    // copy; lowering and code generation never mutate resolver state.
1122 +
    let mut compileArena = res.arena;
1119 1123
    let mut fnArena = alloc::new(&mut FN_ARENA[..]);
1120 1124
1121 1125
    // Lower, dump, and/or generate output.
1122 -
    try compile(&mut ctx, &mut res, &mut fnArena) catch {
1126 +
    try compile(&mut ctx, &res, &mut compileArena, &mut fnArena) catch {
1123 1127
        return 1;
1124 1128
    };
1125 1129
    return 0;
1126 1130
}
lib/std/lang/ast.rad +39 -1
17 17
    arena: alloc::Arena,
18 18
    /// Next node ID to assign. Incremented on each node allocation.
19 19
    nextId: u32,
20 20
}
21 21
22 +
/// Generic declaration parameter.
23 +
export union GenericParam {
24 +
    /// Rigid type parameter with optional trait bounds.
25 +
    Type {
26 +
        /// Parameter name.
27 +
        name: *Node,
28 +
        /// Trait bounds in declaration order.
29 +
        bounds: *mut [*Node],
30 +
    },
31 +
    /// Compile-time constant parameter.
32 +
    Const {
33 +
        /// Parameter name.
34 +
        name: *Node,
35 +
        /// Declared integer type.
36 +
        type: *Node,
37 +
    },
38 +
}
39 +
40 +
/// Application of ordered generic arguments to a declaration or path.
41 +
export record GenericApply {
42 +
    /// Declaration or path receiving the arguments.
43 +
    target: *Node,
44 +
    /// Arguments in source order.
45 +
    args: *mut [*Node],
46 +
}
47 +
22 48
/// Initialize a node arena backed by the given byte slice.
23 49
export fn nodeArena(data: *mut [u8]) -> NodeArena {
24 50
    return NodeArena {
25 51
        arena: alloc::new(data),
26 52
        nextId: 0,
472 498
473 499
/// Record declaration.
474 500
export record RecordDecl {
475 501
    /// Identifier naming the record.
476 502
    name: *Node,
503 +
    /// Generic parameters in declaration order.
504 +
    params: *mut [*Node],
477 505
    /// Field declaration nodes.
478 506
    fields: *mut [*Node],
479 507
    /// Optional attribute list applied to the record.
480 508
    attrs: ?Attributes,
481 509
    /// Trait derivations attached to the record.
486 514
487 515
/// Union declarations.
488 516
export record UnionDecl {
489 517
    /// Identifier naming the union.
490 518
    name: *Node,
519 +
    /// Generic parameters in declaration order.
520 +
    params: *mut [*Node],
491 521
    /// Variant nodes making up the union.
492 522
    variants: *mut [*Node],
493 523
    /// Optional attribute list applied to the union.
494 524
    attrs: ?Attributes,
495 525
    /// Trait derivations attached to the union.
510 540
511 541
/// Function declaration.
512 542
export record FnDecl {
513 543
    /// Identifier naming the function.
514 544
    name: *Node,
545 +
    /// Generic parameters in declaration order.
546 +
    params: *mut [*Node],
515 547
    /// Function type signature.
516 548
    sig: FnSig,
517 549
    /// Optional function body (`nil` for extern functions).
518 550
    body: ?*Node,
519 551
    /// Optional attribute list applied to the function.
617 649
        /// Array or slice.
618 650
        container: *Node,
619 651
        /// Index expression.
620 652
        index: *Node
621 653
    },
654 +
    /// Generic declaration or function application.
655 +
    GenericApply(GenericApply),
622 656
    /// Binary operator expression.
623 657
    BinOp(BinOp),
624 658
    /// Unary operator expression.
625 659
    UnOp(UnOp),
626 660
    /// Builtin function call (e.g. `@sizeOf(T)`).
723 757
    UnionDeclVariant(UnionDeclVariant),
724 758
    /// Attribute node.
725 759
    Attribute(Attribute),
726 760
    /// Record type declaration.
727 761
    RecordDecl(RecordDecl),
762 +
    /// Generic declaration parameter.
763 +
    GenericParam(GenericParam),
764 +
    /// Explicit generic specialization roots declared as one group.
765 +
    Instantiate(*mut [*Node]),
728 766
    /// Record field declaration.
729 767
    RecordField {
730 768
        /// Identifier bound by the declaration.
731 769
        field: ?*Node,
732 770
        /// Declared type annotation.
853 891
    let params: *mut [*Node] = &mut [];
854 892
    let throwList: *mut [*Node] = &mut [];
855 893
    let fnSig = FnSig { params, returnType: nil, throwList };
856 894
    let fnBody = synthNode(arena, NodeValue::Block(Block { statements: bodyStmts }));
857 895
    let fnDecl = synthNode(arena, NodeValue::FnDecl(FnDecl {
858 -
        name: fnName, sig: fnSig, body: fnBody, attrs: nil,
896 +
        name: fnName, params: &mut [], sig: fnSig, body: fnBody, attrs: nil,
859 897
    }));
860 898
    let mut rootStmts: *mut [*Node] = &mut [];
861 899
    rootStmts.append(fnDecl, a);
862 900
    let modBody = synthNode(arena, NodeValue::Block(Block { statements: rootStmts }));
863 901
lib/std/lang/ast/printer.rad +33 -0
293 293
        }
294 294
        case super::NodeValue::BuiltinCall { kind, args } =>
295 295
            return sexpr::list(a, builtinName(kind), nodeListToExprs(a, &args[..])),
296 296
        case super::NodeValue::Subscript { container, index } =>
297 297
            return sexpr::list(a, "[]", &[toExpr(a, container), toExpr(a, index)]),
298 +
        case super::NodeValue::GenericApply(app) => {
299 +
            let buf = try! sexpr::allocExprs(a, app.args.len as u32 + 1);
300 +
            set buf[0] = toExpr(a, app.target);
301 +
            for arg, i in app.args { set buf[i + 1] = toExpr(a, arg); }
302 +
            return sexpr::Expr::List { head: "apply", tail: buf, multiline: false };
303 +
        }
298 304
        case super::NodeValue::FieldAccess(acc) =>
299 305
            return sexpr::list(a, ".", &[toExpr(a, acc.parent), toExpr(a, acc.child)]),
300 306
        case super::NodeValue::ScopeAccess(acc) =>
301 307
            return sexpr::list(a, "::", &[toExpr(a, acc.parent), toExpr(a, acc.child)]),
302 308
        case super::NodeValue::AddressOf(addr) =>
448 454
            return prongToExpr(a, p);
449 455
        }
450 456
        case super::NodeValue::FnDecl(f) => {
451 457
            let params = sexpr::list(a, "params", nodeListToExprs(a, &f.sig.params[..]));
452 458
            let ret = toExprOrNull(a, f.sig.returnType);
459 +
            if f.params.len > 0 {
460 +
                let generics = sexpr::list(a, "generics", nodeListToExprs(a, &f.params[..]));
461 +
                if let body = f.body {
462 +
                    return sexpr::block(a, "fn", &[toExpr(a, f.name), generics, params, ret], &[toExpr(a, body)]);
463 +
                }
464 +
                return sexpr::list(a, "fn", &[toExpr(a, f.name), generics, params, ret]);
465 +
            }
453 466
            if let body = f.body {
454 467
                return sexpr::block(a, "fn", &[toExpr(a, f.name), params, ret], &[toExpr(a, body)]);
455 468
            }
456 469
            return sexpr::list(a, "fn", &[toExpr(a, f.name), params, ret]);
457 470
        }
458 471
        case super::NodeValue::Mod(m) => return sexpr::list(a, "mod", &[toExpr(a, m.name)]),
459 472
        case super::NodeValue::Use(u_) => return sexpr::list(a, "use", &[toExpr(a, u_.path)]),
460 473
        case super::NodeValue::RecordDecl(r) => {
461 474
            let children = fieldListToExprs(a, &r.fields[..]);
475 +
            if r.params.len > 0 {
476 +
                let generics = sexpr::list(a, "generics", nodeListToExprs(a, &r.params[..]));
477 +
                return sexpr::block(a, "record", &[toExpr(a, r.name), generics], children);
478 +
            }
462 479
            return sexpr::block(a, "record", &[toExpr(a, r.name)], children);
463 480
        }
464 481
        case super::NodeValue::RecordField { field, type, value } => {
465 482
            return fieldToExpr(a, field, type, value);
466 483
        }
467 484
        case super::NodeValue::UnionDecl(u_) => {
468 485
            let children = variantListToExprs(a, &u_.variants[..]);
486 +
            if u_.params.len > 0 {
487 +
                let generics = sexpr::list(a, "generics", nodeListToExprs(a, &u_.params[..]));
488 +
                return sexpr::block(a, "union", &[toExpr(a, u_.name), generics], children);
489 +
            }
469 490
            return sexpr::block(a, "union", &[toExpr(a, u_.name)], children);
470 491
        }
471 492
        case super::NodeValue::UnionDeclVariant(v) => {
472 493
            return variantToExpr(a, v.name, v.type);
473 494
        }
474 495
        case super::NodeValue::ExprStmt(e) => return toExpr(a, e),
496 +
        case super::NodeValue::GenericParam(param) => {
497 +
            match param {
498 +
                case super::GenericParam::Type { name, bounds } => {
499 +
                    let boundExpr = sexpr::list(a, "bounds", nodeListToExprs(a, &bounds[..]));
500 +
                    return sexpr::list(a, "type-param", &[toExpr(a, name), boundExpr]);
501 +
                }
502 +
                case super::GenericParam::Const { name, type } =>
503 +
                    return sexpr::list(a, "const-param", &[toExpr(a, name), toExpr(a, type)]),
504 +
            }
505 +
        }
506 +
        case super::NodeValue::Instantiate(applications) =>
507 +
            return sexpr::list(a, "instantiate", nodeListToExprs(a, &applications[..])),
475 508
        case super::NodeValue::TraitDecl { name, supertraits, methods, .. } => {
476 509
            let children = nodeListToExprs(a, &methods[..]);
477 510
            let supers = sexpr::list(a, "supertraits", nodeListToExprs(a, &supertraits[..]));
478 511
            return sexpr::block(a, "trait", &[toExpr(a, name), supers], children);
479 512
        }
lib/std/lang/lower.rad +938 -176
85 85
//!       ↓
86 86
//!   il::DataValue
87 87
//!       ↓
88 88
//!   il::Data
89 89
//!
90 +
/// Unit tests for lowering.
91 +
@test mod tests;
92 +
90 93
use std::fmt;
91 94
use std::io;
92 95
use std::lang::alloc;
93 96
use std::lang::types;
94 97
use std::mem;
163 166
    UnknownIntrinsic,
164 167
    /// Allocation failure.
165 168
    AllocationFailed,
166 169
}
167 170
171 +
/// Incrementally build deterministic internal symbol names.
172 +
record NameBuilder {
173 +
    /// Accumulated name bytes.
174 +
    bytes: *mut [u8],
175 +
    /// Allocator used to grow the name.
176 +
    allocator: alloc::Allocator,
177 +
}
178 +
168 179
/// Print a LowerError for debugging.
169 180
export fn printError(err: LowerError) {
170 181
    match err {
171 182
        case LowerError::MissingSymbol(_) => io::print("MissingSymbol"),
172 183
        case LowerError::MissingType(_) => io::print("MissingType"),
278 289
    Accumulate(*mut [*il::Fn]),
279 290
    /// Send lowered functions to an external consumer immediately.
280 291
    Stream(FnSink),
281 292
}
282 293
283 -
/// Module-level lowering context. Shared across all function lowerings.
284 -
/// Holds global state like the data section (strings, constants) and provides
285 -
/// access to the resolver for type queries.
294 +
/// Module-level lowering context shared across all function lowerings.
295 +
///
296 +
/// The resolver is immutable in this phase. Lowering owns its structural type
297 +
/// substitutions and all emitted IL, data, and symbol-name allocations.
286 298
export record Lowerer {
287 299
    /// Arena for persistent lowering state, including data and symbol names.
288 300
    arena: *mut alloc::Arena,
289 301
    /// Arena for allocations owned by the function currently being lowered.
290 302
    fnArena: *mut alloc::Arena,
291 -
    /// Allocator backed by the arena.
303 +
    /// Allocator backed by the persistent lowering arena.
292 304
    allocator: alloc::Allocator,
293 -
    /// Resolver for type information. Used to query types, symbols, and
294 -
    /// compile-time constant values during lowering.
305 +
    /// Fully resolved semantic metadata queried without mutation.
295 306
    resolver: *resolver::Resolver,
296 307
    /// Module graph for cross-module symbol resolution.
297 308
    moduleGraph: ?*module::ModuleGraph,
298 309
    /// Package name for qualified symbol names.
299 310
    pkgName: *[u8],
300 311
    /// Current module being lowered.
301 312
    currentMod: ?u16,
313 +
    /// Rigid-to-concrete mapping for the function currently being lowered.
314 +
    specialization: ?*resolver::Substitution,
315 +
    /// Concrete generic function whose body is currently being lowered.
316 +
    genericSpecialization: ?*resolver::GenericFnSpecialization,
302 317
    /// Global data items (string literals, constants, static arrays).
303 318
    /// These become the data sections in the final binary.
304 319
    data: *mut [il::Data],
305 320
    /// Destination for lowered functions.
306 321
    output: FnOutput,
307 322
    /// Map of function symbols to qualified names.
308 323
    fnSyms: *mut [FnSymEntry],
309 -
    /// Global error type tag table. Maps nominal types to unique tags.
324 +
    /// Global error tag table keyed by persistent concrete types.
310 325
    errTags: *mut [ErrTagEntry],
311 326
    /// Next error tag to assign (starts at 1; 0 = success).
312 327
    errTagCounter: u32,
313 328
    /// Lowering options.
314 329
    options: LowerOptions,
318 333
record FnSymEntry {
319 334
    sym: *resolver::Symbol,
320 335
    qualName: *[u8],
321 336
}
322 337
338 +
/// Entry mapping a local data symbol to its qualified lowering-owned name.
339 +
record DataSymEntry {
340 +
    /// Resolver symbol identifying the declaration.
341 +
    sym: *resolver::Symbol,
342 +
    /// Function-local qualified data name.
343 +
    qualName: *[u8],
344 +
}
345 +
323 346
/// Entry in the global error tag table.
324 347
record ErrTagEntry {
325 -
    /// The type of this error, identified by its interned pointer.
348 +
    /// Persistent concrete error type.
326 349
    ty: resolver::Type,
327 350
    /// The globally unique tag assigned to this error type (non-zero).
328 351
    tag: u32,
329 352
}
330 353
338 361
        }
339 362
    }
340 363
    return maxSize;
341 364
}
342 365
343 -
/// Get or assign a globally unique error tag for the given error type.
344 -
/// Tag `0` is reserved for success; error tags start at `1`.
345 -
fn getOrAssignErrorTag(self: *mut Lowerer, errType: resolver::Type) -> u32 {
366 +
/// Allocate one persistent structural type component.
367 +
fn allocPersistentType(
368 +
    self: *mut Lowerer,
369 +
    ty: resolver::Type,
370 +
) -> *resolver::Type {
371 +
    let stored = try! alloc::alloc(
372 +
        self.arena,
373 +
        @sizeOf(resolver::Type),
374 +
        @alignOf(resolver::Type),
375 +
    ) as *mut resolver::Type;
376 +
    set *stored = ty;
377 +
    return stored;
378 +
}
379 +
380 +
/// Copy a concrete structural type into persistent lowering storage.
381 +
///
382 +
/// Nominal pointers retain their canonical identity; only structural
383 +
/// components that may live in the function arena are copied.
384 +
fn persistStructuralType(
385 +
    self: *mut Lowerer,
386 +
    ty: resolver::Type,
387 +
) -> resolver::Type {
388 +
    match ty {
389 +
        case resolver::Type::Pointer(pointer) => {
390 +
            let target = persistStructuralType(self, *pointer.target);
391 +
            return resolver::Type::Pointer(resolver::PointerType {
392 +
                class: pointer.class,
393 +
                target: allocPersistentType(self, target),
394 +
                mutable: pointer.mutable,
395 +
            });
396 +
        }
397 +
        case resolver::Type::Slice(slice) => {
398 +
            let item = persistStructuralType(self, *slice.item);
399 +
            return resolver::Type::Slice(resolver::SliceType {
400 +
                class: slice.class,
401 +
                item: allocPersistentType(self, item),
402 +
                mutable: slice.mutable,
403 +
            });
404 +
        }
405 +
        case resolver::Type::Array(array) => {
406 +
            let item = persistStructuralType(self, *array.item);
407 +
            return resolver::Type::Array(resolver::ArrayType {
408 +
                item: allocPersistentType(self, item),
409 +
                length: array.length,
410 +
            });
411 +
        }
412 +
        case resolver::Type::Optional(inner) => {
413 +
            let stored = persistStructuralType(self, *inner);
414 +
            return resolver::Type::Optional(allocPersistentType(self, stored));
415 +
        }
416 +
        case resolver::Type::Fn(info) => {
417 +
            let mut params: *mut [*resolver::Type] = &mut [];
418 +
            let mut throwList: *mut [*resolver::Type] = &mut [];
419 +
            for param in info.paramTypes {
420 +
                let stored = persistStructuralType(self, *param);
421 +
                params.append(allocPersistentType(self, stored), self.allocator);
422 +
            }
423 +
            for thrown in info.throwList {
424 +
                let stored = persistStructuralType(self, *thrown);
425 +
                throwList.append(
426 +
                    allocPersistentType(self, stored), self.allocator
427 +
                );
428 +
            }
429 +
            let returnType = persistStructuralType(self, *info.returnType);
430 +
            let storedInfo = try! alloc::alloc(
431 +
                self.arena,
432 +
                @sizeOf(resolver::FnType),
433 +
                @alignOf(resolver::FnType),
434 +
            ) as *mut resolver::FnType;
435 +
            set *storedInfo = resolver::FnType {
436 +
                paramTypes: &params[..],
437 +
                returnType: allocPersistentType(self, returnType),
438 +
                throwList: &throwList[..],
439 +
                isUnsafe: info.isUnsafe,
440 +
                localCount: info.localCount,
441 +
            };
442 +
            return resolver::Type::Fn(storedInfo);
443 +
        }
444 +
        case resolver::Type::Range { start, end } => {
445 +
            let mut storedStart: ?*resolver::Type = nil;
446 +
            let mut storedEnd: ?*resolver::Type = nil;
447 +
            if let value = start {
448 +
                let stored = persistStructuralType(self, *value);
449 +
                set storedStart = allocPersistentType(self, stored);
450 +
            }
451 +
            if let value = end {
452 +
                let stored = persistStructuralType(self, *value);
453 +
                set storedEnd = allocPersistentType(self, stored);
454 +
            }
455 +
            return resolver::Type::Range {
456 +
                start: storedStart,
457 +
                end: storedEnd,
458 +
            };
459 +
        }
460 +
        else => return ty,
461 +
    }
462 +
}
463 +
464 +
/// Get or assign a globally unique tag for a concrete error type.
465 +
fn getOrAssignErrorTag(
466 +
    self: *mut Lowerer,
467 +
    errType: resolver::Type,
468 +
) -> u32 {
469 +
    assert not resolver::containsGenericParameter(errType);
346 470
    for entry in self.errTags {
347 -
        if entry.ty == errType {
471 +
        if resolver::typesEqual(entry.ty, errType) {
348 472
            return entry.tag;
349 473
        }
350 474
    }
351 475
    let tag = self.errTagCounter;
352 -
353 476
    set self.errTagCounter += 1;
354 -
    self.errTags.append(ErrTagEntry { ty: errType, tag }, self.allocator);
355 -
477 +
    self.errTags.append(ErrTagEntry {
478 +
        ty: persistStructuralType(self, errType),
479 +
        tag,
480 +
    }, self.allocator);
356 481
    return tag;
357 482
}
358 483
359 484
/// Emit one function to the active output.
360 485
fn emitFunction(self: *mut Lowerer, func: *il::Fn, role: FnRole) {
679 804
    allocator: alloc::Allocator,
680 805
    /// Type signature of the function being lowered.
681 806
    fnType: *resolver::FnType,
682 807
    /// Function name, used as prefix for generated data symbols.
683 808
    fnName: *[u8],
809 +
    /// Names assigned to data declarations in this function.
810 +
    dataSyms: *mut [DataSymEntry],
684 811
685 812
    // ~ SSA variable tracking ~ //
686 813
687 814
    /// Metadata (name, type, mutability) for each variable. Indexed by variable
688 815
    /// id. Doesn't change after declaration. For the SSA value of a variable in
733 860
// Module Lowering Entry Point //
734 861
/////////////////////////////////
735 862
736 863
/// Lower a complete module AST to an IL program.
737 864
///
738 -
/// This is the main entry point for the lowering pass. It:
739 -
/// 1. Counts functions to preallocate the output array.
740 -
/// 2. Iterates over top-level declarations, lowering each.
741 -
/// 3. Returns the complete IL program with functions and data section.
742 -
///
743 -
/// The resolver must have already processed the AST -- we rely on its type
744 -
/// annotations, symbol table, and constant evaluations.
865 +
/// The resolver must have completed semantic analysis and generic
866 +
/// specialization before this phase. Lowering treats all resolver metadata as
867 +
/// immutable and allocates emitted state exclusively from `arena`.
745 868
export fn lower(
746 869
    res: *resolver::Resolver,
747 870
    root: *ast::Node,
748 871
    pkgName: *[u8],
749 872
    arena: *mut alloc::Arena
754 877
        allocator: alloc::arenaAllocator(arena),
755 878
        resolver: res,
756 879
        moduleGraph: nil,
757 880
        pkgName,
758 881
        currentMod: nil,
882 +
        specialization: nil,
883 +
        genericSpecialization: nil,
759 884
        data: &mut [],
760 885
        output: FnOutput::Accumulate(&mut []),
761 886
        fnSyms: &mut [],
762 887
        errTags: &mut [],
763 888
        errTagCounter: 1,
770 895
771 896
/////////////////////////////////
772 897
// Multi-Module Lowering API   //
773 898
/////////////////////////////////
774 899
775 -
/// Create a lowerer for multi-module compilation.
900 +
/// Create a multi-module lowerer over fully resolved immutable metadata.
776 901
export fn lowerer(
777 902
    res: *resolver::Resolver,
778 903
    graph: *module::ModuleGraph,
779 904
    pkgName: *[u8],
780 905
    arena: *mut alloc::Arena,
787 912
        allocator: alloc::arenaAllocator(arena),
788 913
        resolver: res,
789 914
        moduleGraph: graph,
790 915
        pkgName,
791 916
        currentMod: nil,
917 +
        specialization: nil,
918 +
        genericSpecialization: nil,
792 919
        data: &mut [],
793 920
        output: FnOutput::Accumulate(&mut []),
794 921
        fnSyms: &mut [],
795 922
        errTags: &mut [],
796 923
        errTagCounter: 1,
818 945
    let stmtsList = block.statements;
819 946
820 947
    for node in stmtsList {
821 948
        match node.value {
822 949
            case ast::NodeValue::FnDecl(decl) => {
950 +
                // Generic declarations are templates, not emitted functions.
951 +
                if decl.params.len > 0 {
952 +
                    continue;
953 +
                }
823 954
                if let f = try lowerFnDecl(low, node, decl) {
824 955
                    let role = lowerFnRole(isRoot, decl.attrs);
825 956
                    emitFunction(low, f, role);
826 957
                }
827 958
            }
828 959
            case ast::NodeValue::ConstDecl(decl) => {
829 -
                try lowerDataDecl(low, node, decl.value, true);
960 +
                try lowerDataDecl(low, node, decl.value, true, nil);
830 961
            }
831 962
            case ast::NodeValue::StaticDecl(decl) => {
832 -
                try lowerDataDecl(low, node, decl.value, false);
963 +
                try lowerDataDecl(low, node, decl.value, false, nil);
833 964
            }
834 965
            case ast::NodeValue::InstanceDecl { traitName, targetType, methods } => {
835 966
                try lowerInstanceDecl(low, node, traitName, targetType, methods);
836 967
            }
837 968
            case ast::NodeValue::MethodDecl { name, receiverName, receiverType, sig, body, .. } => {
840 971
                }
841 972
            }
842 973
            else => {},
843 974
        }
844 975
    }
976 +
    try lowerGenericFnSpecializations(low);
977 +
}
978 +
979 +
/// Lower explicit generic function roots owned by the current module.
980 +
fn lowerGenericFnSpecializations(low: *mut Lowerer) throws (LowerError) {
981 +
    let mut cursor = resolver::genericFnSpecializations(low.resolver);
982 +
    while let specialization = cursor {
983 +
        let templateSym = specialization.template;
984 +
        if low.moduleGraph <> nil and templateSym.moduleId <> low.currentMod {
985 +
            set cursor = specialization.next;
986 +
            continue;
987 +
        }
988 +
        let case ast::NodeValue::FnDecl(decl) = templateSym.node.value else {
989 +
            throw LowerError::ExpectedFunction;
990 +
        };
991 +
        if not shouldLowerFn(&decl, low.options.buildTest) {
992 +
            set cursor = specialization.next;
993 +
            continue;
994 +
        }
995 +
        let template = resolver::genericTemplateFor(low.resolver, templateSym)
996 +
            else throw LowerError::MissingMetadata;
997 +
        let sub = resolver::Substitution {
998 +
            params: template.params,
999 +
            args: specialization.args,
1000 +
        };
1001 +
        let symbolicFnType = template.signature
1002 +
            else throw LowerError::MissingMetadata;
1003 +
        let mut concreteFnType = *specialization.fnType;
1004 +
        set concreteFnType.localCount = symbolicFnType.localCount;
1005 +
        set low.genericSpecialization = specialization;
1006 +
        set low.specialization = &sub;
1007 +
        let name = specializationName(low, specialization);
1008 +
        let func = try lowerConcreteFn(
1009 +
            low,
1010 +
            templateSym.node,
1011 +
            decl,
1012 +
            &concreteFnType,
1013 +
            name,
1014 +
            false,
1015 +
        ) catch e {
1016 +
            set low.genericSpecialization = nil;
1017 +
            set low.specialization = nil;
1018 +
            throw e;
1019 +
        };
1020 +
        set low.genericSpecialization = nil;
1021 +
        set low.specialization = nil;
1022 +
        emitFunction(low, func, FnRole::Normal);
1023 +
        set cursor = specialization.next;
1024 +
    }
845 1025
}
846 1026
847 1027
/// Finalize lowering and return the unified IL program.
848 1028
export fn finalize(low: *Lowerer) -> il::Program {
849 1029
    let mut fns: *mut [*il::Fn] = undefined;
892 1072
        return name;
893 1073
    }
894 1074
    return il::formatQualifiedName(self.arena, path, name);
895 1075
}
896 1076
1077 +
/// Append bytes to a symbol name.
1078 +
fn namePush(builder: *mut NameBuilder, text: *[u8]) {
1079 +
    for byte in text {
1080 +
        builder.bytes.append(byte, builder.allocator);
1081 +
    }
1082 +
}
1083 +
1084 +
/// Append a decimal `u32` to a symbol name.
1085 +
fn namePushU32(builder: *mut NameBuilder, value: u32) {
1086 +
    let mut digits: [u8; 10] = undefined;
1087 +
    namePush(builder, fmt::formatU32(value, &mut digits[..]));
1088 +
}
1089 +
1090 +
/// Append a decimal `u64` to a symbol name.
1091 +
fn namePushU64(builder: *mut NameBuilder, value: u64) {
1092 +
    let mut digits: [u8; 20] = undefined;
1093 +
    namePush(builder, fmt::formatU64(value, &mut digits[..]));
1094 +
}
1095 +
1096 +
/// Append the stable, source-qualified name of a module-level declaration.
1097 +
fn namePushQualified(
1098 +
    self: *mut Lowerer,
1099 +
    builder: *mut NameBuilder,
1100 +
    modId: ?u16,
1101 +
    name: *[u8],
1102 +
) {
1103 +
    let path = getModulePath(self, modId);
1104 +
    if path.len == 0 or path[0] <> self.pkgName {
1105 +
        namePush(builder, self.pkgName);
1106 +
        namePush(builder, "::");
1107 +
    }
1108 +
    for segment in path {
1109 +
        namePush(builder, segment);
1110 +
        namePush(builder, "::");
1111 +
    }
1112 +
    namePush(builder, name);
1113 +
}
1114 +
1115 +
/// Append a trait's qualified name.
1116 +
fn namePushTrait(
1117 +
    self: *mut Lowerer,
1118 +
    builder: *mut NameBuilder,
1119 +
    traitInfo: *resolver::TraitType,
1120 +
) {
1121 +
    namePushQualified(self, builder, traitInfo.moduleId, traitInfo.name);
1122 +
}
1123 +
1124 +
/// Append a canonical resolved type using Radiance source syntax.
1125 +
fn namePushType(
1126 +
    self: *mut Lowerer,
1127 +
    builder: *mut NameBuilder,
1128 +
    ty: resolver::Type,
1129 +
) {
1130 +
    match ty {
1131 +
        case resolver::Type::Void => namePush(builder, "void"),
1132 +
        case resolver::Type::Opaque => namePush(builder, "opaque"),
1133 +
        case resolver::Type::Never => namePush(builder, "!"),
1134 +
        case resolver::Type::Bool => namePush(builder, "bool"),
1135 +
        case resolver::Type::U8 => namePush(builder, "u8"),
1136 +
        case resolver::Type::U16 => namePush(builder, "u16"),
1137 +
        case resolver::Type::U32 => namePush(builder, "u32"),
1138 +
        case resolver::Type::U64 => namePush(builder, "u64"),
1139 +
        case resolver::Type::I8 => namePush(builder, "i8"),
1140 +
        case resolver::Type::I16 => namePush(builder, "i16"),
1141 +
        case resolver::Type::I32 => namePush(builder, "i32"),
1142 +
        case resolver::Type::I64 => namePush(builder, "i64"),
1143 +
        case resolver::Type::Pointer(pointer) => {
1144 +
            match pointer.class {
1145 +
                case types::PointerClass::Owned => namePush(builder, "*"),
1146 +
                case types::PointerClass::Ref => namePush(builder, "&"),
1147 +
                case types::PointerClass::Unsafe => namePush(builder, "*unsafe "),
1148 +
            }
1149 +
            if pointer.mutable { namePush(builder, "mut "); }
1150 +
            namePushType(self, builder, *pointer.target);
1151 +
        }
1152 +
        case resolver::Type::Slice(slice) => {
1153 +
            match slice.class {
1154 +
                case types::PointerClass::Owned => namePush(builder, "*"),
1155 +
                case types::PointerClass::Ref => namePush(builder, "&"),
1156 +
                case types::PointerClass::Unsafe => namePush(builder, "*unsafe "),
1157 +
            }
1158 +
            if slice.mutable { namePush(builder, "mut "); }
1159 +
            namePush(builder, "[");
1160 +
            namePushType(self, builder, *slice.item);
1161 +
            namePush(builder, "]");
1162 +
        }
1163 +
        case resolver::Type::Array(array) => {
1164 +
            namePush(builder, "[");
1165 +
            namePushType(self, builder, *array.item);
1166 +
            namePush(builder, "; ");
1167 +
            namePushU32(builder, array.length);
1168 +
            namePush(builder, "]");
1169 +
        }
1170 +
        case resolver::Type::ConstArgument { value, .. } => {
1171 +
            if value.negative { namePush(builder, "-"); }
1172 +
            namePushU64(builder, value.magnitude);
1173 +
        }
1174 +
        case resolver::Type::Optional(inner) => {
1175 +
            namePush(builder, "?");
1176 +
            namePushType(self, builder, *inner);
1177 +
        }
1178 +
        case resolver::Type::Fn(info) => {
1179 +
            if info.isUnsafe { namePush(builder, "unsafe "); }
1180 +
            namePush(builder, "fn(");
1181 +
            for param, i in info.paramTypes {
1182 +
                if i > 0 { namePush(builder, ", "); }
1183 +
                namePushType(self, builder, *param);
1184 +
            }
1185 +
            namePush(builder, ") -> ");
1186 +
            namePushType(self, builder, *info.returnType);
1187 +
            if info.throwList.len > 0 {
1188 +
                namePush(builder, " throws ");
1189 +
                for thrown, i in info.throwList {
1190 +
                    if i > 0 { namePush(builder, ", "); }
1191 +
                    namePushType(self, builder, *thrown);
1192 +
                }
1193 +
            }
1194 +
        }
1195 +
        case resolver::Type::Nominal(nominal) => {
1196 +
            if let data = resolver::genericDataSpecializationForNominal(
1197 +
                self.resolver, nominal
1198 +
            ) {
1199 +
                namePushQualified(
1200 +
                    self, builder, data.template.moduleId, data.template.name
1201 +
                );
1202 +
                namePush(builder, "⟨");
1203 +
                for arg, i in data.args {
1204 +
                    if i > 0 { namePush(builder, ", "); }
1205 +
                    namePushType(self, builder, *arg);
1206 +
                }
1207 +
                namePush(builder, "⟩");
1208 +
                return;
1209 +
            }
1210 +
            if let sym = resolver::symbolForNominal(self.resolver, nominal) {
1211 +
                namePushQualified(self, builder, sym.moduleId, sym.name);
1212 +
                return;
1213 +
            }
1214 +
            match *nominal {
1215 +
                case resolver::NominalType::Record(recordType) => {
1216 +
                    namePush(builder, "{ ");
1217 +
                    for field, i in recordType.fields {
1218 +
                        if i > 0 { namePush(builder, ", "); }
1219 +
                        if let name = field.name {
1220 +
                            namePush(builder, name);
1221 +
                            namePush(builder, ": ");
1222 +
                        }
1223 +
                        namePushType(self, builder, field.fieldType);
1224 +
                    }
1225 +
                    namePush(builder, " }");
1226 +
                }
1227 +
                case resolver::NominalType::Union(_) =>
1228 +
                    panic "namePushType: anonymous union has no source identity",
1229 +
                case resolver::NominalType::Placeholder(_) =>
1230 +
                    panic "namePushType: unresolved nominal type",
1231 +
            }
1232 +
        }
1233 +
        case resolver::Type::TraitObject(object) => {
1234 +
            match object.class {
1235 +
                case types::PointerClass::Owned => namePush(builder, "*"),
1236 +
                case types::PointerClass::Ref => namePush(builder, "&"),
1237 +
                case types::PointerClass::Unsafe => namePush(builder, "*unsafe "),
1238 +
            }
1239 +
            if object.mutable { namePush(builder, "mut "); }
1240 +
            namePush(builder, "opaque ");
1241 +
            namePushTrait(self, builder, object.traitInfo);
1242 +
        }
1243 +
        else => panic "namePushType: non-concrete type",
1244 +
    }
1245 +
}
1246 +
1247 +
/// Build a readable specialization name from source identity and canonical arguments.
1248 +
fn specializationName(
1249 +
    self: *mut Lowerer,
1250 +
    specialization: *resolver::GenericFnSpecialization,
1251 +
) -> *[u8] {
1252 +
    let template = specialization.template;
1253 +
    let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator };
1254 +
    namePushQualified(self, &mut builder, template.moduleId, template.name);
1255 +
    namePush(&mut builder, "⟨");
1256 +
    for arg, i in specialization.args {
1257 +
        if i > 0 { namePush(&mut builder, ", "); }
1258 +
        namePushType(self, &mut builder, *arg);
1259 +
    }
1260 +
    namePush(&mut builder, "⟩");
1261 +
    return &builder.bytes[..];
1262 +
}
1263 +
897 1264
/// Register a function symbol with its qualified name.
898 1265
/// Called when lowering function declarations, so cross-package calls can find
899 1266
/// the function by name.
900 1267
fn registerFnSym(self: *mut Lowerer, sym: *resolver::Symbol, qualName: *[u8]) {
901 1268
    self.fnSyms.append(FnSymEntry { sym, qualName }, self.allocator);
913 1280
        }
914 1281
    }
915 1282
    return nil;
916 1283
}
917 1284
1285 +
/// Register a local data symbol with its lowering-owned qualified name.
1286 +
fn registerDataSym(
1287 +
    self: *mut FnLowerer,
1288 +
    sym: *resolver::Symbol,
1289 +
    qualName: *[u8],
1290 +
) {
1291 +
    self.dataSyms.append(DataSymEntry { sym, qualName }, self.allocator);
1292 +
}
1293 +
1294 +
/// Look up the current function's most recently registered local data name.
1295 +
fn lookupDataSym(self: *FnLowerer, sym: *resolver::Symbol) -> ?*[u8] {
1296 +
    let mut i = self.dataSyms.len;
1297 +
    while i > 0 {
1298 +
        set i -= 1;
1299 +
        let entry = &self.dataSyms[i];
1300 +
        if entry.sym == sym {
1301 +
            return entry.qualName;
1302 +
        }
1303 +
    }
1304 +
    return nil;
1305 +
}
1306 +
918 1307
/// Set the package context for lowering.
919 1308
/// Called before lowering each package.
920 1309
export fn setPackage(self: *mut Lowerer, graph: *module::ModuleGraph, pkgName: *[u8]) {
921 1310
    set self.moduleGraph = graph;
922 1311
    set self.pkgName = pkgName;
935 1324
    let mut fnLow = FnLowerer {
936 1325
        low: self,
937 1326
        allocator: alloc::arenaAllocator(self.fnArena),
938 1327
        fnType: fnType,
939 1328
        fnName: qualName,
1329 +
        dataSyms: &mut [],
940 1330
        vars: &mut [],
941 1331
        params: &mut [],
942 1332
        blockData: &mut [],
943 1333
        entryBlock: nil,
944 1334
        currentBlock: nil,
988 1378
989 1379
    // Register function symbol for cross-package call resolution.
990 1380
    if let sym = data.sym {
991 1381
        registerFnSym(self, sym, qualName);
992 1382
    }
993 -
    let mut fnLow = fnLowerer(self, node, fnType, qualName);
1383 +
    return try lowerConcreteFn(self, node, decl, fnType, qualName, isExtern);
1384 +
}
994 1385
995 -
    // If the function returns an aggregate or is throwing, prepend a hidden
996 -
    // return parameter. The caller allocates the buffer and passes it
997 -
    // as the first argument; the callee writes the return value into it.
1386 +
/// Lower one already-concrete function signature through the shared body path.
1387 +
fn lowerConcreteFn(
1388 +
    self: *mut Lowerer,
1389 +
    node: *ast::Node,
1390 +
    decl: ast::FnDecl,
1391 +
    fnType: *resolver::FnType,
1392 +
    qualName: *[u8],
1393 +
    isExtern: bool,
1394 +
) -> *il::Fn throws (LowerError) {
1395 +
    let mut fnLow = fnLowerer(self, node, fnType, qualName);
998 1396
    if requiresReturnParam(fnType) and not isExtern {
999 1397
        set fnLow.returnReg = nextReg(&mut fnLow);
1000 1398
    }
1001 1399
    let lowParams = try lowerParams(&mut fnLow, *fnType, decl.sig.params, nil);
1002 -
    let func = try! alloc::alloc(self.fnArena, @sizeOf(il::Fn), @alignOf(il::Fn)) as *mut il::Fn;
1003 1400
1401 +
    let func = try! alloc::alloc(
1402 +
        self.fnArena, @sizeOf(il::Fn), @alignOf(il::Fn)
1403 +
    ) as *mut il::Fn;
1004 1404
    set *func = il::Fn {
1005 1405
        name: qualName,
1006 1406
        params: lowParams,
1007 1407
        returnType: undefined,
1008 1408
        isExtern,
1009 1409
        isLeaf: true,
1010 1410
        blocks: &[],
1011 1411
    };
1012 -
    // Throwing functions return a result aggregate (word-sized pointer).
1013 -
    // TODO: The resolver should set an appropriate type that takes into account
1014 -
    //       the throws list. It shouldn't set the return type to the "success"
1015 -
    //       value only.
1016 1412
    if fnType.throwList.len > 0 {
1017 1413
        set func.returnType = il::Type::W64;
1018 1414
    } else {
1019 1415
        set func.returnType = ilType(self, *fnType.returnType);
1020 1416
    }
1021 1417
    let body = decl.body else {
1022 -
        // Extern functions have no body.
1023 1418
        assert isExtern;
1024 1419
        return func;
1025 1420
    };
1026 1421
    set func.blocks = try lowerFnBody(&mut fnLow, body);
1027 1422
    set func.isLeaf = fnLow.isLeaf;
1028 1423
1029 1424
    return func;
1030 1425
}
1031 1426
1032 -
/// Build a qualified name of the form "Type::method".
1033 -
fn instanceMethodName(self: *mut Lowerer, modId: ?u16, typeName: *[u8], methodName: *[u8]) -> *[u8] {
1034 -
    let sepLen: u32 = 2; // "::"
1035 -
    let totalLen = typeName.len + sepLen + methodName.len;
1036 -
    let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8];
1037 -
    let mut pos: u32 = 0;
1038 -
1039 -
    set pos += try! mem::copy(&mut buf[pos..], typeName);
1040 -
    set pos += try! mem::copy(&mut buf[pos..], "::");
1041 -
    set pos += try! mem::copy(&mut buf[pos..], methodName);
1042 -
    assert pos == totalLen;
1043 -
1044 -
    return qualifyName(self, modId, &buf[..totalLen]);
1045 -
}
1046 -
1047 -
/// Build a v-table data name of the form "vtable::Type::Trait".
1048 -
fn vtableName(self: *mut Lowerer, modId: ?u16, typeName: *[u8], traitName: *[u8]) -> *[u8] {
1049 -
    let prefix = "vtable::";
1050 -
    let sepLen: u32 = 2; // "::"
1051 -
    let totalLen = prefix.len + typeName.len + sepLen + traitName.len;
1052 -
    let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8];
1053 -
    let mut pos: u32 = 0;
1054 -
1055 -
    set pos += try! mem::copy(&mut buf[pos..], prefix);
1056 -
    set pos += try! mem::copy(&mut buf[pos..], typeName);
1057 -
    set pos += try! mem::copy(&mut buf[pos..], "::");
1058 -
    set pos += try! mem::copy(&mut buf[pos..], traitName);
1059 -
    assert pos == totalLen;
1060 -
1061 -
    return qualifyName(self, modId, &buf[..totalLen]);
1427 +
/// Build a readable method name from its concrete type, trait, and source name.
1428 +
fn instanceMethodName(
1429 +
    self: *mut Lowerer,
1430 +
    concreteType: resolver::Type,
1431 +
    traitInfo: ?*resolver::TraitType,
1432 +
    methodName: *[u8],
1433 +
) -> *[u8] {
1434 +
    let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator };
1435 +
    namePushType(self, &mut builder, concreteType);
1436 +
    if let traitValue = traitInfo {
1437 +
        namePush(&mut builder, " ");
1438 +
        namePushTrait(self, &mut builder, traitValue);
1439 +
    }
1440 +
    namePush(&mut builder, "::");
1441 +
    namePush(&mut builder, methodName);
1442 +
    return &builder.bytes[..];
1443 +
}
1444 +
1445 +
/// Build a readable v-table name from its concrete type and trait.
1446 +
fn vtableName(
1447 +
    self: *mut Lowerer,
1448 +
    concreteType: resolver::Type,
1449 +
    traitInfo: *resolver::TraitType,
1450 +
) -> *[u8] {
1451 +
    let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator };
1452 +
    namePush(&mut builder, "vtable::");
1453 +
    namePushType(self, &mut builder, concreteType);
1454 +
    namePush(&mut builder, " ");
1455 +
    namePushTrait(self, &mut builder, traitInfo);
1456 +
    return &builder.bytes[..];
1062 1457
}
1063 1458
1064 1459
/// Lower an instance declaration (`instance Trait for Type { ... }`).
1065 1460
///
1066 1461
/// Each method in the instance block is lowered as a standalone function
1067 -
/// with a qualified name of the form `Type::method`. A read-only v-table
1068 -
/// data record is emitted containing pointers to these functions, ordered
1069 -
/// by the trait's method indices. The v-table is later referenced when
1462 +
/// with a qualified name containing both concrete and declaring-trait
1463 +
/// identities. A read-only v-table data record points to these functions,
1464 +
/// ordered by the trait's method indices. The v-table is later referenced when
1070 1465
/// constructing trait objects for dynamic dispatch.
1071 1466
fn lowerInstanceDecl(
1072 1467
    self: *mut Lowerer,
1073 1468
    node: *ast::Node,
1074 1469
    traitNameNode: *ast::Node,
1075 1470
    targetTypeNode: *ast::Node,
1076 1471
    methods: *mut [*ast::Node]
1077 1472
) throws (LowerError) {
1078 -
    // Look up the trait and type from the resolver.
1473 +
    // Look up the trait and concrete instance from resolver metadata.
1079 1474
    let traitSym = resolver::nodeData(self.resolver, traitNameNode).sym
1080 1475
        else throw LowerError::MissingSymbol(traitNameNode);
1081 1476
    let case resolver::SymbolData::Trait(traitInfo) = traitSym.data
1082 1477
        else throw LowerError::MissingMetadata;
1083 -
    let typeSym = resolver::nodeData(self.resolver, targetTypeNode).sym
1084 -
        else throw LowerError::MissingSymbol(targetTypeNode);
1085 1478
1086 -
    let tName = traitSym.name;
1087 -
    let typeName = typeSym.name;
1479 +
    let concreteType = resolver::typeFor(self.resolver, targetTypeNode)
1480 +
        else throw LowerError::MissingType(targetTypeNode);
1481 +
    let instEntry = resolver::findInstance(self.resolver, traitInfo, concreteType)
1482 +
        else throw LowerError::MissingMetadata;
1088 1483
1089 1484
    // Lower each instance method as a regular function.
1090 1485
    // Collect qualified names for the v-table. Empty entries are filled
1091 1486
    // later from inherited supertrait methods.
1092 1487
    let mut methodNames: [*[u8]; ast::MAX_TRAIT_METHODS] = undefined;
1098 1493
        } = methodNode.value else continue;
1099 1494
1100 1495
        let case ast::NodeValue::Ident(mName) = name.value else {
1101 1496
            throw LowerError::ExpectedIdentifier;
1102 1497
        };
1103 -
        let qualName = instanceMethodName(self, nil, typeName, mName);
1498 +
        let method = resolver::findTraitMethod(traitInfo, mName)
1499 +
            else panic "lowerInstanceDecl: method not found in trait";
1500 +
        let qualName = instanceMethodName(
1501 +
            self, instEntry.concreteType, method.owner, mName
1502 +
        );
1104 1503
        let func = try lowerMethod(self, methodNode, qualName, receiverName, sig, body)
1105 1504
            else continue;
1106 1505
        emitFunction(self, func, FnRole::Normal);
1107 1506
1108 -
        let method = resolver::findTraitMethod(traitInfo, mName)
1109 -
            else panic "lowerInstanceDecl: method not found in trait";
1110 -
1111 1507
        set methodNames[method.index] = qualName;
1112 1508
        set methodNameSet[method.index] = true;
1113 1509
    }
1114 1510
1115 -
    // Fill inherited method slots from supertraits.
1116 -
    // These methods were already lowered as part of the supertrait instance
1117 -
    // declarations and use the same `Type::method` qualified name.
1511 +
    // Fill inherited method slots from their declaring supertraits. Their
1512 +
    // declaring-trait identity selects the already lowered implementation.
1118 1513
    for method, i in traitInfo.methods {
1119 1514
        if not methodNameSet[i] {
1120 -
            set methodNames[i] = instanceMethodName(self, nil, typeName, method.name);
1515 +
            let inheritedInst = resolver::findInstance(
1516 +
                self.resolver, method.owner, instEntry.concreteType
1517 +
            ) else throw LowerError::MissingMetadata;
1518 +
            set methodNames[i] = instanceMethodName(
1519 +
                self,
1520 +
                inheritedInst.concreteType,
1521 +
                method.owner,
1522 +
                method.name,
1523 +
            );
1121 1524
        }
1122 1525
    }
1123 1526
1124 1527
    // Create v-table in data section, used for dynamic dispatch.
1125 -
    let vName = vtableName(self, nil, typeName, tName);
1528 +
    let vName = vtableName(self, instEntry.concreteType, traitInfo);
1126 1529
    let values = try! alloc::allocSlice(
1127 1530
        self.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue), traitInfo.methods.len as u32
1128 1531
    ) as *mut [il::DataValue];
1129 1532
1130 1533
    for i in 0..traitInfo.methods.len {
1198 1601
        else throw LowerError::MissingSymbol(node);
1199 1602
    let case ast::NodeValue::Ident(mName) = name.value
1200 1603
        else throw LowerError::ExpectedIdentifier;
1201 1604
    let me = resolver::findMethodBySymbol(self.resolver, sym)
1202 1605
        else throw LowerError::MissingMetadata;
1203 -
    let qualName = instanceMethodName(self, nil, me.concreteTypeName, mName);
1606 +
    let qualName = instanceMethodName(
1607 +
        self, me.concreteType, nil, mName
1608 +
    );
1204 1609
1205 1610
    return try lowerMethod(self, node, qualName, receiverName, sig, body);
1206 1611
}
1207 1612
1208 1613
/// Check if a function should be lowered.
1307 1712
        }
1308 1713
        throw LowerError::MissingConst(node);
1309 1714
    };
1310 1715
1311 1716
    if let case resolver::ConstValue::String(s) = val {
1312 -
        if let case resolver::Type::Slice { .. } = ty {
1717 +
        if let case resolver::Type::Slice(_) = ty {
1313 1718
            let strSym = try getOrCreateStringData(self, s, dataPrefix);
1314 1719
            dataSliceHeader(b, strSym, s.len);
1315 1720
            return;
1316 1721
        }
1317 1722
    }
1324 1729
/// Lower a constant or static declaration to the data section.
1325 1730
fn lowerDataDecl(
1326 1731
    self: *mut Lowerer,
1327 1732
    node: *ast::Node,
1328 1733
    value: *ast::Node,
1329 -
    readOnly: bool
1734 +
    readOnly: bool,
1735 +
    localName: ?*[u8],
1330 1736
) throws (LowerError) {
1331 1737
    let data = resolver::nodeData(self.resolver, node);
1332 1738
    let sym = data.sym else {
1333 1739
        throw LowerError::MissingSymbol(node);
1334 1740
    };
1335 1741
    if data.ty == resolver::Type::Unknown {
1336 1742
        throw LowerError::MissingType(node);
1337 1743
    }
1338 1744
    let layout = resolver::getTypeLayout(data.ty);
1339 -
    let qualName = qualifyName(self, nil, sym.name);
1745 +
    let mut qualName: *[u8] = undefined;
1746 +
    if let name = localName {
1747 +
        set qualName = name;
1748 +
    } else {
1749 +
        set qualName = qualifyName(self, nil, sym.name);
1750 +
    }
1340 1751
    let mut b = dataBuilder(self.allocator);
1341 1752
    try lowerConstDataInto(self, value, data.ty, layout.size, qualName, &mut b);
1342 1753
    let result = dataBuilderFinish(&b);
1343 1754
1344 1755
    self.data.append(il::Data {
1379 1790
    addr: ast::AddressOf,
1380 1791
    ty: resolver::Type,
1381 1792
    dataPrefix: *[u8],
1382 1793
    b: *mut DataValueBuilder
1383 1794
) throws (LowerError) {
1384 -
    let case resolver::Type::Slice { mutable, .. } = ty
1795 +
    let case resolver::Type::Slice(slice) = ty
1385 1796
        else throw LowerError::ExpectedSliceOrArray;
1386 1797
    let targetTy = resolver::typeFor(self.resolver, addr.target)
1387 1798
        else throw LowerError::MissingType(addr.target);
1388 1799
    let case resolver::Type::Array(arrInfo) = targetTy
1389 1800
        else throw LowerError::ExpectedArray;
1391 1802
    let mut nested = dataBuilder(self.allocator);
1392 1803
    let layout = resolver::getTypeLayout(targetTy);
1393 1804
    try lowerConstDataInto(self, addr.target, targetTy, layout.size, dataPrefix, &mut nested);
1394 1805
1395 1806
    let backing = dataBuilderFinish(&nested);
1396 -
    let readOnly = not mutable;
1807 +
    let readOnly = not slice.mutable;
1397 1808
    let mut dataName: *[u8] = undefined;
1398 1809
    if readOnly {
1399 1810
        if let found = findConstData(self, backing.values, layout.alignment) {
1400 1811
            set dataName = found;
1401 1812
        } else {
1911 2322
    set self.dataCounter += 1;
1912 2323
    return try nextDeclDataName(self.low, self.fnName, counter, "literal");
1913 2324
}
1914 2325
1915 2326
/// Assign a unique function-local data symbol name.
1916 -
fn registerLocalDataDeclName(self: *mut FnLowerer, node: *ast::Node) throws (LowerError) {
2327 +
fn registerLocalDataDeclName(
2328 +
    self: *mut FnLowerer,
2329 +
    node: *ast::Node,
2330 +
) -> *[u8] throws (LowerError) {
1917 2331
    let sym = resolver::nodeData(self.low.resolver, node).sym
1918 2332
        else throw LowerError::MissingSymbol(node);
1919 2333
1920 2334
    let prefix = self.fnName;
1921 2335
    let segments: *mut [*[u8]] = &mut [prefix, "nominal", sym.name];
1922 -
    let name = try buildSegmentedName(self.low, segments);
1923 -
1924 -
    set sym.name = name;
2336 +
    let localName = try buildSegmentedName(self.low, segments);
2337 +
    let modId = resolver::moduleIdForSymbol(self.low.resolver, sym);
2338 +
    let qualName = qualifyName(self.low, modId, localName);
2339 +
    registerDataSym(self, sym, qualName);
2340 +
    return qualName;
1925 2341
}
1926 2342
1927 2343
/// Get the next available SSA register.
1928 2344
fn nextReg(self: *mut FnLowerer) -> il::Reg {
1929 2345
    let reg = il::Reg { n: self.regCounter };
1930 2346
    set self.regCounter += 1;
1931 2347
    return reg;
1932 2348
}
1933 2349
2350 +
/// Allocate a structural type component in the current function arena.
2351 +
fn allocSpecializedType(
2352 +
    self: *mut FnLowerer,
2353 +
    ty: resolver::Type,
2354 +
) -> *resolver::Type {
2355 +
    let value = try! alloc::alloc(
2356 +
        self.low.fnArena,
2357 +
        @sizeOf(resolver::Type),
2358 +
        @alignOf(resolver::Type),
2359 +
    ) as *mut resolver::Type;
2360 +
    set *value = ty;
2361 +
    return value;
2362 +
}
2363 +
2364 +
/// Apply the current generic function specialization without mutating resolver
2365 +
/// metadata or allocating from resolver-owned arenas.
2366 +
fn specializeType(
2367 +
    self: *mut FnLowerer,
2368 +
    ty: resolver::Type,
2369 +
) -> resolver::Type throws (LowerError) {
2370 +
    let sub = self.low.specialization else return ty;
2371 +
    if not resolver::containsGenericParameter(ty) {
2372 +
        return ty;
2373 +
    }
2374 +
    match ty {
2375 +
        case resolver::Type::Parameter(param) =>
2376 +
            return resolver::substitutionArg(sub, param),
2377 +
        case resolver::Type::ConstParameter(param) =>
2378 +
            return resolver::substitutionArg(sub, param),
2379 +
        case resolver::Type::GenericConstExpr { type, expr } => {
2380 +
            let value = resolver::constIntWithSubstitution(
2381 +
                self.low.resolver, expr, *type, sub
2382 +
            ) else throw LowerError::MissingMetadata;
2383 +
            return resolver::Type::ConstArgument { type, value };
2384 +
        }
2385 +
        case resolver::Type::Pointer(pointer) => {
2386 +
            let target = try specializeType(self, *pointer.target);
2387 +
            return resolver::Type::Pointer(resolver::PointerType {
2388 +
                class: pointer.class,
2389 +
                target: allocSpecializedType(self, target),
2390 +
                mutable: pointer.mutable,
2391 +
            });
2392 +
        }
2393 +
        case resolver::Type::Slice(slice) => {
2394 +
            let item = try specializeType(self, *slice.item);
2395 +
            return resolver::Type::Slice(resolver::SliceType {
2396 +
                class: slice.class,
2397 +
                item: allocSpecializedType(self, item),
2398 +
                mutable: slice.mutable,
2399 +
            });
2400 +
        }
2401 +
        case resolver::Type::Array(array) => {
2402 +
            let item = try specializeType(self, *array.item);
2403 +
            return resolver::Type::Array(resolver::ArrayType {
2404 +
                item: allocSpecializedType(self, item),
2405 +
                length: array.length,
2406 +
            });
2407 +
        }
2408 +
        case resolver::Type::GenericArray { item, length } => {
2409 +
            let concreteItem = try specializeType(self, *item);
2410 +
            let value = resolver::constIntWithSubstitution(
2411 +
                self.low.resolver, length, resolver::Type::U32, sub
2412 +
            ) else throw LowerError::MissingMetadata;
2413 +
            return resolver::Type::Array(resolver::ArrayType {
2414 +
                item: allocSpecializedType(self, concreteItem),
2415 +
                length: value.magnitude as u32,
2416 +
            });
2417 +
        }
2418 +
        case resolver::Type::Optional(inner) => {
2419 +
            let value = try specializeType(self, *inner);
2420 +
            return resolver::Type::Optional(allocSpecializedType(self, value));
2421 +
        }
2422 +
        case resolver::Type::GenericDataApply(app) => {
2423 +
            let mut args: *mut [*resolver::Type] = &mut [];
2424 +
            for arg in app.args {
2425 +
                let concrete = try specializeType(self, *arg);
2426 +
                if resolver::containsGenericParameter(concrete) {
2427 +
                    throw LowerError::MissingMetadata;
2428 +
                }
2429 +
                args.append(allocSpecializedType(self, concrete), self.allocator);
2430 +
            }
2431 +
            let specialization = resolver::findGenericDataSpecialization(
2432 +
                self.low.resolver, app.template, &args[..]
2433 +
            ) else throw LowerError::MissingMetadata;
2434 +
            return resolver::Type::Nominal(specialization.nominal);
2435 +
        }
2436 +
        case resolver::Type::GenericRecord(genericRecord) => {
2437 +
            let mut fields: *mut [resolver::RecordField] = &mut [];
2438 +
            let mut offset: u32 = 0;
2439 +
            let mut alignment: u32 = 1;
2440 +
            for field in genericRecord.fields {
2441 +
                let fieldType = try specializeType(self, field.fieldType);
2442 +
                if resolver::containsGenericParameter(fieldType) {
2443 +
                    throw LowerError::MissingMetadata;
2444 +
                }
2445 +
                let fieldLayout = resolver::getTypeLayout(fieldType);
2446 +
                set offset = mem::alignUp(offset, fieldLayout.alignment);
2447 +
                fields.append(resolver::RecordField {
2448 +
                    name: field.name,
2449 +
                    fieldType: persistStructuralType(self.low, fieldType),
2450 +
                    offset: offset as i32,
2451 +
                }, self.low.allocator);
2452 +
                set offset += fieldLayout.size;
2453 +
                if fieldLayout.alignment > alignment {
2454 +
                    set alignment = fieldLayout.alignment;
2455 +
                }
2456 +
            }
2457 +
            let nominal = try! alloc::alloc(
2458 +
                self.low.arena,
2459 +
                @sizeOf(resolver::NominalType),
2460 +
                @alignOf(resolver::NominalType),
2461 +
            ) as *mut resolver::NominalType;
2462 +
            set *nominal = resolver::NominalType::Record(resolver::RecordType {
2463 +
                fields: &fields[..],
2464 +
                labeled: genericRecord.labeled,
2465 +
                layout: resolver::Layout {
2466 +
                    size: mem::alignUp(offset, alignment),
2467 +
                    alignment,
2468 +
                },
2469 +
                declaredLinear: false,
2470 +
            });
2471 +
            return resolver::Type::Nominal(nominal);
2472 +
        }
2473 +
        case resolver::Type::Fn(info) => {
2474 +
            let mut params: *mut [*resolver::Type] = &mut [];
2475 +
            let mut throwTypes: *mut [*resolver::Type] = &mut [];
2476 +
            for param in info.paramTypes {
2477 +
                let concrete = try specializeType(self, *param);
2478 +
                params.append(allocSpecializedType(self, concrete), self.allocator);
2479 +
            }
2480 +
            for thrown in info.throwList {
2481 +
                let concrete = try specializeType(self, *thrown);
2482 +
                throwTypes.append(
2483 +
                    allocSpecializedType(self, concrete), self.allocator
2484 +
                );
2485 +
            }
2486 +
            let result = try specializeType(self, *info.returnType);
2487 +
            let fnType = try! alloc::alloc(
2488 +
                self.low.fnArena,
2489 +
                @sizeOf(resolver::FnType),
2490 +
                @alignOf(resolver::FnType),
2491 +
            ) as *mut resolver::FnType;
2492 +
            set *fnType = resolver::FnType {
2493 +
                paramTypes: &params[..],
2494 +
                returnType: allocSpecializedType(self, result),
2495 +
                throwList: &throwTypes[..],
2496 +
                isUnsafe: info.isUnsafe,
2497 +
                localCount: info.localCount,
2498 +
            };
2499 +
            return resolver::Type::Fn(fnType);
2500 +
        }
2501 +
        case resolver::Type::Range { start, end } => {
2502 +
            let mut concreteStart: ?*resolver::Type = nil;
2503 +
            let mut concreteEnd: ?*resolver::Type = nil;
2504 +
            if let value = start {
2505 +
                let concrete = try specializeType(self, *value);
2506 +
                set concreteStart = allocSpecializedType(self, concrete);
2507 +
            }
2508 +
            if let value = end {
2509 +
                let concrete = try specializeType(self, *value);
2510 +
                set concreteEnd = allocSpecializedType(self, concrete);
2511 +
            }
2512 +
            return resolver::Type::Range {
2513 +
                start: concreteStart,
2514 +
                end: concreteEnd,
2515 +
            };
2516 +
        }
2517 +
        else => return ty,
2518 +
    }
2519 +
}
2520 +
1934 2521
/// Look up the resolved type of an AST node, or throw `MissingType`.
1935 2522
fn typeOf(self: *mut FnLowerer, node: *ast::Node) -> resolver::Type throws (LowerError) {
1936 2523
    let ty = resolver::typeFor(self.low.resolver, node)
1937 2524
        else throw LowerError::MissingType(node);
1938 -
    return ty;
2525 +
    return try specializeType(self, ty);
1939 2526
}
1940 2527
1941 2528
/// Look up the symbol for an AST node, or throw `MissingSymbol`.
1942 2529
fn symOf(self: *mut FnLowerer, node: *ast::Node) -> *mut resolver::Symbol throws (LowerError) {
1943 2530
    let sym = resolver::nodeData(self.low.resolver, node).sym
2370 2957
}
2371 2958
2372 2959
/// Emit a copy instruction that loads a data symbol's address into a register.
2373 2960
fn emitDataAddr(self: *mut FnLowerer, sym: *resolver::Symbol) -> il::Reg {
2374 2961
    let dst = nextReg(self);
2375 -
    let modId = resolver::moduleIdForSymbol(self.low.resolver, sym);
2376 -
    let qualName = qualifyName(self.low, modId, sym.name);
2962 +
    let mut qualName: *[u8] = undefined;
2963 +
    if let localName = lookupDataSym(self, sym) {
2964 +
        set qualName = localName;
2965 +
    } else {
2966 +
        let modId = resolver::moduleIdForSymbol(self.low.resolver, sym);
2967 +
        set qualName = qualifyName(self.low, modId, sym.name);
2968 +
    }
2377 2969
2378 2970
    emit(self, il::Instr::Copy { dst, val: il::Val::DataSym(qualName) });
2379 2971
2380 2972
    return dst;
2381 2973
}
3190 3782
/// For null-ptr-optimized types, loads the data pointer, or returns it
3191 3783
/// directly for scalar pointers. For aggregates, returns the tag register.
3192 3784
fn optionalNilReg(self: *mut FnLowerer, val: il::Val, typ: resolver::Type) -> il::Reg throws (LowerError) {
3193 3785
    let reg = emitValToReg(self, val);
3194 3786
3195 -
    match typ {
3196 -
        case resolver::Type::Optional(resolver::Type::Slice { .. }) => {
3787 +
    if let case resolver::Type::Optional(inner) = typ {
3788 +
        if let case resolver::Type::Slice(_) = *inner {
3197 3789
            let ptrReg = nextReg(self);
3198 3790
            emitLoadW64At(self, ptrReg, reg, SLICE_PTR_OFFSET);
3199 3791
            return ptrReg;
3200 3792
        }
3201 -
        case resolver::Type::Optional(resolver::Type::Pointer { .. }) => return reg,
3202 -
        case resolver::Type::Optional(_) => return tvalTagReg(self, reg),
3203 -
        else => return reg,
3793 +
        if let case resolver::Type::Pointer(_) = *inner {
3794 +
            return reg;
3795 +
        }
3796 +
        return tvalTagReg(self, reg);
3204 3797
    }
3798 +
    return reg;
3205 3799
}
3206 3800
3207 3801
/// Lower an optional nil check (`opt == nil` or `opt <> nil`).
3208 3802
fn lowerNilCheck(self: *mut FnLowerer, opt: *ast::Node, isEq: bool) -> il::Val throws (LowerError) {
3209 3803
    let optTy = try typeOf(self, opt);
3421 4015
            }
3422 4016
            // Plain nested record destructuring pattern.
3423 4017
            // Auto-deref: if the field is a pointer, load it first.
3424 4018
            let mut derefType = fieldInfo.fieldType;
3425 4019
            let mut nestedBase = emitPtrOffset(self, base, fieldInfo.offset);
3426 -
            if let case resolver::Type::Pointer { target, .. } = fieldInfo.fieldType {
4020 +
            if let case resolver::Type::Pointer(pointer) = fieldInfo.fieldType {
3427 4021
                let ptrReg = nextReg(self);
3428 4022
                emitLoadW64At(self, ptrReg, nestedBase, 0);
3429 4023
                set nestedBase = ptrReg;
3430 -
                set derefType = *target;
4024 +
                set derefType = *pointer.target;
3431 4025
            }
3432 4026
            let recInfo = resolver::getRecord(derefType)
3433 4027
                else throw LowerError::ExpectedRecord;
3434 4028
3435 4029
            try bindNestedRecordFields(self, nestedBase, lit, recInfo, matchBy, failBlock);
3457 4051
3458 4052
    // Auto-deref: when the field is a pointer and the pattern destructures
3459 4053
    // the pointed-to value, load the pointer and use the target type.
3460 4054
    // The loaded pointer becomes the base address for the nested subject.
3461 4055
    let mut derefBase: ?il::Reg = nil;
3462 -
    if let case resolver::Type::Pointer { target, .. } = fieldType {
4056 +
    if let case resolver::Type::Pointer(pointer) = fieldType {
3463 4057
        if resolver::isDestructuringPattern(pattern) {
3464 4058
            let ptrReg = nextReg(self);
3465 4059
            emitLoadW64At(self, ptrReg, fieldPtr, 0);
3466 4060
            set derefBase = ptrReg;
3467 -
            set fieldType = *target;
4061 +
            set fieldType = *pointer.target;
3468 4062
        }
3469 4063
    }
3470 4064
    // Build a MatchSubject for the nested field.
3471 4065
    let ilTy = ilType(self.low, fieldType);
3472 4066
    let kind = matchSubjectKind(fieldType);
3948 4542
        case ast::NodeValue::Let(l) => {
3949 4543
            try lowerLet(self, node, l);
3950 4544
        }
3951 4545
        case ast::NodeValue::ConstDecl(decl) => {
3952 4546
            // Local constants lower to data declarations and emit no runtime code.
3953 -
            try registerLocalDataDeclName(self, node);
3954 -
            try lowerDataDecl(self.low, node, decl.value, true);
4547 +
            let qualName = try registerLocalDataDeclName(self, node);
4548 +
            try lowerDataDecl(self.low, node, decl.value, true, qualName);
3955 4549
        }
3956 4550
        case ast::NodeValue::StaticDecl(decl) => {
3957 4551
            // Local statics lower to data declarations and emit no runtime code.
3958 -
            try registerLocalDataDeclName(self, node);
3959 -
            try lowerDataDecl(self.low, node, decl.value, false);
4552 +
            let qualName = try registerLocalDataDeclName(self, node);
4553 +
            try lowerDataDecl(self.low, node, decl.value, false, qualName);
3960 4554
        }
3961 4555
        case ast::NodeValue::If(i) => {
3962 4556
            try lowerIf(self, i);
3963 4557
        }
3964 4558
        case ast::NodeValue::IfLet(i) => {
4064 4658
/// choosing how to compare or store that value.
4065 4659
fn effectiveType(self: *mut FnLowerer, node: *ast::Node) -> resolver::Type throws (LowerError) {
4066 4660
    let ty = try typeOf(self, node);
4067 4661
    if let coerce = resolver::coercionFor(self.low.resolver, node) {
4068 4662
        if let case resolver::Coercion::OptionalLift(optTy) = coerce {
4069 -
            return optTy;
4663 +
            return try specializeType(self, optTy);
4070 4664
        }
4071 4665
    }
4072 4666
    return ty;
4073 4667
}
4074 4668
4075 4669
/// Check if a resolver type lowers to an aggregate in memory.
4076 4670
fn isAggregateType(typ: resolver::Type) -> bool {
4077 4671
    match typ {
4078 -
        case resolver::Type::Slice { .. },
4079 -
             resolver::Type::TraitObject { .. } => return true,
4080 -
        case resolver::Type::Optional(resolver::Type::Pointer { .. }) => {
4672 +
        case resolver::Type::Optional(resolver::Type::Pointer(_)) => {
4081 4673
            // Optional pointers are scalar due to NPO.
4082 4674
            return false;
4083 4675
        }
4084 4676
        case resolver::Type::Optional(_) => {
4085 4677
            // All other optionals, including optional slices, are aggregates.
4087 4679
        }
4088 4680
        case resolver::Type::Nominal(_) => {
4089 4681
            // Void unions are small enough to pass by value.
4090 4682
            return not resolver::isVoidUnion(typ);
4091 4683
        }
4092 -
        case resolver::Type::Array(_),
4684 +
        case resolver::Type::Slice(_),
4685 +
             resolver::Type::TraitObject(_),
4686 +
             resolver::Type::Array(_),
4093 4687
             resolver::Type::Nil => return true,
4094 4688
        else => return false,
4095 4689
    }
4096 4690
}
4097 4691
4242 4836
/// For optional pointers (`?*T`), returns an immediate `0` (null pointer).
4243 4837
/// For other optionals, builds a tagged aggregate with tag set to `0` (absent).
4244 4838
fn buildNilOptional(self: *mut FnLowerer, optType: resolver::Type) -> il::Val throws (LowerError) {
4245 4839
    let case resolver::Type::Optional(inner) = optType
4246 4840
        else throw LowerError::ExpectedOptional;
4247 -
    if let case resolver::Type::Pointer { .. } = *inner {
4841 +
    if let case resolver::Type::Pointer(_) = *inner {
4248 4842
        return il::Val::Imm(0);
4249 4843
    }
4250 -
    if let case resolver::Type::Slice { item, mutable, .. } = *inner {
4844 +
    if let case resolver::Type::Slice(slice) = *inner {
4251 4845
        return try buildSliceValue(
4252 -
            self, item, mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0)
4846 +
            self, slice.item, slice.mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0)
4253 4847
        );
4254 4848
    }
4255 4849
    let valOffset = resolver::getOptionalValOffset(*inner) as i32;
4256 4850
    return try buildTagged(self, resolver::getTypeLayout(optType), 0, nil, *inner, 1, valOffset);
4257 4851
}
4277 4871
    mutable: bool,
4278 4872
    ptrVal: il::Val,
4279 4873
    lenVal: il::Val,
4280 4874
    capVal: il::Val
4281 4875
) -> il::Val throws (LowerError) {
4282 -
    let sliceType = resolver::Type::Slice {
4876 +
    let sliceType = resolver::Type::Slice(resolver::SliceType {
4283 4877
        class: types::PointerClass::Unsafe,
4284 4878
        item: elemTy,
4285 4879
        mutable,
4286 -
    };
4880 +
    });
4287 4881
    let dst = try emitReserve(self, sliceType);
4288 -
    let ptrTy = resolver::Type::Pointer {
4882 +
    let ptrTy = resolver::Type::Pointer(resolver::PointerType {
4289 4883
        class: types::PointerClass::Unsafe,
4290 4884
        target: elemTy,
4291 4885
        mutable,
4292 -
    };
4886 +
    });
4293 4887
4294 4888
    try emitStore(self, dst, SLICE_PTR_OFFSET, ptrTy, ptrVal);
4295 4889
    try emitStore(self, dst, SLICE_LEN_OFFSET, resolver::Type::U32, lenVal);
4296 4890
    try emitStore(self, dst, SLICE_CAP_OFFSET, resolver::Type::U32, capVal);
4297 4891
4303 4897
    self: *mut FnLowerer,
4304 4898
    dataVal: il::Val,
4305 4899
    traitInfo: *resolver::TraitType,
4306 4900
    inst: *resolver::InstanceEntry
4307 4901
) -> il::Val throws (LowerError) {
4308 -
    let vName = vtableName(self.low, inst.moduleId, inst.concreteTypeName, traitInfo.name);
4902 +
    let vName = vtableName(
4903 +
        self.low, inst.concreteType, traitInfo
4904 +
    );
4309 4905
4310 4906
    // Reserve space for the trait object on the stack.
4311 4907
    let slot = emitReserveLayout(self, resolver::Layout {
4312 4908
        size: resolver::PTR_SIZE * 2,
4313 4909
        alignment: resolver::PTR_SIZE,
4475 5071
    mutable: bool,
4476 5072
    a: il::Reg,
4477 5073
    b: il::Reg,
4478 5074
    offset: i32
4479 5075
) -> il::Val throws (LowerError) {
4480 -
    let ptrTy = resolver::Type::Pointer {
5076 +
    let ptrTy = resolver::Type::Pointer(resolver::PointerType {
4481 5077
        class: types::PointerClass::Unsafe,
4482 5078
        target: elemTy,
4483 5079
        mutable,
4484 -
    };
5080 +
    });
4485 5081
    let ptrEq = try emitEqAtOffset(self, a, b, offset + SLICE_PTR_OFFSET, ptrTy);
4486 5082
    let lenEq = try emitEqAtOffset(self, a, b, offset + SLICE_LEN_OFFSET, resolver::Type::U32);
4487 5083
4488 5084
    return emitTypedBinOp(self, il::BinOp::And, il::Type::W32, ptrEq, lenEq);
4489 5085
}
4728 5324
    a: il::Reg,
4729 5325
    b: il::Reg,
4730 5326
    offset: i32
4731 5327
) -> il::Val throws (LowerError) {
4732 5328
    match typ {
4733 -
        case resolver::Type::Slice { item, mutable, .. } =>
4734 -
            return try lowerSliceEq(self, item, mutable, a, b, offset),
5329 +
        case resolver::Type::Slice(slice) =>
5330 +
            return try lowerSliceEq(self, slice.item, slice.mutable, a, b, offset),
4735 5331
        case resolver::Type::Optional(inner) => {
4736 -
            if let case resolver::Type::Slice { item, mutable, .. } = *inner {
5332 +
            if let case resolver::Type::Slice(slice) = *inner {
4737 5333
                // Optional slices use null pointer optimization.
4738 -
                return try lowerSliceEq(self, item, mutable, a, b, offset);
5334 +
                return try lowerSliceEq(self, slice.item, slice.mutable, a, b, offset);
4739 5335
            }
4740 5336
            return try lowerOptionalEq(self, *inner, a, b, offset);
4741 5337
        }
4742 5338
        case resolver::Type::Array(arr) =>
4743 5339
            return try lowerArrayEq(self, arr, a, b, offset),
4945 5541
    range: ast::Range,
4946 5542
    info: resolver::SliceRangeInfo
4947 5543
) -> SliceRangeResult throws (LowerError) {
4948 5544
    let baseVal = try lowerExpr(self, container);
4949 5545
    let baseReg = emitValToReg(self, baseVal);
5546 +
    let itemType = try specializeType(self, *info.itemType);
4950 5547
4951 5548
    // Extract data pointer and container length.
4952 5549
    let mut dataReg = baseReg;
4953 5550
    let mut containerLen: il::Val = undefined;
4954 5551
    if let cap = info.capacity { // Slice from array.
4986 5583
    // Only compute range offset and count if the start value is not
4987 5584
    // statically known to be zero.
4988 5585
    if startVal <> il::Val::Imm(0) {
4989 5586
        // Offset the data pointer by the start value.
4990 5587
        set dataReg = emitElem(
4991 -
            self, resolver::getTypeLayout(*info.itemType).size, dataReg, startVal
5588 +
            self, resolver::getTypeLayout(itemType).size, dataReg, startVal
4992 5589
        );
4993 5590
        // Compute the count as `end - start`.
4994 5591
        let lenReg = nextReg(self);
4995 5592
        emit(self, il::Instr::BinOp {
4996 5593
            op: il::BinOp::Sub,
5013 5610
) -> il::Val throws (LowerError) {
5014 5611
    let info = resolver::sliceRangeInfoFor(self.low.resolver, sliceNode) else {
5015 5612
        throw LowerError::MissingMetadata;
5016 5613
    };
5017 5614
    let r = try resolveSliceRangePtr(self, container, range, info);
5615 +
    let itemType = try specializeType(self, *info.itemType);
5018 5616
    return try buildSliceValue(
5019 -
        self, info.itemType, info.mutable, il::Val::Reg(r.dataReg), r.count, r.count
5617 +
        self, &itemType, info.mutable, il::Val::Reg(r.dataReg), r.count, r.count
5020 5618
    );
5021 5619
}
5022 5620
5023 5621
/// Lower an address-of (`&x`) expression.
5024 5622
fn lowerAddressOf(self: *mut FnLowerer, node: *ast::Node, addr: ast::AddressOf) -> il::Val throws (LowerError) {
5093 5691
    self: *mut FnLowerer,
5094 5692
    sliceNode: *ast::Node,
5095 5693
    arrayNode: *ast::Node
5096 5694
) -> il::Val throws (LowerError) {
5097 5695
    let sliceTy = try typeOf(self, sliceNode);
5098 -
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy else {
5696 +
    let case resolver::Type::Slice(slice) = sliceTy else {
5099 5697
        throw LowerError::UnexpectedType(&sliceTy);
5100 5698
    };
5101 5699
    let arrayTy = try typeOf(self, arrayNode);
5102 5700
    let case resolver::Type::Array(arrayInfo) = arrayTy else {
5103 5701
        throw LowerError::ExpectedArray;
5104 5702
    };
5105 5703
    let length = arrayInfo.length;
5106 5704
    if length == 0 {
5107 5705
        return try buildSliceValue(
5108 -
            self, item, mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0)
5706 +
            self, slice.item, slice.mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0)
5109 5707
        );
5110 5708
    }
5111 5709
    if resolver::isConstExpr(self.low.resolver, arrayNode) {
5112 5710
        let mut b = dataBuilder(self.low.allocator);
5113 5711
        match arrayNode.value {
5116 5714
            case ast::NodeValue::ArrayRepeatLit(repeat) =>
5117 5715
                try lowerConstArrayRepeatInto(self.low, repeat, arrayTy, self.fnName, &mut b),
5118 5716
            else => throw LowerError::UnexpectedNodeValue(arrayNode),
5119 5717
        }
5120 5718
        let result = dataBuilderFinish(&b);
5121 -
        let alignment = resolver::getTypeLayout(*item).alignment;
5719 +
        let alignment = resolver::getTypeLayout(*slice.item).alignment;
5122 5720
        return try lowerConstDataAsSlice(
5123 -
            self, result.values, alignment, not mutable,
5124 -
            item, mutable, length
5721 +
            self, result.values, alignment, not slice.mutable,
5722 +
            slice.item, slice.mutable, length
5125 5723
        );
5126 5724
    }
5127 5725
    let data = try lowerExpr(self, arrayNode);
5128 5726
    let count = il::Val::Imm(length as i64);
5129 -
    return try buildSliceValue(self, item, mutable, data, count, count);
5727 +
    return try buildSliceValue(self, slice.item, slice.mutable, data, count, count);
5130 5728
}
5131 5729
5132 5730
/// Lower the common element pointer computation for subscript operations.
5133 5731
/// Handles both arrays and slices by resolving the container type, extracting
5134 5732
/// the data pointer (for slices), and emitting an [`il::Instr::Elem`] to compute
5144 5742
5145 5743
    let mut dataReg = baseReg;
5146 5744
    let mut elemType: resolver::Type = undefined;
5147 5745
5148 5746
    match subjectTy {
5149 -
        case resolver::Type::Slice { item, .. } => {
5150 -
            set elemType = *item;
5747 +
        case resolver::Type::Slice(slice) => {
5748 +
            set elemType = *slice.item;
5151 5749
            let sliceLen = loadSliceLen(self, baseReg);
5152 5750
            // Runtime safety check: index must be strictly less than slice length.
5153 5751
            try emitTrapUnlessCmp(self, il::CmpOp::Ult, il::Type::W32, indexVal, sliceLen);
5154 5752
5155 5753
            set dataReg = loadSlicePtr(self, baseReg);
5431 6029
    container: *ast::Node,
5432 6030
    range: ast::Range,
5433 6031
    info: resolver::SliceRangeInfo
5434 6032
) throws (LowerError) {
5435 6033
    let r = try resolveSliceRangePtr(self, container, range, info);
5436 -
    let elemSize = resolver::getTypeLayout(*info.itemType).size;
6034 +
    let itemType = try specializeType(self, *info.itemType);
6035 +
    let elemSize = resolver::getTypeLayout(itemType).size;
5437 6036
    let rhsTy = try typeOf(self, rhs);
5438 6037
5439 -
    if let case resolver::Type::Slice { .. } = rhsTy {
6038 +
    if let case resolver::Type::Slice(_) = rhsTy {
5440 6039
        // Copy from source slice.
5441 6040
        let srcReg = emitValToReg(self, try lowerExpr(self, rhs));
5442 6041
        let srcData = loadSlicePtr(self, srcReg);
5443 6042
        let srcLen = loadSliceLen(self, srcReg);
5444 6043
5450 6049
        );
5451 6050
        try emitByteCopyLoop(self, r.dataReg, srcData, bytes, "copy");
5452 6051
    } else {
5453 6052
        // Fill with scalar value.
5454 6053
        let fillVal = try lowerExpr(self, rhs);
5455 -
        try emitFillLoop(self, r.dataReg, fillVal, r.count, *info.itemType, elemSize);
6054 +
        try emitFillLoop(self, r.dataReg, fillVal, r.count, itemType, elemSize);
5456 6055
    }
5457 6056
}
5458 6057
5459 6058
/// Emit a typed fill loop: `for i in 0..count { dst[i * stride] = value; }`.
5460 6059
fn emitFillLoop(
5656 6255
    match info {
5657 6256
        case resolver::ForLoopInfo::Range { valType, range, bindingName, indexName } => {
5658 6257
            let endExpr = range.end else {
5659 6258
                throw LowerError::MissingMetadata;
5660 6259
            };
6260 +
            let concreteValType = try specializeType(self, *valType);
5661 6261
            let mut startVal = il::Val::Imm(0);
5662 6262
            if let start = range.start {
5663 6263
                set startVal = try lowerExpr(self, start);
5664 6264
            }
5665 6265
            let endVal = try lowerExpr(self, endExpr);
5666 -
            let iterType = ilType(self.low, *valType);
6266 +
            let iterType = ilType(self.low, concreteValType);
5667 6267
            let valVar = newVar(self, bindingName, iterType, false, startVal);
5668 6268
5669 6269
            let mut indexVar: ?Var = nil;
5670 -
            if indexName <> nil { // Optional index always starts at zero.
5671 -
                set indexVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0));
6270 +
            if indexName <> nil {
6271 +
                set indexVar = newVar(
6272 +
                    self, indexName, il::Type::W32, false, il::Val::Imm(0)
6273 +
                );
5672 6274
            }
5673 6275
            let iter = ForIter::Range {
5674 -
                valVar, indexVar, endVal, valType: iterType,
5675 -
                unsigned: isUnsignedType(*valType),
6276 +
                valVar,
6277 +
                indexVar,
6278 +
                endVal,
6279 +
                valType: iterType,
6280 +
                unsigned: isUnsignedType(concreteValType),
5676 6281
            };
5677 6282
5678 6283
            try lowerForLoop(self, &iter, f.body);
5679 6284
        }
5680 6285
        case resolver::ForLoopInfo::Collection { elemType, length, bindingName, indexName } => {
6286 +
            let concreteElemType = try specializeType(self, *elemType);
5681 6287
            let containerVal = try lowerExpr(self, f.iterable);
5682 6288
            let containerReg = emitValToReg(self, containerVal);
5683 6289
5684 6290
            let mut dataReg = containerReg;
5685 6291
            let mut lengthVal: il::Val = undefined;
5686 -
            if let len = length { // Array (length is known).
6292 +
            if let len = length {
5687 6293
                set lengthVal = il::Val::Imm(len as i64);
5688 -
            } else { // Slice (length must be loaded).
6294 +
            } else {
5689 6295
                set lengthVal = loadSliceLen(self, containerReg);
5690 6296
                set dataReg = loadSlicePtr(self, containerReg);
5691 6297
            }
5692 -
            // Declare index value binidng.
5693 -
            let idxVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0));
5694 6298
5695 -
            // Declare element value binding.
6299 +
            let idxVar = newVar(
6300 +
                self, indexName, il::Type::W32, false, il::Val::Imm(0)
6301 +
            );
5696 6302
            let mut valVar: ?Var = nil;
5697 6303
            if bindingName <> nil {
5698 6304
                set valVar = newVar(
5699 6305
                    self,
5700 6306
                    bindingName,
5701 -
                    ilType(self.low, *elemType),
6307 +
                    ilType(self.low, concreteElemType),
5702 6308
                    false,
5703 -
                    il::Val::Undef
6309 +
                    il::Val::Undef,
5704 6310
                );
5705 6311
            }
5706 -
            let iter = ForIter::Collection { valVar, idxVar, dataReg, lengthVal, elemType };
5707 6312
6313 +
            let iter = ForIter::Collection {
6314 +
                valVar,
6315 +
                idxVar,
6316 +
                dataReg,
6317 +
                lengthVal,
6318 +
                elemType: &concreteElemType,
6319 +
            };
5708 6320
            try lowerForLoop(self, &iter, f.body);
5709 6321
        }
5710 6322
    }
5711 6323
    exitVarScope(self, savedVarsLen);
5712 6324
}
6176 6788
/// String literals are stored as global data and the result is a slice
6177 6789
/// pointing to the data with the appropriate length.
6178 6790
fn lowerStringLit(self: *mut FnLowerer, node: *ast::Node, s: *[u8]) -> il::Val throws (LowerError) {
6179 6791
    // Get the slice type from the node.
6180 6792
    let sliceTy = try typeOf(self, node);
6181 -
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy
6793 +
    let case resolver::Type::Slice(slice) = sliceTy
6182 6794
        else throw LowerError::ExpectedSliceOrArray;
6183 6795
    // Build the string data value.
6184 6796
    let ptr = try! alloc::alloc(
6185 6797
        self.low.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue)
6186 6798
    ) as *mut il::DataValue;
6187 6799
6188 6800
    set *ptr = il::DataValue { item: il::DataItem::Str(s), count: 1 };
6189 6801
6190 6802
    return try lowerConstDataAsSlice(
6191 -
        self, @sliceOf(ptr, 1), 1, true, item, mutable, s.len
6803 +
        self, @sliceOf(ptr, 1), 1, true, slice.item, slice.mutable, s.len
6192 6804
    );
6193 6805
}
6194 6806
6195 6807
/// Lower a builtin call expression.
6196 6808
fn lowerBuiltinCall(self: *mut FnLowerer, node: *ast::Node, kind: ast::Builtin, args: *mut [*ast::Node]) -> il::Val throws (LowerError) {
6209 6821
fn lowerSliceOf(self: *mut FnLowerer, node: *ast::Node, args: *mut [*ast::Node]) -> il::Val throws (LowerError) {
6210 6822
    if args.len <> 2 and args.len <> 3 {
6211 6823
        throw LowerError::InvalidArgCount;
6212 6824
    }
6213 6825
    let sliceTy = try typeOf(self, node);
6214 -
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy
6826 +
    let case resolver::Type::Slice(slice) = sliceTy
6215 6827
        else throw LowerError::ExpectedSliceOrArray;
6216 6828
    let ptrVal = try lowerExpr(self, args[0]);
6217 6829
    let lenVal = try lowerExpr(self, args[1]);
6218 6830
    let mut capVal = lenVal;
6219 6831
    if args.len == 3 {
6220 6832
        set capVal = try lowerExpr(self, args[2]);
6221 6833
    }
6222 6834
    if not isLtEq(lenVal, capVal) {
6223 6835
        try emitTrapIfLt(self, il::Type::W32, capVal, lenVal);
6224 6836
    }
6225 -
    return try buildSliceValue(self, item, mutable, ptrVal, lenVal, capVal);
6837 +
    return try buildSliceValue(self, slice.item, slice.mutable, ptrVal, lenVal, capVal);
6226 6838
}
6227 6839
6228 6840
/// Lower a `try` expression.
6229 6841
fn lowerTry(self: *mut FnLowerer, node: *ast::Node, t: ast::Try) -> il::Val throws (LowerError) {
6230 6842
    let case ast::NodeValue::Call(callExpr) = t.expr.value else {
6244 6856
    let callNodeExtra = resolver::nodeData(self.low.resolver, t.expr).extra;
6245 6857
    if let case resolver::NodeExtra::TraitMethodCall {
6246 6858
        traitInfo, methodIndex
6247 6859
    } = callNodeExtra {
6248 6860
        set resVal = try lowerTraitMethodCall(self, t.expr, callExpr, traitInfo, methodIndex);
6861 +
    } else if let case resolver::NodeExtra::GenericBoundMethodCall {
6862 +
        param, traitInfo, methodIndex, explicitReceiver,
6863 +
    } = callNodeExtra {
6864 +
        set resVal = try lowerGenericBoundMethodCall(
6865 +
            self, t.expr, callExpr, param, traitInfo, methodIndex, explicitReceiver
6866 +
        );
6249 6867
    } else if let case resolver::NodeExtra::MethodCall { method } = callNodeExtra {
6250 6868
        set resVal = try lowerMethodCall(self, t.expr, callExpr, method);
6251 6869
    } else {
6252 6870
        set resVal = try lowerCall(self, t.expr, callExpr);
6253 6871
    }
6646 7264
fn lowerCallOrCtor(self: *mut FnLowerer, node: *ast::Node, call: ast::Call) -> il::Val throws (LowerError) {
6647 7265
    let nodeData = resolver::nodeData(self.low.resolver, node).extra;
6648 7266
6649 7267
    // Check for slice method dispatch.
6650 7268
    if let case resolver::NodeExtra::SliceAppend { elemType } = nodeData {
6651 -
        return try lowerSliceAppend(self, call, elemType);
7269 +
        let concrete = try specializeType(self, *elemType);
7270 +
        return try lowerSliceAppend(self, call, &concrete);
6652 7271
    }
6653 7272
    if let case resolver::NodeExtra::SliceDelete { elemType } = nodeData {
6654 -
        try lowerSliceDelete(self, call, elemType);
7273 +
        let concrete = try specializeType(self, *elemType);
7274 +
        try lowerSliceDelete(self, call, &concrete);
6655 7275
        return il::Val::Undef;
6656 7276
    }
6657 7277
    // Check for trait method dispatch.
6658 7278
    if let case resolver::NodeExtra::TraitMethodCall { traitInfo, methodIndex } = nodeData {
6659 7279
        return try lowerTraitMethodCall(self, node, call, traitInfo, methodIndex);
6660 7280
    }
7281 +
    if let case resolver::NodeExtra::GenericBoundMethodCall {
7282 +
        param, traitInfo, methodIndex, explicitReceiver,
7283 +
    } = nodeData {
7284 +
        return try lowerGenericBoundMethodCall(
7285 +
            self, node, call, param, traitInfo, methodIndex, explicitReceiver
7286 +
        );
7287 +
    }
6661 7288
    // Check for standalone method call.
6662 7289
    if let case resolver::NodeExtra::MethodCall { method } = nodeData {
6663 7290
        return try lowerMethodCall(self, node, call, method);
6664 7291
    }
6665 7292
    if let sym = resolver::nodeData(self.low.resolver, call.callee).sym {
6827 7454
/// If the parent is already a pointer type, the value is used directly.
6828 7455
/// If the parent is a value type (eg. a local record), its address is taken.
6829 7456
fn lowerReceiver(self: *mut FnLowerer, parent: *ast::Node, parentTy: resolver::Type) -> il::Val
6830 7457
    throws (LowerError)
6831 7458
{
6832 -
    if let case resolver::Type::Pointer { .. } = parentTy {
7459 +
    if let case resolver::Type::Pointer(_) = parentTy {
6833 7460
        // Already a pointer: lower and use directly.
6834 7461
        return try lowerExpr(self, parent);
6835 7462
    }
6836 7463
    // Value type: take its address by lowering it and returning the slot pointer.
6837 7464
    // Aggregate types are already lowered as pointers to stack slots.
6845 7472
    try emitStore(self, slot, 0, parentTy, val);
6846 7473
6847 7474
    return il::Val::Reg(slot);
6848 7475
}
6849 7476
7477 +
/// Lower a bounded generic method to its concrete instance function.
7478 +
fn lowerGenericBoundMethodCall(
7479 +
    self: *mut FnLowerer,
7480 +
    node: *ast::Node,
7481 +
    call: ast::Call,
7482 +
    param: *resolver::GenericParamType,
7483 +
    traitInfo: *resolver::TraitType,
7484 +
    methodIndex: u32,
7485 +
    explicitReceiver: bool,
7486 +
) -> il::Val throws (LowerError) {
7487 +
    let mut receiverNode: *ast::Node = undefined;
7488 +
    if explicitReceiver {
7489 +
        if call.args.len == 0 {
7490 +
            throw LowerError::MissingMetadata;
7491 +
        }
7492 +
        set receiverNode = call.args[0];
7493 +
    } else {
7494 +
        let case ast::NodeValue::FieldAccess(access) = call.callee.value
7495 +
            else throw LowerError::MissingMetadata;
7496 +
        set receiverNode = access.parent;
7497 +
    }
7498 +
    let concreteType = try specializeType(self, resolver::Type::Parameter(param));
7499 +
    let inst = resolver::findInstance(
7500 +
        self.low.resolver, traitInfo, concreteType
7501 +
    ) else throw LowerError::MissingMetadata;
7502 +
    let method = &traitInfo.methods[methodIndex];
7503 +
    let _ = resolver::findInstance(
7504 +
        self.low.resolver, method.owner, concreteType
7505 +
    ) else throw LowerError::MissingMetadata;
7506 +
    let methodSym = inst.methods[methodIndex];
7507 +
    let case resolver::SymbolData::Value {
7508 +
        type: resolver::Type::Fn(fnInfo), ..
7509 +
    } = methodSym.data else throw LowerError::MissingMetadata;
7510 +
    let mut receiverVal: il::Val = undefined;
7511 +
    if explicitReceiver {
7512 +
        set receiverVal = try lowerCallArg(self, receiverNode, call.args.len > 1);
7513 +
    } else {
7514 +
        let receiverType = try typeOf(self, receiverNode);
7515 +
        set receiverVal = try lowerReceiver(self, receiverNode, receiverType);
7516 +
    }
7517 +
    let qualName = instanceMethodName(
7518 +
        self.low,
7519 +
        concreteType,
7520 +
        method.owner,
7521 +
        method.name,
7522 +
    );
7523 +
    let argOffset: u32 = 1 if requiresReturnParam(fnInfo) else 0;
7524 +
    let receiverCount: u32 = 0 if explicitReceiver else 1;
7525 +
    let args = try allocVals(self, call.args.len + receiverCount + argOffset);
7526 +
    set args[argOffset] = receiverVal;
7527 +
    for arg, i in call.args {
7528 +
        if explicitReceiver and i == 0 {
7529 +
            continue;
7530 +
        }
7531 +
        set args[i + receiverCount + argOffset] = try lowerCallArg(
7532 +
            self, arg, i + 1 < call.args.len
7533 +
        );
7534 +
    }
7535 +
    return try emitCallValue(self, il::Val::FnAddr(qualName), fnInfo, args);
7536 +
}
7537 +
6850 7538
/// Lower a standalone method call via direct dispatch.
6851 7539
///
6852 7540
/// Given `obj.method(args)` where `method` is a standalone method on a concrete type,
6853 7541
/// emits a direct call with the receiver address as the first argument:
6854 7542
///
6865 7553
6866 7554
    // Get the receiver as a pointer.
6867 7555
    let parentTy = try typeOf(self, access.parent);
6868 7556
    let receiverVal = try lowerReceiver(self, access.parent, parentTy);
6869 7557
6870 -
    let qualName = instanceMethodName(self.low, nil, method.concreteTypeName, method.name);
6871 7558
    let case resolver::SymbolData::Value { type: resolver::Type::Fn(fnInfo), .. } = method.symbol.data
6872 7559
        else panic "lowerMethodCall: expected Fn type on method symbol";
7560 +
    let qualName = instanceMethodName(
7561 +
        self.low, method.concreteType, nil, method.name
7562 +
    );
6873 7563
6874 7564
    // Build args: optional return param slot + receiver + user args.
6875 7565
    let argOffset: u32 = 1 if requiresReturnParam(fnInfo) else 0;
6876 7566
    let args = try allocVals(self, call.args.len + 1 + argOffset);
6877 7567
    set args[argOffset] = receiverVal;
6943 7633
6944 7634
/// Resolve callee to an IL value. For direct function calls, use the symbol name.
6945 7635
/// For variables holding function pointers or complex expressions (eg. `array[i]()`),
6946 7636
/// lower the callee expression.
6947 7637
fn lowerCallee(self: *mut FnLowerer, callee: *ast::Node) -> il::Val throws (LowerError) {
7638 +
    if let generic = try lowerGenericFnValue(self, callee) {
7639 +
        return generic;
7640 +
    }
6948 7641
    if let sym = resolver::nodeData(self.low.resolver, callee).sym {
6949 7642
        if let case ast::NodeValue::FnDecl(_) = sym.node.value {
6950 7643
            // First try to look up the symbol in our registered functions.
6951 7644
            // This handles cross-package calls correctly, since packages are
6952 7645
            // lowered in dependency order.
6991 7684
    let coerce = resolver::coercionFor(self.low.resolver, node) else {
6992 7685
        return val;
6993 7686
    };
6994 7687
    match coerce {
6995 7688
        case resolver::Coercion::OptionalLift(optType) => {
7689 +
            let concrete = try specializeType(self, optType);
6996 7690
            if let case ast::NodeValue::Nil = node.value {
6997 -
                return try buildNilOptional(self, optType);
7691 +
                return try buildNilOptional(self, concrete);
6998 7692
            }
6999 -
            return try wrapInOptional(self, val, optType);
7693 +
            return try wrapInOptional(self, val, concrete);
7000 7694
        }
7001 7695
        case resolver::Coercion::NumericCast { from, to } => {
7002 -
            return lowerNumericCast(self, val, from, to);
7696 +
            return lowerNumericCast(
7697 +
                self,
7698 +
                val,
7699 +
                try specializeType(self, from),
7700 +
                try specializeType(self, to),
7701 +
            );
7003 7702
        }
7004 7703
        case resolver::Coercion::ResultWrap => {
7005 7704
            let payloadType = *self.fnType.returnType;
7006 7705
            return try buildResult(self, 0, val, payloadType);
7007 7706
        }
7138 7837
        else =>
7139 7838
            throw LowerError::UnexpectedNodeValue(node),
7140 7839
    }
7141 7840
}
7142 7841
7842 +
/// Lower a rigid constant parameter using the active specialization.
7843 +
fn lowerGenericConstValue(
7844 +
    self: *mut FnLowerer,
7845 +
    node: *ast::Node,
7846 +
) -> ?il::Val {
7847 +
    let sub = self.low.specialization else return nil;
7848 +
    let sym = resolver::symbolFor(self.low.resolver, node) else return nil;
7849 +
    let case resolver::SymbolData::ConstParameter(param) = sym.data else return nil;
7850 +
    let arg = resolver::substitutionArg(sub, param);
7851 +
    let case resolver::Type::ConstArgument { value, .. } = arg else return nil;
7852 +
    return il::Val::Imm(constIntToI64(value));
7853 +
}
7854 +
7855 +
/// Lower resolver-selected generic function metadata to a concrete address.
7856 +
fn lowerGenericFnValue(
7857 +
    self: *mut FnLowerer,
7858 +
    node: *ast::Node,
7859 +
) -> ?il::Val throws (LowerError) {
7860 +
    let data = resolver::nodeData(self.low.resolver, node);
7861 +
    match data.extra {
7862 +
        case resolver::NodeExtra::GenericFnCall(specialization) => {
7863 +
            return il::Val::FnAddr(
7864 +
                specializationName(self.low, specialization)
7865 +
            );
7866 +
        }
7867 +
        case resolver::NodeExtra::GenericFnDependency(dependency) => {
7868 +
            let caller = self.low.genericSpecialization
7869 +
                else throw LowerError::MissingMetadata;
7870 +
            let specialization = resolver::genericFnSpecializationForDependency(
7871 +
                self.low.resolver, dependency, caller
7872 +
            ) else throw LowerError::MissingMetadata;
7873 +
            return il::Val::FnAddr(
7874 +
                specializationName(self.low, specialization)
7875 +
            );
7876 +
        }
7877 +
        else => return nil,
7878 +
    }
7879 +
}
7880 +
7143 7881
/// Lower an expression AST node to an IL value.
7144 7882
/// This is the main expression dispatch, all expression nodes go through here.
7145 7883
fn lowerExpr(self: *mut FnLowerer, node: *ast::Node) -> il::Val throws (LowerError) {
7146 7884
    if self.low.options.debug {
7147 7885
        set self.srcLoc.offset = node.span.offset;
7148 7886
    }
7149 7887
    let mut val: il::Val = undefined;
7150 7888
7151 7889
    match node.value {
7152 7890
        case ast::NodeValue::Ident(_) => {
7153 -
            // First try local variable lookup.
7154 -
            // Otherwise fall back to global symbol lookup.
7155 -
            if let v = lookupLocalVar(self, node) {
7891 +
            if let constVal = lowerGenericConstValue(self, node) {
7892 +
                set val = constVal;
7893 +
            } else if let generic = try lowerGenericFnValue(self, node) {
7894 +
                set val = generic;
7895 +
            // First try local variable lookup, then global symbol lookup.
7896 +
            } else if let v = lookupLocalVar(self, node) {
7156 7897
                set val = try useVar(self, v);
7157 7898
                if self.vars[*v].addressTaken {
7158 7899
                    let typ = try typeOf(self, node);
7159 7900
                    let ptr = emitValToReg(self, val);
7160 7901
                    set val = emitRead(self, ptr, 0, typ);
7162 7903
            } else {
7163 7904
                set val = try lowerGlobalSymbol(self, node);
7164 7905
            }
7165 7906
        }
7166 7907
        case ast::NodeValue::ScopeAccess(_) => {
7167 -
            set val = try lowerScopeAccess(self, node);
7908 +
            if let generic = try lowerGenericFnValue(self, node) {
7909 +
                set val = generic;
7910 +
            } else {
7911 +
                set val = try lowerScopeAccess(self, node);
7912 +
            }
7168 7913
        }
7169 7914
        case ast::NodeValue::Number(lit) => {
7170 7915
            set val = il::Val::Imm(lit.magnitude as i64);
7171 7916
        }
7172 7917
        case ast::NodeValue::Bool(b) => {
7203 7948
            set val = try lowerUnOp(self, node, unop);
7204 7949
        }
7205 7950
        case ast::NodeValue::Subscript { container, index } => {
7206 7951
            set val = try lowerSubscript(self, node, container, index);
7207 7952
        }
7953 +
        case ast::NodeValue::GenericApply(_) => {
7954 +
            let generic = try lowerGenericFnValue(self, node)
7955 +
                else panic "lowerExpr: unresolved generic application";
7956 +
            set val = generic;
7957 +
        }
7208 7958
        case ast::NodeValue::BuiltinCall { kind, args } => {
7209 7959
            set val = try lowerBuiltinCall(self, node, kind, args);
7210 7960
        }
7211 7961
        case ast::NodeValue::Call(call) => {
7212 7962
            set val = try lowerCallOrCtor(self, node, call);
7222 7972
                    //       Perhaps just store the `ConstInt`.
7223 7973
                    case resolver::ConstValue::Int(i) => set val = il::Val::Imm(constIntToI64(i)),
7224 7974
                    else => set val = try lowerFieldAccess(self, access),
7225 7975
                }
7226 7976
            } else {
7227 -
                set val = try lowerFieldAccess(self, access);
7977 +
                let parentTy = try typeOf(self, access.parent);
7978 +
                let mut handled = false;
7979 +
                if let case resolver::Type::Array(array) = parentTy {
7980 +
                    if let case ast::NodeValue::Ident(name) = access.child.value;
7981 +
                       mem::eq(name, "len")
7982 +
                    {
7983 +
                        set val = il::Val::Imm(array.length as i64);
7984 +
                        set handled = true;
7985 +
                    }
7986 +
                }
7987 +
                if not handled {
7988 +
                    set val = try lowerFieldAccess(self, access);
7989 +
                }
7228 7990
            }
7229 7991
        }
7230 7992
        case ast::NodeValue::ArrayLit(elements) => {
7231 7993
            set val = try lowerArrayLit(self, node, elements);
7232 7994
        }
7272 8034
            let _ = expr;
7273 8035
            set val = il::Val::Undef;
7274 8036
        }
7275 8037
        // Lower these as statements.
7276 8038
        case ast::NodeValue::ConstDecl(decl) => {
7277 -
            try registerLocalDataDeclName(self, node);
7278 -
            try lowerDataDecl(self.low, node, decl.value, true);
8039 +
            let qualName = try registerLocalDataDeclName(self, node);
8040 +
            try lowerDataDecl(self.low, node, decl.value, true, qualName);
7279 8041
            set val = il::Val::Undef;
7280 8042
        }
7281 8043
        case ast::NodeValue::StaticDecl(decl) => {
7282 -
            try registerLocalDataDeclName(self, node);
7283 -
            try lowerDataDecl(self.low, node, decl.value, false);
8044 +
            let qualName = try registerLocalDataDeclName(self, node);
8045 +
            try lowerDataDecl(self.low, node, decl.value, false, qualName);
7284 8046
            set val = il::Val::Undef;
7285 8047
        }
7286 8048
        case ast::NodeValue::Throw { .. },
7287 8049
             ast::NodeValue::Return { .. },
7288 8050
             ast::NodeValue::Continue,
7314 8076
             resolver::Type::U16 => return il::Type::W16,
7315 8077
        case resolver::Type::I32,
7316 8078
             resolver::Type::U32 => return il::Type::W32,
7317 8079
        case resolver::Type::I64,
7318 8080
             resolver::Type::U64,
7319 -
             resolver::Type::Pointer { .. },
7320 -
             resolver::Type::Slice { .. },
7321 -
             resolver::Type::TraitObject { .. },
8081 +
             resolver::Type::Pointer(_),
8082 +
             resolver::Type::Slice(_),
8083 +
             resolver::Type::TraitObject(_),
7322 8084
             resolver::Type::Array(_),
7323 8085
             resolver::Type::Optional(_),
7324 8086
             resolver::Type::Fn(_) => return il::Type::W64,
7325 8087
        case resolver::Type::Nominal(_) => {
7326 8088
            if resolver::isVoidUnion(typ) {
lib/std/lang/lower/tests.rad added +18 -0
1 +
//! Lowering tests.
2 +
3 +
use std::testing;
4 +
use std::lang::alloc;
5 +
use std::lang::module;
6 +
use std::lang::resolver;
7 +
8 +
/// Verify that a lowerer constructor accepts an immutable resolver pointer.
9 +
@test fn testLowererAcceptsImmutableResolver() throws (testing::TestError) {
10 +
    let constructor: fn(
11 +
        *resolver::Resolver,
12 +
        *module::ModuleGraph,
13 +
        *[u8],
14 +
        *mut alloc::Arena,
15 +
        *mut alloc::Arena,
16 +
        super::LowerOptions
17 +
    ) -> super::Lowerer = super::lowerer;
18 +
}
lib/std/lang/parser.rad +152 -12
331 331
    return node(p, ast::NodeValue::CondExpr(
332 332
        ast::CondExpr { condition, thenExpr, elseExpr }
333 333
    ));
334 334
}
335 335
336 +
/// Return whether a token can begin an unambiguous type argument.
337 +
fn isDefiniteTypeStart(kind: scanner::TokenKind) -> bool {
338 +
    match kind {
339 +
        case scanner::TokenKind::Question,
340 +
             scanner::TokenKind::Star,
341 +
             scanner::TokenKind::Amp,
342 +
             scanner::TokenKind::LBracket,
343 +
             scanner::TokenKind::U8,
344 +
             scanner::TokenKind::U16,
345 +
             scanner::TokenKind::U32,
346 +
             scanner::TokenKind::U64,
347 +
             scanner::TokenKind::I8,
348 +
             scanner::TokenKind::I16,
349 +
             scanner::TokenKind::I32,
350 +
             scanner::TokenKind::I64,
351 +
             scanner::TokenKind::Bool,
352 +
             scanner::TokenKind::Opaque,
353 +
             scanner::TokenKind::Fn => return true,
354 +
        else => return false,
355 +
    }
356 +
}
357 +
358 +
/// Parse one generic argument. A bare nominal path remains a type because the
359 +
/// parser cannot know the template parameter kind yet. If a following operator
360 +
/// continues the path as an expression, restore the speculative type parse and
361 +
/// retain the whole expression for constant-parameter resolution.
362 +
fn parseGenericArg(p: *mut Parser) -> *ast::Node throws (ParseError) {
363 +
    if isDefiniteTypeStart(p.current.kind) or
364 +
       p.current.kind == scanner::TokenKind::Ident or
365 +
       p.current.kind == scanner::TokenKind::Super
366 +
    {
367 +
        let saved = saveState(p);
368 +
        if let arg = try? parseType(p);
369 +
           check(p, scanner::TokenKind::Comma) or
370 +
           check(p, scanner::TokenKind::RAngle)
371 +
        {
372 +
            return arg;
373 +
        }
374 +
        restoreState(p, &saved);
375 +
    }
376 +
    return try parseNormalExpr(p);
377 +
}
378 +
379 +
/// Parse a non-empty generic argument list.
380 +
fn parseGenericArgs(p: *mut Parser) -> *mut [*ast::Node] throws (ParseError) {
381 +
    try expect(p, scanner::TokenKind::LAngle, "expected left angle before generic arguments");
382 +
    if check(p, scanner::TokenKind::RAngle) {
383 +
        throw failParsing(p, "generic argument list cannot be empty");
384 +
    }
385 +
    let mut args = ast::nodeSlice(p.arena, 4);
386 +
    loop {
387 +
        args.append(try parseGenericArg(p), p.allocator);
388 +
        if not consume(p, scanner::TokenKind::Comma) {
389 +
            break;
390 +
        }
391 +
        if check(p, scanner::TokenKind::RAngle) {
392 +
            throw failParsing(p, "expected generic argument after `,`");
393 +
        }
394 +
    }
395 +
    try expect(p, scanner::TokenKind::RAngle, "expected right angle after generic arguments");
396 +
    return args;
397 +
}
398 +
399 +
/// Parse generic arguments following a target.
400 +
fn parseGenericApply(p: *mut Parser, target: *ast::Node) -> *ast::Node
401 +
    throws (ParseError)
402 +
{
403 +
    let args = try parseGenericArgs(p);
404 +
    return node(p, ast::NodeValue::GenericApply(ast::GenericApply {
405 +
        target, args,
406 +
    }));
407 +
}
408 +
336 409
/// Parse array subscript or slice expression after `[`.
337 410
fn parseSubscriptOrSlice(p: *mut Parser, container: *ast::Node) -> *ast::Node
338 411
    throws (ParseError)
339 412
{
340 413
    try expect(p, scanner::TokenKind::LBracket, "expected `[`");
398 471
                ));
399 472
            }
400 473
            case scanner::TokenKind::LBracket => {
401 474
                set result = try parseSubscriptOrSlice(p, result);
402 475
            }
476 +
            case scanner::TokenKind::LAngle => {
477 +
                set result = try parseGenericApply(p, result);
478 +
            }
403 479
            case scanner::TokenKind::LParen => {
404 480
                set result = try parseCall(p, result);
405 481
            }
406 482
            case scanner::TokenKind::LBrace if p.context <> Context::Condition => {
407 483
                set result = try parseRecordLit(p, result);
485 561
        case scanner::TokenKind::Comma,
486 562
             scanner::TokenKind::Semicolon,
487 563
             scanner::TokenKind::RParen,
488 564
             scanner::TokenKind::RBrace,
489 565
             scanner::TokenKind::RBracket,
566 +
             scanner::TokenKind::RAngle,
490 567
             scanner::TokenKind::Else,
491 568
             scanner::TokenKind::In,
492 569
             scanner::TokenKind::LBrace,
493 570
             scanner::TokenKind::Eof =>
494 571
            return true,
936 1013
            return try parseTraitDecl(p, attrs);
937 1014
        }
938 1015
        case scanner::TokenKind::Instance => {
939 1016
            return try parseInstanceDecl(p);
940 1017
        }
1018 +
        case scanner::TokenKind::Instantiate => {
1019 +
            return try parseInstantiate(p);
1020 +
        }
941 1021
        else => {
942 1022
            return try parseExprStmt(p);
943 1023
        }
944 1024
    }
945 1025
}
1603 1683
    try expect(p, terminator, "expected closing delimiter after record fields");
1604 1684
1605 1685
    return fields;
1606 1686
}
1607 1687
1688 +
/// Parse an optional generic parameter list.
1689 +
fn parseGenericParams(p: *mut Parser) -> *mut [*ast::Node] throws (ParseError) {
1690 +
    let mut params = ast::nodeSlice(p.arena, 4);
1691 +
    if not consume(p, scanner::TokenKind::LAngle) {
1692 +
        return params;
1693 +
    }
1694 +
    if check(p, scanner::TokenKind::RAngle) {
1695 +
        throw failParsing(p, "generic parameter list cannot be empty");
1696 +
    }
1697 +
    loop {
1698 +
        let isConst = consume(p, scanner::TokenKind::Constant);
1699 +
        if isConst and consume(p, scanner::TokenKind::Constant) {
1700 +
            throw failParsing(p, "duplicate `constant` in generic parameter");
1701 +
        }
1702 +
        let name = try parseIdent(p, "expected generic parameter name");
1703 +
        let mut param: *ast::Node = undefined;
1704 +
        if isConst {
1705 +
            try expect(p, scanner::TokenKind::Colon, "expected `:` after constant parameter");
1706 +
            let type = try parseType(p);
1707 +
            set param = node(p, ast::NodeValue::GenericParam(
1708 +
                ast::GenericParam::Const { name, type }
1709 +
            ));
1710 +
        } else {
1711 +
            let bounds = try parseDerives(p);
1712 +
            set param = node(p, ast::NodeValue::GenericParam(
1713 +
                ast::GenericParam::Type { name, bounds }
1714 +
            ));
1715 +
        }
1716 +
        params.append(param, p.allocator);
1717 +
        if not consume(p, scanner::TokenKind::Comma) {
1718 +
            break;
1719 +
        }
1720 +
        if check(p, scanner::TokenKind::RAngle) {
1721 +
            throw failParsing(p, "expected generic parameter after `,`");
1722 +
        }
1723 +
    }
1724 +
    try expect(p, scanner::TokenKind::RAngle, "expected right angle after generic parameters");
1725 +
    return params;
1726 +
}
1727 +
1608 1728
/// Parse an optional derives list (`: Trait + Trait`).
1609 1729
fn parseDerives(p: *mut Parser) -> *mut [*ast::Node] throws (ParseError) {
1610 1730
    let mut derives = ast::nodeSlice(p.arena, 4);
1611 1731
1612 1732
    if not consume(p, scanner::TokenKind::Colon) {
1613 1733
        return derives;
1614 1734
    }
1615 1735
    loop {
1616 -
        let t = try parseIdent(p, "expected trait name in derive list");
1736 +
        let t = try parseTypePath(p);
1617 1737
        derives.append(t, p.allocator);
1618 1738
1619 1739
        if not consume(p, scanner::TokenKind::Plus) {
1620 1740
            break;
1621 1741
        }
1678 1798
    throws (ParseError)
1679 1799
{
1680 1800
    try expect(p, scanner::TokenKind::Record, "expected `record`");
1681 1801
1682 1802
    let name = try parseIdent(p, "expected record name");
1803 +
    let params = try parseGenericParams(p);
1683 1804
    let derives = try parseDerives(p);
1684 1805
1685 1806
    if consume(p, scanner::TokenKind::LParen) {
1686 1807
        let fields = try parseRecordFields(p, RecordFieldMode::Unlabeled);
1687 1808
        try expect(p, scanner::TokenKind::Semicolon, "expected `;` after record");
1688 1809
        return node(p, ast::NodeValue::RecordDecl(
1689 -
            ast::RecordDecl { name, fields, attrs, derives, labeled: false }
1810 +
            ast::RecordDecl { name, params, fields, attrs, derives, labeled: false }
1690 1811
        ));
1691 1812
    } else {
1692 1813
        try expect(p, scanner::TokenKind::LBrace, "expected `{` before record body");
1693 1814
        let fields = try parseRecordFields(p, RecordFieldMode::Labeled);
1694 1815
        return node(p, ast::NodeValue::RecordDecl(
1695 -
            ast::RecordDecl { name, fields, attrs, derives, labeled: true }
1816 +
            ast::RecordDecl { name, params, fields, attrs, derives, labeled: true }
1696 1817
        ));
1697 1818
    }
1698 1819
}
1699 1820
1700 1821
/// Parse a union declaration.
1703 1824
    throws (ParseError)
1704 1825
{
1705 1826
    try expect(p, scanner::TokenKind::Union, "expected `union`");
1706 1827
1707 1828
    let name = try parseIdent(p, "expected union name");
1829 +
    let params = try parseGenericParams(p);
1708 1830
    let derives = try parseDerives(p);
1709 1831
1710 1832
    try expect(p, scanner::TokenKind::LBrace, "expected `{` before union body");
1711 1833
1712 1834
    let mut variants = ast::nodeSlice(p.arena, 128);
1727 1849
            let fields = try parseRecordFields(p, RecordFieldMode::Labeled);
1728 1850
            set payloadType = node(p, ast::NodeValue::TypeSig(
1729 1851
                ast::TypeSig::Record { fields, labeled: true }
1730 1852
            ));
1731 1853
        } else if consume(p, scanner::TokenKind::Equal) {
1732 -
            // TODO: Support constant expressions.
1733 -
            try expect(p, scanner::TokenKind::Number, "expected integer literal after `=`");
1734 -
            let literal = try parseIntLiteral(p, p.previous.source);
1735 -
            set explicitValue = nodeNumber(p, literal);
1854 +
            set explicitValue = try parseNormalExpr(p);
1736 1855
        }
1737 1856
1738 1857
        let variant = node(p, ast::NodeValue::UnionDeclVariant(
1739 1858
            ast::UnionDeclVariant {
1740 1859
                name: variantName, index: variants.len as u32, value: explicitValue, type: payloadType,
1747 1866
        }
1748 1867
    }
1749 1868
    try expect(p, scanner::TokenKind::RBrace, "expected `}`");
1750 1869
1751 1870
    return node(p, ast::NodeValue::UnionDecl(
1752 -
        ast::UnionDecl { name, variants, attrs, derives }
1871 +
        ast::UnionDecl { name, params, variants, attrs, derives }
1753 1872
    ));
1754 1873
}
1755 1874
1756 1875
/// Parse a function parameter.
1757 1876
fn parseFnParam(p: *mut Parser) -> *ast::Node
1839 1958
    // Method syntax: `fn (recv: *Type) name(params) { body }`.
1840 1959
    if check(p, scanner::TokenKind::LParen) {
1841 1960
        return try parseMethodDecl(p, attrs);
1842 1961
    }
1843 1962
    let name = try parseIdent(p, "expected function name");
1963 +
    let params = try parseGenericParams(p);
1844 1964
    let sig = try parseFnTypeSig(p);
1845 1965
    let mut body: ?*ast::Node = nil;
1846 1966
    let mut fnAttrs = attrs;
1847 1967
1848 1968
    if consume(p, scanner::TokenKind::Semicolon) {
1861 1981
        }
1862 1982
    } else {
1863 1983
        set body = try parseBlock(p);
1864 1984
    }
1865 1985
    return node(p, ast::NodeValue::FnDecl(
1866 -
        ast::FnDecl { name, sig, body, attrs: fnAttrs }
1986 +
        ast::FnDecl { name, params, sig, body, attrs: fnAttrs }
1867 1987
    ));
1868 1988
}
1869 1989
1870 1990
/// Parse a pointer-like type after its ownership prefix.
1871 1991
fn parsePointerLikeType(
1966 2086
        }
1967 2087
        case scanner::TokenKind::LBracket => {
1968 2088
            return try parseArrayType(p);
1969 2089
        }
1970 2090
        case scanner::TokenKind::Super, scanner::TokenKind::Ident => {
1971 -
            let path = try parseTypePath(p);
1972 2091
2092 +
            let mut name = try parseTypePath(p);
2093 +
            if check(p, scanner::TokenKind::LAngle) {
2094 +
                set name = try parseGenericApply(p, name);
2095 +
            }
1973 2096
            return node(p, ast::NodeValue::TypeSig(
1974 -
                ast::TypeSig::Nominal(path)
2097 +
                ast::TypeSig::Nominal(name)
1975 2098
            ));
1976 2099
        }
1977 2100
        case scanner::TokenKind::U8 => {
1978 2101
            advance(p);
1979 2102
            return nodeTypeInt(p, 1, ast::Signedness::Unsigned);
2240 2363
        case scanner::TokenKind::RBrace => return "expected `}`",
2241 2364
        else => return "expected delimiter",
2242 2365
    }
2243 2366
}
2244 2367
2368 +
/// Parse one or more explicit specialization roots.
2369 +
fn parseInstantiate(p: *mut Parser) -> *ast::Node throws (ParseError) {
2370 +
    try expect(p, scanner::TokenKind::Instantiate, "expected `instantiate`");
2371 +
    let mut applications = ast::nodeSlice(p.arena, 4);
2372 +
    loop {
2373 +
        let target = try parseTypePath(p);
2374 +
        if not check(p, scanner::TokenKind::LAngle) {
2375 +
            throw failParsing(p, "`instantiate` requires a generic application");
2376 +
        }
2377 +
        applications.append(try parseGenericApply(p, target), p.allocator);
2378 +
        if not consume(p, scanner::TokenKind::Comma) {
2379 +
            break;
2380 +
        }
2381 +
    }
2382 +
    return node(p, ast::NodeValue::Instantiate(applications));
2383 +
}
2384 +
2245 2385
/// Parse a trait declaration.
2246 2386
/// Syntax: `trait Name { fn (*Trait) method(...) -> T; ... }`
2247 2387
fn parseTraitDecl(p: *mut Parser, attrs: ?ast::Attributes) -> *ast::Node
2248 2388
    throws (ParseError)
2249 2389
{
2293 2433
    throws (ParseError)
2294 2434
{
2295 2435
    try expect(p, scanner::TokenKind::Instance, "expected `instance`");
2296 2436
    let traitName = try parseTypePath(p);
2297 2437
    try expect(p, scanner::TokenKind::For, "expected `for` after trait name");
2298 -
    let targetType = try parseTypePath(p);
2438 +
    let targetType = try parseType(p);
2299 2439
    try expect(p, scanner::TokenKind::LBrace, "expected `{` after target type");
2300 2440
2301 2441
    let mut methods = ast::nodeSlice(p.arena, ast::MAX_TRAIT_METHODS);
2302 2442
2303 2443
    while not check(p, scanner::TokenKind::RBrace) and
lib/std/lang/parser/tests.rad +194 -5
117 117
    try super::expect(&mut parser, scanner::TokenKind::Eof, "expected end of statement");
118 118
119 119
    return root;
120 120
}
121 121
122 +
/// Require a statement to fail with one focused parser diagnostic.
123 +
fn expectStmtParseError(input: *[u8], message: *[u8])
124 +
    throws (testing::TestError)
125 +
{
126 +
    let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]);
127 +
    let mut parser = super::mkParser(
128 +
        scanner::SourceLoc::String, input, &mut arena, &mut STRING_POOL
129 +
    );
130 +
    super::advance(&mut parser);
131 +
    try super::parseStmt(&mut parser) catch {
132 +
        assert parser.errors.count == 1;
133 +
        assert mem::eq(parser.errors.list[0].message, message);
134 +
        return;
135 +
    };
136 +
    throw testing::TestError::Failed;
137 +
}
138 +
122 139
/// Parse an expression expected to be a number literal and return its payload.
123 140
fn parseNumberLiteral(text: *[u8]) -> fmt::IntLiteral
124 141
    throws (testing::TestError)
125 142
{
126 143
    let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]);
1137 1154
    let case ast::NodeValue::FnDecl(decl) = node.value
1138 1155
        else throw testing::TestError::Failed;
1139 1156
    let attrs = decl.attrs
1140 1157
        else throw testing::TestError::Failed;
1141 1158
1142 -
    try testing::expect(attrs.list.len == 1);
1143 -
    try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Unsafe));
1159 +
    assert attrs.list.len == 1;
1160 +
    assert ast::attributesContains(&attrs, ast::Attribute::Unsafe);
1144 1161
}
1145 1162
1146 1163
/// Test rejecting `unsafe` on declarations where it has no semantics.
1147 1164
@test fn testParseUnsafeUnsupportedDecl() throws (testing::TestError) {
1148 1165
    let recordDecl: ?*ast::Node = try? parseStmtStr("unsafe record R {}");
1149 -
    try testing::expect(recordDecl == nil);
1166 +
    assert recordDecl == nil;
1150 1167
    let constDecl: ?*ast::Node = try? parseStmtStr("unsafe constant X = 1;");
1151 -
    try testing::expect(constDecl == nil);
1168 +
    assert constDecl == nil;
1152 1169
}
1153 1170
1154 1171
/// Test `unsafe` on the other declaration forms that support it.
1155 1172
@test fn testParseUnsafeMethodAndModule() throws (testing::TestError) {
1156 1173
    let moduleNode = try! parseStmtStr("unsafe mod io;");
1162 1179
    let instanceNode = try! parseStmtStr(
1163 1180
        "instance Read for Value { unsafe fn (value: &Value) get() {} }"
1164 1181
    );
1165 1182
    let case ast::NodeValue::InstanceDecl { methods, .. } = instanceNode.value
1166 1183
        else throw testing::TestError::Failed;
1167 -
    try testing::expect(methods.len == 1);
1184 +
    assert methods.len == 1;
1168 1185
    let case ast::NodeValue::MethodDecl { attrs, .. } = methods[0].value
1169 1186
        else throw testing::TestError::Failed;
1170 1187
    let methodAttrs = attrs else throw testing::TestError::Failed;
1171 1188
    assert ast::attributesContains(&methodAttrs, ast::Attribute::Unsafe);
1172 1189
2937 2954
    // Throws lists.
2938 2955
    let throwsNode = try! parseStmtStr("fn handle() throws (Error, Other,) {}");
2939 2956
    let case ast::NodeValue::FnDecl(throwsDecl) = throwsNode.value else throw testing::TestError::Failed;
2940 2957
    try testing::expect(throwsDecl.sig.throwList.len == 2);
2941 2958
}
2959 +
2960 +
/// Generic declarations retain ordered type, bound, and constant parameters.
2961 +
@test fn testParseGenericDeclarations() throws (testing::TestError) {
2962 +
    let recordNode = try! parseStmtStr(
2963 +
        "record Pair⟨T: Reader + Writer, U⟩ { first: T, second: U }"
2964 +
    );
2965 +
    let case ast::NodeValue::RecordDecl(recordDecl) = recordNode.value
2966 +
        else throw testing::TestError::Failed;
2967 +
    assert recordDecl.params.len == 2;
2968 +
    let case ast::NodeValue::GenericParam(ast::GenericParam::Type {
2969 +
        name: firstName, bounds
2970 +
    }) = recordDecl.params[0].value else throw testing::TestError::Failed;
2971 +
    try expectIdent(firstName, "T");
2972 +
    assert bounds.len == 2;
2973 +
    try expectIdent(bounds[0], "Reader");
2974 +
    try expectIdent(bounds[1], "Writer");
2975 +
2976 +
    let unionNode = try! parseStmtStr("union Maybe⟨T⟩ { None, Some(T) }");
2977 +
    let case ast::NodeValue::UnionDecl(unionDecl) = unionNode.value
2978 +
        else throw testing::TestError::Failed;
2979 +
    assert unionDecl.params.len == 1;
2980 +
2981 +
    let fnNode = try! parseStmtStr("fn first⟨T⟩(value: T) -> T { return value; }");
2982 +
    let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
2983 +
        else throw testing::TestError::Failed;
2984 +
    assert fnDecl.params.len == 1;
2985 +
2986 +
    let constNode = try! parseStmtStr(
2987 +
        "record InlineVec⟨T, constant N: u32⟩ { data: [T; 4] }"
2988 +
    );
2989 +
    let case ast::NodeValue::RecordDecl(constDecl) = constNode.value
2990 +
        else throw testing::TestError::Failed;
2991 +
    let case ast::NodeValue::GenericParam(ast::GenericParam::Const {
2992 +
        name: constName, type: constType
2993 +
    }) = constDecl.params[1].value else throw testing::TestError::Failed;
2994 +
    try expectIdent(constName, "N");
2995 +
    try expectIntType(constType, 4, ast::Signedness::Unsigned);
2996 +
}
2997 +
2998 +
/// Generic applications nest in nominal types and preserve qualified targets.
2999 +
@test fn testParseGenericTypeApplications() throws (testing::TestError) {
3000 +
    let node = try! parseTypeStr("Result⟨collections::Vec⟨T⟩, E⟩");
3001 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(outerNode)) = node.value
3002 +
        else throw testing::TestError::Failed;
3003 +
    let case ast::NodeValue::GenericApply(outer) = outerNode.value
3004 +
        else throw testing::TestError::Failed;
3005 +
    try expectIdent(outer.target, "Result");
3006 +
    assert outer.args.len == 2;
3007 +
3008 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(innerNode)) =
3009 +
        outer.args[0].value else throw testing::TestError::Failed;
3010 +
    let case ast::NodeValue::GenericApply(inner) = innerNode.value
3011 +
        else throw testing::TestError::Failed;
3012 +
    let case ast::NodeValue::ScopeAccess(path) = inner.target.value
3013 +
        else throw testing::TestError::Failed;
3014 +
    try expectIdent(path.parent, "collections");
3015 +
    try expectIdent(path.child, "Vec");
3016 +
    assert inner.args.len == 1;
3017 +
    try expectTypeIdent(inner.args[0], "T");
3018 +
    try expectTypeIdent(outer.args[1], "E");
3019 +
3020 +
    let constNode = try! parseTypeStr("InlineVec⟨T, N + 1⟩");
3021 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(constAppNode)) =
3022 +
        constNode.value else throw testing::TestError::Failed;
3023 +
    let case ast::NodeValue::GenericApply(constApp) = constAppNode.value
3024 +
        else throw testing::TestError::Failed;
3025 +
    let case ast::NodeValue::BinOp(constExpr) = constApp.args[1].value
3026 +
        else throw testing::TestError::Failed;
3027 +
    assert constExpr.op == ast::BinaryOp::Add;
3028 +
    try expectIdent(constExpr.left, "N");
3029 +
    try expectNumber(constExpr.right, "1");
3030 +
3031 +
    let rangeNode = try! parseTypeStr("Window⟨0..⟩");
3032 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(rangeAppNode)) =
3033 +
        rangeNode.value else throw testing::TestError::Failed;
3034 +
    let case ast::NodeValue::GenericApply(rangeApp) = rangeAppNode.value
3035 +
        else throw testing::TestError::Failed;
3036 +
    let case ast::NodeValue::Range(range) = rangeApp.args[0].value
3037 +
        else throw testing::TestError::Failed;
3038 +
    assert range.start <> nil;
3039 +
    assert range.end == nil;
3040 +
}
3041 +
3042 +
/// Function applications use generic syntax without changing array subscripts.
3043 +
@test fn testParseGenericFunctionApplications() throws (testing::TestError) {
3044 +
    let explicit = try! parseExprStr("first⟨i32⟩(value)");
3045 +
    let case ast::NodeValue::Call(call) = explicit.value
3046 +
        else throw testing::TestError::Failed;
3047 +
    let case ast::NodeValue::GenericApply(app) = call.callee.value
3048 +
        else throw testing::TestError::Failed;
3049 +
    try expectIdent(app.target, "first");
3050 +
    assert app.args.len == 1;
3051 +
    try expectIntType(app.args[0], 4, ast::Signedness::Signed);
3052 +
3053 +
    let singleSymbolic = try! parseExprStr("first⟨T⟩(value)");
3054 +
    let case ast::NodeValue::Call(singleCall) = singleSymbolic.value
3055 +
        else throw testing::TestError::Failed;
3056 +
    let case ast::NodeValue::GenericApply(singleApp) = singleCall.callee.value
3057 +
        else throw testing::TestError::Failed;
3058 +
    assert singleApp.args.len == 1;
3059 +
    try expectTypeIdent(singleApp.args[0], "T");
3060 +
3061 +
    let recordExpr = try! parseExprStr("Pair⟨T⟩ { first: value }");
3062 +
    let case ast::NodeValue::RecordLit(recordLit) = recordExpr.value
3063 +
        else throw testing::TestError::Failed;
3064 +
    let recordType = recordLit.typeName else throw testing::TestError::Failed;
3065 +
    let case ast::NodeValue::GenericApply(recordApp) = recordType.value
3066 +
        else throw testing::TestError::Failed;
3067 +
    assert recordApp.args.len == 1;
3068 +
3069 +
    let indexedCall = try! parseExprStr("callbacks[*index](value)");
3070 +
    let case ast::NodeValue::Call(indexed) = indexedCall.value
3071 +
        else throw testing::TestError::Failed;
3072 +
    let case ast::NodeValue::Subscript { index, .. } = indexed.callee.value
3073 +
        else throw testing::TestError::Failed;
3074 +
    let case ast::NodeValue::Deref(indexTarget) = index.value
3075 +
        else throw testing::TestError::Failed;
3076 +
    try expectIdent(indexTarget, "index");
3077 +
3078 +
    let symbolic = try! parseExprStr("map⟨T, U⟩(value)");
3079 +
    let case ast::NodeValue::Call(symbolicCall) = symbolic.value
3080 +
        else throw testing::TestError::Failed;
3081 +
    let case ast::NodeValue::GenericApply(symbolicApp) = symbolicCall.callee.value
3082 +
        else throw testing::TestError::Failed;
3083 +
    assert symbolicApp.args.len == 2;
3084 +
3085 +
    let functionValue = try! parseExprStr("first⟨i32⟩");
3086 +
    let case ast::NodeValue::GenericApply(valueApp) = functionValue.value
3087 +
        else throw testing::TestError::Failed;
3088 +
    try expectIntType(valueApp.args[0], 4, ast::Signedness::Signed);
3089 +
3090 +
    let subscript = try! parseExprStr("values[index]");
3091 +
    let case ast::NodeValue::Subscript { .. } = subscript.value
3092 +
        else throw testing::TestError::Failed;
3093 +
}
3094 +
3095 +
/// Instantiation roots retain every applied path in a grouped declaration.
3096 +
@test fn testParseInstantiateDeclaration() throws (testing::TestError) {
3097 +
    let node = try! parseStmtStr(
3098 +
        "instantiate collections::Pair⟨i32, bool⟩, Maybe⟨i32⟩;"
3099 +
    );
3100 +
    let case ast::NodeValue::Instantiate(applications) = node.value
3101 +
        else throw testing::TestError::Failed;
3102 +
    assert applications.len == 2;
3103 +
    let case ast::NodeValue::GenericApply(app) = applications[0].value
3104 +
        else throw testing::TestError::Failed;
3105 +
    let case ast::NodeValue::ScopeAccess(path) = app.target.value
3106 +
        else throw testing::TestError::Failed;
3107 +
    try expectIdent(path.parent, "collections");
3108 +
    try expectIdent(path.child, "Pair");
3109 +
    assert app.args.len == 2;
3110 +
    let case ast::NodeValue::GenericApply(second) = applications[1].value
3111 +
        else throw testing::TestError::Failed;
3112 +
    try expectIdent(second.target, "Maybe");
3113 +
    assert second.args.len == 1;
3114 +
}
3115 +
3116 +
/// Generic syntax reports focused malformed-list diagnostics.
3117 +
@test fn testParseGenericDiagnostics() throws (testing::TestError) {
3118 +
    try expectStmtParseError(
3119 +
        "record Empty⟨⟩ {}", "generic parameter list cannot be empty"
3120 +
    );
3121 +
    try expectStmtParseError(
3122 +
        "record Bad⟨constant constant N: u32⟩ {}", "duplicate `constant` in generic parameter"
3123 +
    );
3124 +
    try expectStmtParseError(
3125 +
        "instantiate Pair⟨i32,⟩;", "expected generic argument after `,`"
3126 +
    );
3127 +
    try expectStmtParseError(
3128 +
        "instantiate Pair;", "`instantiate` requires a generic application"
3129 +
    );
3130 +
}
lib/std/lang/resolver.rad +3554 -611
28 28
export constant ANALYZE_EXPR_FN_NAME: *[u8] = "__expr__";
29 29
/// Synthetic function name used when wrapping a block for analysis.
30 30
export constant ANALYZE_BLOCK_FN_NAME: *[u8] = "__block__";
31 31
32 32
/// Maximum number of symbols stored within a module scope.
33 -
export constant MAX_MODULE_SYMBOLS: u32 = 512;
33 +
export constant MAX_MODULE_SYMBOLS: u32 = 768;
34 34
/// Maximum number of symbols stored within a local scope.
35 35
export constant MAX_LOCAL_SYMBOLS: u32 = 32;
36 36
/// Maximum function parameters.
37 37
export constant MAX_FN_PARAMS: u32 = 8;
38 38
/// Maximum function thrown types.
45 45
export constant MAX_LOOP_DEPTH: u32 = 16;
46 46
/// Maximum trait instances.
47 47
export constant MAX_INSTANCES: u32 = 128;
48 48
/// Maximum standalone methods (across all types).
49 49
export constant MAX_METHODS: u32 = 256;
50 +
/// Maximum generic parameters on one declaration.
51 +
export constant MAX_GENERIC_PARAMS: u32 = 8;
52 +
/// Maximum explicit specialization roots in one package.
53 +
export constant MAX_GENERIC_ROOTS: u32 = 256;
54 +
/// Maximum canonical data and function specializations in one package.
55 +
export constant MAX_GENERIC_SPECIALIZATIONS: u32 = 512;
56 +
/// Maximum expanding generic function dependency depth.
57 +
export constant MAX_GENERIC_SPECIALIZATION_DEPTH: u16 = 32;
50 58
/// Maximum number of linear bindings active in one function.
51 59
constant MAX_LINEAR_BINDINGS: u32 = 32;
52 60
/// Maximum nesting depth tracked for loops.
53 61
constant MAX_LINEAR_LOOP_DEPTH: u32 = 16;
54 62
63 +
/// Resolution state for a trait signature table.
64 +
export union TraitState {
65 +
    /// Signature resolution has not started.
66 +
    Queued,
67 +
    /// Signature resolution is in progress.
68 +
    Resolving,
69 +
    /// Signature resolution is complete.
70 +
    Complete,
71 +
}
72 +
55 73
/// Trait definition stored in the resolver.
56 74
export record TraitType {
57 75
    /// Trait name.
58 76
    name: *[u8],
77 +
    /// Module-local identity used by semantic tables.
78 +
    moduleId: u16,
79 +
    nodeId: u32,
59 80
    /// Method signatures, including from supertraits.
60 81
    methods: *mut [TraitMethod],
61 82
    /// Supertraits that must also be implemented.
62 83
    supertraits: *mut [*TraitType],
84 +
    /// Rigid `Self` type used by static signatures.
85 +
    selfType: *GenericParamType,
86 +
    /// Whether signature resolution has started or completed.
87 +
    state: TraitState,
88 +
    /// Whether every vtable-exposed method is object-safe.
89 +
    objectSafe: bool,
63 90
}
64 91
65 92
/// A single method signature within a trait.
66 93
export record TraitMethod {
67 94
    /// Method name.
70 97
    fnType: *FnType,
71 98
    /// Whether the receiver is mutable.
72 99
    mutable: bool,
73 100
    /// Pointer-like class used by the receiver.
74 101
    receiverClass: types::PointerClass,
102 +
    /// Trait that originally declared this method.
103 +
    owner: *TraitType,
75 104
    /// V-table slot index.
76 105
    index: u32,
77 106
}
78 107
79 108
/// An entry in the trait instance registry.
80 109
export record InstanceEntry {
81 110
    /// Trait type descriptor.
82 111
    traitType: *TraitType,
83 112
    /// Concrete type that implements the trait.
84 113
    concreteType: Type,
85 -
    /// Name of the concrete type.
86 -
    concreteTypeName: *[u8],
87 114
    /// Module where this instance was declared.
88 115
    moduleId: u16,
89 116
    /// Method symbols for each trait method, in declaration order.
90 117
    methods: *mut [*mut Symbol],
91 118
}
92 119
93 120
/// An entry in the method registry.
94 121
export record MethodEntry {
95 122
    /// Concrete type that owns the method.
96 123
    concreteType: Type,
97 -
    /// Name of the concrete type.
98 -
    concreteTypeName: *[u8],
99 124
    /// Method name.
100 125
    name: *[u8],
101 126
    /// Function type excluding the receiver.
102 127
    fnType: *FnType,
103 128
    /// Whether the receiver is mutable.
162 187
export record ArrayType {
163 188
    item: *Type,
164 189
    length: u32,
165 190
}
166 191
192 +
/// Anonymous record whose field layout depends on rigid parameters.
193 +
export record GenericRecordType {
194 +
    /// Fields in declaration order.
195 +
    fields: *[RecordField],
196 +
    /// Whether the fields have labels.
197 +
    labeled: bool,
198 +
}
199 +
167 200
/// Record nominal type.
168 201
export record RecordType {
169 202
    fields: *[RecordField],
170 203
    labeled: bool,
171 204
    /// Cached layout.
266 299
        bindingName: ?*[u8],
267 300
        indexName: ?*[u8]
268 301
    },
269 302
}
270 303
304 +
/// A rigid type parameter belonging to one generic declaration.
305 +
export record GenericParamType {
306 +
    /// Declaration that owns the parameter.
307 +
    owner: *ast::Node,
308 +
    /// Parameter declaration node.
309 +
    node: *ast::Node,
310 +
    /// Parameter name.
311 +
    name: *[u8],
312 +
    /// Position in the declaration's ordered parameter list.
313 +
    index: u32,
314 +
    /// Resolved trait bounds.
315 +
    bounds: *[*TraitType],
316 +
    /// Shared usage flag, mutable through symbol references.
317 +
    used: *mut bool,
318 +
    /// Declared integer type for a constant parameter, or `nil` for a type parameter.
319 +
    constType: ?*Type,
320 +
}
321 +
271 322
/// Resolved function signature details.
272 323
export record FnType {
273 324
    paramTypes: *[*Type],
274 325
    returnType: *Type,
275 326
    throwList: *[*Type],
276 327
    /// Whether calling this function requires an unsafe context.
277 328
    isUnsafe: bool,
278 329
    localCount: u32,
279 330
}
280 331
332 +
/// Resolved, declaration-scoped generic metadata.
333 +
export record GenericTemplate {
334 +
    /// Template symbol.
335 +
    symbol: *mut Symbol,
336 +
    /// Ordered rigid type parameters.
337 +
    params: *[*GenericParamType],
338 +
    /// Symbolic function signature, for function templates.
339 +
    signature: ?*FnType,
340 +
    /// Symbolic field or variant types, in declaration order.
341 +
    members: *[*Type],
342 +
    /// Whether the declaration explicitly carries the `Linear` marker.
343 +
    declaredLinear: bool,
344 +
    /// Whether a generic function body has already been checked.
345 +
    bodyResolved: bool,
346 +
    /// Symbolic body types consumed by lowering, recorded during body analysis.
347 +
    typeUses: *mut [GenericTypeUse],
348 +
    /// Next generic template.
349 +
    next: ?*mut GenericTemplate,
350 +
}
351 +
352 +
/// Canonical concrete specialization of a generic record or union.
353 +
export record GenericDataSpecialization {
354 +
    /// Template symbol whose declaration is specialized.
355 +
    template: *mut Symbol,
356 +
    /// Ordered, interned concrete type arguments.
357 +
    args: *[*Type],
358 +
    /// Ordinary nominal type produced for this application.
359 +
    nominal: *mut NominalType,
360 +
    /// Whether an explicit `instantiate` declaration requested this type.
361 +
    rooted: bool,
362 +
    /// First concrete application site, used for root diagnostics.
363 +
    site: *ast::Node,
364 +
    /// Next data specialization.
365 +
    next: ?*mut GenericDataSpecialization,
366 +
}
367 +
368 +
/// Worklist state for a concrete generic function body.
369 +
export union GenericFnState {
370 +
    /// Specialization is waiting for dependency processing.
371 +
    Queued,
372 +
    /// Specialization dependencies are being processed.
373 +
    Lowering,
374 +
    /// Specialization dependency processing is complete.
375 +
    Complete,
376 +
}
377 +
378 +
/// Canonical concrete specialization of a generic free function.
379 +
export record GenericFnSpecialization {
380 +
    /// Template symbol whose body is lowered.
381 +
    template: *mut Symbol,
382 +
    /// Ordered, interned concrete type arguments.
383 +
    args: *[*Type],
384 +
    /// Substituted concrete function signature.
385 +
    fnType: *FnType,
386 +
    /// First explicit instantiation site.
387 +
    site: *ast::Node,
388 +
    /// Dependency-closure state.
389 +
    state: GenericFnState,
390 +
    /// Distance from an explicit root, used to bound expanding recursion.
391 +
    depth: u16,
392 +
    /// Whether all lowering-consumed body types have been materialized.
393 +
    typesMaterialized: bool,
394 +
    /// Next function specialization.
395 +
    next: ?*mut GenericFnSpecialization,
396 +
}
397 +
398 +
/// A generic call retained in a checked symbolic function body.
399 +
export record GenericFnDependency {
400 +
    /// Generic function that contains the call, or `nil` for a root call.
401 +
    caller: ?*mut Symbol,
402 +
    /// Generic function called by this dependency.
403 +
    callee: *mut Symbol,
404 +
    /// Symbolic arguments supplied by the caller.
405 +
    args: *[*Type],
406 +
    /// Source node for the call.
407 +
    site: *ast::Node,
408 +
    /// Next dependency for the same template.
409 +
    next: ?*GenericFnDependency,
410 +
}
411 +
412 +
/// Concrete call selected for one symbolic edge in one caller specialization.
413 +
export record GenericFnDependencyResolution {
414 +
    /// Symbolic dependency that selected this call.
415 +
    dependency: *GenericFnDependency,
416 +
    /// Concrete caller specialization.
417 +
    caller: *GenericFnSpecialization,
418 +
    /// Concrete callee specialization.
419 +
    callee: *GenericFnSpecialization,
420 +
    /// Next resolved dependency for the caller.
421 +
    next: ?*GenericFnDependencyResolution,
422 +
}
423 +
424 +
/// One symbolic type use that must be materialized for each reachable generic
425 +
/// function specialization before lowering begins.
426 +
record GenericTypeUse {
427 +
    /// AST node whose lowering metadata contains the type.
428 +
    site: *ast::Node,
429 +
    /// Symbolic type consumed by lowering.
430 +
    ty: Type,
431 +
}
432 +
433 +
/// Type-syntax resolution context.
434 +
union TypeSyntaxContext {
435 +
    /// Resolve fully concrete types and require ordinary aggregate layout.
436 +
    Concrete,
437 +
    /// Retain rigid parameters and defer generic aggregate layout.
438 +
    Symbolic,
439 +
}
440 +
441 +
/// Ordered replacement types for rigid parameters.
442 +
export record Substitution {
443 +
    /// Rigid parameters to replace.
444 +
    params: *[*GenericParamType],
445 +
    /// Concrete arguments matched by position with `params`.
446 +
    args: *[*Type],
447 +
}
448 +
449 +
/// Source of member types for aggregate construction.
450 +
union AggregateMemberSource {
451 +
    /// Resolve ordinary declaration member types.
452 +
    Ordinary,
453 +
    /// Substitute symbolic member types from a generic template.
454 +
    Generic {
455 +
        members: *[*Type],
456 +
        substitution: *Substitution,
457 +
    },
458 +
}
459 +
460 +
/// Symbolic application of a generic data template inside another template.
461 +
export record GenericDataApplyType {
462 +
    /// Generic data template being applied.
463 +
    template: *mut Symbol,
464 +
    /// Symbolic arguments supplied to the template.
465 +
    args: *[*Type],
466 +
    /// Source node for the application.
467 +
    site: *ast::Node,
468 +
}
469 +
470 +
/// Pointer-like address payload.
471 +
export record PointerType {
472 +
    /// Ownership and safety class.
473 +
    class: types::PointerClass,
474 +
    /// Pointer target type.
475 +
    target: *Type,
476 +
    /// Whether the pointer is mutable.
477 +
    mutable: bool,
478 +
}
479 +
480 +
/// Pointer-like slice payload.
481 +
export record SliceType {
482 +
    /// Ownership and safety class.
483 +
    class: types::PointerClass,
484 +
    /// Slice element type.
485 +
    item: *Type,
486 +
    /// Whether the slice is mutable.
487 +
    mutable: bool,
488 +
}
489 +
490 +
/// Erased pointer-like type payload.
491 +
export record TraitObjectType {
492 +
    /// Ownership and safety class.
493 +
    class: types::PointerClass,
494 +
    /// Trait definition.
495 +
    traitInfo: *TraitType,
496 +
    /// Whether the pointer is mutable.
497 +
    mutable: bool,
498 +
}
499 +
281 500
/// Describes a type computed during semantic analysis.
282 501
export union Type {
283 502
    /// A type that couldn't be decided.
284 503
    Unknown,
285 504
    /// Types only used during inference.
291 510
    /// Range types, eg. `start..end`.
292 511
    Range {
293 512
        start: ?*Type,
294 513
        end: ?*Type,
295 514
    },
296 -
    /// Owning pointer-like address.
297 -
    Pointer {
298 -
        class: types::PointerClass,
299 -
        target: *Type,
300 -
        mutable: bool,
301 -
    },
302 -
    /// Owning slice.
303 -
    Slice {
304 -
        class: types::PointerClass,
305 -
        item: *Type,
306 -
        mutable: bool,
307 -
    },
515 +
    /// Pointer-like address.
516 +
    Pointer(PointerType),
517 +
    /// Pointer-like slice.
518 +
    Slice(SliceType),
308 519
    /// Eg. `[i32; 32]`.
309 520
    Array(ArrayType),
521 +
    /// Array type whose length depends on a rigid constant parameter.
522 +
    GenericArray {
523 +
        item: *Type,
524 +
        length: *ast::Node,
525 +
    },
526 +
    /// Rigid integer constant parameter within a generic declaration.
527 +
    ConstParameter(*GenericParamType),
528 +
    /// Canonical typed integer generic argument.
529 +
    ConstArgument {
530 +
        type: *Type,
531 +
        value: ConstInt,
532 +
    },
533 +
    /// Symbolic integer expression awaiting constant-parameter substitution.
534 +
    GenericConstExpr {
535 +
        type: *Type,
536 +
        expr: *ast::Node,
537 +
    },
310 538
    /// Eg. `?T`.
311 539
    Optional(*Type),
312 540
    /// Eg. `fn id(i32) -> i32`.
313 541
    Fn(*FnType),
314 542
    /// Named, ie. user-defined types, includes union variants.
315 543
    Nominal(*NominalType),
316 -
    /// Owning trait object. An erased type with v-table.
317 -
    TraitObject {
318 -
        /// Ownership and safety class.
319 -
        class: types::PointerClass,
320 -
        /// Trait definition.
321 -
        traitInfo: *TraitType,
322 -
        /// Whether the pointer is mutable.
323 -
        mutable: bool,
324 -
    },
544 +
    /// Rigid type parameter within a generic declaration.
545 +
    Parameter(*GenericParamType),
546 +
    /// Anonymous record awaiting substitution before layout.
547 +
    GenericRecord(*GenericRecordType),
548 +
    /// Generic data application awaiting substitution of its arguments.
549 +
    GenericDataApply(*GenericDataApplyType),
550 +
    /// An erased pointer-like type with a v-table.
551 +
    TraitObject(TraitObjectType),
325 552
}
326 553
327 554
/// Structured diagnostic payload for type mismatches.
328 555
export record TypeMismatch {
329 556
    expected: Type,
381 608
        /// Module scope.
382 609
        scope: *mut Scope,
383 610
    },
384 611
    /// Payload describing type symbols with their resolved type.
385 612
    Type(*mut NominalType),
613 +
    /// Rigid generic type parameter.
614 +
    TypeParameter(*GenericParamType),
615 +
    /// Rigid generic integer constant parameter.
616 +
    ConstParameter(*GenericParamType),
386 617
    /// Trait symbol.
387 618
    Trait(*mut TraitType),
388 619
}
389 620
390 621
/// Resolved symbol allocated during semantic analysis.
579 810
    ReceiverMutabilityMismatch,
580 811
    /// Duplicate instance declaration for the same (trait, type) pair.
581 812
    DuplicateInstance,
582 813
    /// Instance declaration is missing a required trait method.
583 814
    MissingTraitMethod(*[u8]),
815 +
    /// Subtrait instance attempts to override an inherited method.
816 +
    InheritedTraitMethod(*[u8]),
584 817
    /// Trait name used as a value expression.
585 818
    UnexpectedTraitName,
586 819
    /// Trait method receiver does not point to the declaring trait.
587 820
    TraitReceiverMismatch,
821 +
    /// A trait mentioning `Self` outside its receiver cannot form an object.
822 +
    TraitNotObjectSafe,
823 +
    /// Supertrait declarations form a cycle.
824 +
    TraitInheritanceCycle,
825 +
    /// An instance target is not a supported concrete type.
826 +
    InvalidInstanceTarget,
588 827
    /// Trait declaration and instance disagree about unsafe call requirements.
589 828
    TraitMethodSafetyMismatch,
590 829
    /// Function declaration has too many parameters.
591 830
    FnParamOverflow(CountMismatch),
592 831
    /// Function declaration has too many throws.
619 858
    BorrowConflict(*[u8]),
620 859
    /// Unsafe pointer operation outside an `unsafe` declaration.
621 860
    UnsafeOperation,
622 861
    /// Safe code cannot call an `unsafe` function.
623 862
    UnsafeCall,
863 +
    /// A syntax node is not valid in a generic context.
864 +
    GenericUnsupported,
865 +
    /// A generic bound did not name a trait.
866 +
    GenericBoundNotTrait,
867 +
    /// A constant parameter type is not a concrete integer type.
868 +
    GenericConstUnsupported,
869 +
    /// An attribute cannot be applied to a generic function.
870 +
    GenericFnAttribute,
871 +
    /// Generic function declarations must be at module scope.
872 +
    GenericFnNested,
873 +
    /// A type parameter does not affect its function.
874 +
    GenericFnUnusedParameter(*[u8]),
875 +
    /// More than one bound exposes the selected method name.
876 +
    GenericBoundAmbiguous(*[u8]),
877 +
    /// A rigid parameter was used where a concrete layout is required.
878 +
    GenericLayoutRequired,
879 +
    /// A concrete generic specialization has infinitely recursive layout.
880 +
    GenericRecursiveLayout,
881 +
    /// A function specialization targeted a non-function declaration.
882 +
    GenericFunctionExpected,
883 +
    /// A concrete type argument does not satisfy a declared trait bound.
884 +
    GenericBoundUnsatisfied(*[u8]),
885 +
    /// A generic function application has no explicit instantiation root.
886 +
    GenericFunctionInstantiationRequired,
887 +
    /// A generic call graph expands beyond the specialization bound.
888 +
    GenericSpecializationChain,
889 +
    /// Generic argument inference did not determine every parameter.
890 +
    GenericInferenceIncomplete,
891 +
    /// Generic argument inference found incompatible evidence.
892 +
    GenericInferenceConflict,
893 +
    /// A generic declaration was named without required arguments.
894 +
    GenericArgumentsRequired,
895 +
    /// A concrete application is not covered by an explicit instantiation root.
896 +
    GenericInstantiationRequired,
624 897
    /// Internal error.
625 898
    Internal,
899 +
    /// A generic application supplied the wrong number of arguments.
900 +
    GenericArgumentCount(CountMismatch),
901 +
    /// A data specialization targeted a non-data generic declaration.
902 +
    GenericDataExpected,
903 +
    /// A data specialization argument still contains a rigid parameter.
904 +
    GenericConcreteArgumentsRequired,
905 +
    /// A declaration exceeds the generic parameter limit.
906 +
    GenericParameterLimit,
907 +
    /// A package exceeds the explicit generic root limit.
908 +
    GenericRootLimit,
909 +
    /// A package exceeds the canonical specialization limit.
910 +
    GenericSpecializationLimit,
626 911
}
627 912
628 913
/// Diagnostics returned by the analyzer.
629 914
export record Diagnostics {
630 915
    errors: *mut [Error],
673 958
        /// Trait definition.
674 959
        traitInfo: *TraitType,
675 960
        /// Method index in the v-table.
676 961
        methodIndex: u32,
677 962
    },
963 +
    /// Static method call through a bounded generic parameter.
964 +
    GenericBoundMethodCall {
965 +
        param: *GenericParamType,
966 +
        traitInfo: *TraitType,
967 +
        methodIndex: u32,
968 +
        /// Whether the receiver is the first explicit call argument.
969 +
        explicitReceiver: bool,
970 +
    },
678 971
    /// Standalone method call metadata.
679 972
    MethodCall { method: *MethodEntry },
680 973
    /// Slice `.append(val, allocator)` method call.
681 974
    SliceAppend { elemType: *Type },
682 975
    /// Slice `.delete(index)` method call.
683 976
    SliceDelete { elemType: *Type },
977 +
    /// Concrete specialization selected by an explicit generic function value.
978 +
    GenericFnCall(*GenericFnSpecialization),
979 +
    /// Symbolic generic call resolved under the caller's specialization.
980 +
    GenericFnDependency(*GenericFnDependency),
684 981
}
685 982
686 983
/// Combined resolver metadata for a single AST node.
687 984
export record NodeData {
688 985
    /// Resolved type for this node.
770 1067
    effectiveTy: Type,
771 1068
    /// How bindings should be created.
772 1069
    by: MatchBy,
773 1070
}
774 1071
1072 +
/// Stack node used to stop cycles while walking ordinary nominal containers.
1073 +
record GenericRootVisit {
1074 +
    /// Nominal type visited at this stack entry.
1075 +
    nominal: *NominalType,
1076 +
    /// Previous stack entry.
1077 +
    parent: ?*GenericRootVisit,
1078 +
}
1079 +
1080 +
/// A uniquely selected method exposed by a generic parameter bound.
1081 +
record GenericBoundMethod {
1082 +
    /// Trait that exposes the selected method.
1083 +
    traitInfo: *TraitType,
1084 +
    /// Selected trait method.
1085 +
    method: *TraitMethod,
1086 +
}
1087 +
775 1088
/// How an expression uses a linear result.
776 1089
union LinearUse {
777 1090
    /// Consume the value and end its availability.
778 1091
    Consume,
779 1092
    /// Read the value without consuming it.
816 1129
    loopDepth: u32,
817 1130
}
818 1131
819 1132
/// Unwrap a pointer type for pattern matching.
820 1133
export fn unwrapMatchSubject(ty: Type) -> MatchSubject {
821 -
    if let case Type::Pointer { target, mutable, .. } = ty {
822 -
        let by = MatchBy::MutRef if mutable else MatchBy::Ref;
823 -
        return MatchSubject { effectiveTy: *target, by };
1134 +
    if let case Type::Pointer(pointer) = ty {
1135 +
        let by = MatchBy::MutRef if pointer.mutable else MatchBy::Ref;
1136 +
        return MatchSubject { effectiveTy: *pointer.target, by };
824 1137
    }
825 1138
    return MatchSubject { effectiveTy: ty, by: MatchBy::Value };
826 1139
}
827 1140
828 1141
/// Global resolver state.
835 1148
    loopStack: [LoopCtx; MAX_LOOP_DEPTH],
836 1149
    /// Current loop depth, indexes into loop stack.
837 1150
    loopDepth: u32,
838 1151
    /// Signature of the function currently being analyzed.
839 1152
    currentFn: ?*FnType,
1153 +
    /// Generic function template whose body is currently being analyzed.
1154 +
    currentGenericTemplate: ?*mut GenericTemplate,
1155 +
    /// Rigid `Self` type while resolving a trait signature.
1156 +
    currentTraitSelf: ?*GenericParamType,
840 1157
    /// Current module being analyzed.
841 1158
    currentMod: u16,
842 1159
    /// Nesting depth of unsafe modules and function bodies.
843 1160
    unsafeDepth: u32,
844 1161
    /// Configuration for semantic analysis.
861 1178
    instancesLen: u32,
862 1179
    /// Standalone method registry.
863 1180
    methods: [MethodEntry; MAX_METHODS],
864 1181
    /// Number of registered standalone methods.
865 1182
    methodsLen: u32,
1183 +
    /// Sparse metadata for generic declarations.
1184 +
    genericTemplates: ?*mut GenericTemplate,
1185 +
    /// Canonical generic function specializations.
1186 +
    genericFnSpecializations: ?*mut GenericFnSpecialization,
1187 +
    /// Symbolic and deferred generic call edges.
1188 +
    genericFnDependencies: ?*GenericFnDependency,
1189 +
    /// Concrete resolutions of symbolic generic call edges.
1190 +
    genericFnDependencyResolutions: ?*GenericFnDependencyResolution,
1191 +
    /// Package-wide canonical generic data specializations.
1192 +
    genericDataSpecializations: ?*mut GenericDataSpecialization,
1193 +
    /// Number of explicit generic roots requested by the package.
1194 +
    genericRoots: u32,
1195 +
    /// Number of canonical data and function specializations.
1196 +
    genericSpecializationCount: u32,
866 1197
}
867 1198
868 1199
/// Internal error sentinel thrown when analysis cannot proceed.
869 1200
export union ResolveError {
870 1201
    Failure,
895 1226
    set self.types = node;
896 1227
897 1228
    return &node.ty;
898 1229
}
899 1230
1231 +
/// Return whether a type contains a rigid generic parameter.
1232 +
export fn containsGenericParameter(ty: Type) -> bool {
1233 +
    match ty {
1234 +
        case Type::Pointer(pointer) =>
1235 +
            return containsGenericParameter(*pointer.target),
1236 +
        case Type::Slice(slice) =>
1237 +
            return containsGenericParameter(*slice.item),
1238 +
        case Type::Parameter(_), Type::ConstParameter(_),
1239 +
             Type::GenericConstExpr { .. } => return true,
1240 +
        case Type::Array(array) => return containsGenericParameter(*array.item),
1241 +
        case Type::GenericArray { .. } => return true,
1242 +
        case Type::Optional(inner) => return containsGenericParameter(*inner),
1243 +
        // Symbolic anonymous records require materialization even when their
1244 +
        // own fields happen not to mention a rigid parameter.
1245 +
        case Type::GenericRecord(_) => return true,
1246 +
        case Type::GenericDataApply(_) => return true,
1247 +
        case Type::Fn(info) => {
1248 +
            for param in info.paramTypes {
1249 +
                if containsGenericParameter(*param) {
1250 +
                    return true;
1251 +
                }
1252 +
            }
1253 +
            if containsGenericParameter(*info.returnType) {
1254 +
                return true;
1255 +
            }
1256 +
            for thrown in info.throwList {
1257 +
                if containsGenericParameter(*thrown) {
1258 +
                    return true;
1259 +
                }
1260 +
            }
1261 +
            return false;
1262 +
        }
1263 +
        case Type::Range { start, end } => {
1264 +
            if let ty = start {
1265 +
                if containsGenericParameter(*ty) {
1266 +
                    return true;
1267 +
                }
1268 +
            }
1269 +
            if let ty = end {
1270 +
                if containsGenericParameter(*ty) {
1271 +
                    return true;
1272 +
                }
1273 +
            }
1274 +
            return false;
1275 +
        }
1276 +
        else => return false,
1277 +
    }
1278 +
}
1279 +
1280 +
/// Return whether a by-value type reaches an in-progress nominal placeholder.
1281 +
fn hasUnresolvedNominalLayout(ty: Type) -> bool {
1282 +
    match ty {
1283 +
        case Type::Pointer(_), Type::Slice(_) => return false,
1284 +
        case Type::Array(array) => return hasUnresolvedNominalLayout(*array.item),
1285 +
        case Type::Optional(inner) => return hasUnresolvedNominalLayout(*inner),
1286 +
        case Type::Nominal(info) => {
1287 +
            if let case NominalType::Placeholder(_) = *info {
1288 +
                return true;
1289 +
            }
1290 +
            return false;
1291 +
        }
1292 +
        case Type::GenericRecord(rec) => {
1293 +
            for field in rec.fields {
1294 +
                if hasUnresolvedNominalLayout(field.fieldType) {
1295 +
                    return true;
1296 +
                }
1297 +
            }
1298 +
            return false;
1299 +
        }
1300 +
        else => return false,
1301 +
    }
1302 +
}
1303 +
1304 +
/// Materialize concrete generic data applications within a type while
1305 +
/// preserving rigid parameters and constant-dependent constructors.
1306 +
fn materializeConcreteGenericData(
1307 +
    self: *mut Resolver,
1308 +
    ty: Type,
1309 +
    site: *ast::Node,
1310 +
) -> Type throws (ResolveError) {
1311 +
    match ty {
1312 +
        case Type::Pointer(pointer) => {
1313 +
            let inner = try materializeConcreteGenericData(self, *pointer.target, site);
1314 +
            return Type::Pointer(PointerType {
1315 +
                class: pointer.class,
1316 +
                target: allocType(self, inner),
1317 +
                mutable: pointer.mutable,
1318 +
            });
1319 +
        }
1320 +
        case Type::Slice(slice) => {
1321 +
            let inner = try materializeConcreteGenericData(self, *slice.item, site);
1322 +
            return Type::Slice(SliceType {
1323 +
                class: slice.class,
1324 +
                item: allocType(self, inner),
1325 +
                mutable: slice.mutable,
1326 +
            });
1327 +
        }
1328 +
        case Type::Array(array) => {
1329 +
            let item = try materializeConcreteGenericData(self, *array.item, site);
1330 +
            return Type::Array(ArrayType {
1331 +
                item: allocType(self, item),
1332 +
                length: array.length,
1333 +
            });
1334 +
        }
1335 +
        case Type::GenericArray { item, length } => {
1336 +
            let inner = try materializeConcreteGenericData(self, *item, site);
1337 +
            return Type::GenericArray { item: allocType(self, inner), length };
1338 +
        }
1339 +
        case Type::Optional(inner) => {
1340 +
            let value = try materializeConcreteGenericData(self, *inner, site);
1341 +
            return Type::Optional(allocType(self, value));
1342 +
        }
1343 +
        case Type::GenericDataApply(app) => {
1344 +
            let a = alloc::arenaAllocator(&mut self.arena);
1345 +
            let mut args: *mut [*Type] = &mut [];
1346 +
            let mut concrete = true;
1347 +
            for arg in app.args {
1348 +
                let value = try materializeConcreteGenericData(self, *arg, site);
1349 +
                set concrete = concrete and not containsGenericParameter(value);
1350 +
                args.append(allocType(self, value), a);
1351 +
            }
1352 +
            if concrete {
1353 +
                let nominal = try specializeGenericData(
1354 +
                    self, app.site, app.template, &args[..], false
1355 +
                );
1356 +
                return Type::Nominal(nominal);
1357 +
            }
1358 +
            let application = try! alloc::alloc(
1359 +
                &mut self.arena,
1360 +
                @sizeOf(GenericDataApplyType),
1361 +
                @alignOf(GenericDataApplyType),
1362 +
            ) as *mut GenericDataApplyType;
1363 +
            set *application = GenericDataApplyType {
1364 +
                template: app.template,
1365 +
                args: &args[..],
1366 +
                site: app.site,
1367 +
            };
1368 +
            return Type::GenericDataApply(application);
1369 +
        }
1370 +
        case Type::Fn(info) => {
1371 +
            let a = alloc::arenaAllocator(&mut self.arena);
1372 +
            let mut params: *mut [*Type] = &mut [];
1373 +
            let mut throwTypes: *mut [*Type] = &mut [];
1374 +
            for param in info.paramTypes {
1375 +
                let value = try materializeConcreteGenericData(self, *param, site);
1376 +
                params.append(allocType(self, value), a);
1377 +
            }
1378 +
            for thrown in info.throwList {
1379 +
                let value = try materializeConcreteGenericData(self, *thrown, site);
1380 +
                throwTypes.append(allocType(self, value), a);
1381 +
            }
1382 +
            let result = try materializeConcreteGenericData(
1383 +
                self, *info.returnType, site
1384 +
            );
1385 +
            return Type::Fn(allocFnType(self, FnType {
1386 +
                paramTypes: &params[..],
1387 +
                returnType: allocType(self, result),
1388 +
                throwList: &throwTypes[..],
1389 +
                isUnsafe: info.isUnsafe,
1390 +
                localCount: info.localCount,
1391 +
            }));
1392 +
        }
1393 +
        case Type::GenericRecord(rec) => {
1394 +
            let a = alloc::arenaAllocator(&mut self.arena);
1395 +
            let mut fields: *mut [RecordField] = &mut [];
1396 +
            let mut symbolic = false;
1397 +
            for field in rec.fields {
1398 +
                let fieldType = try materializeConcreteGenericData(
1399 +
                    self, field.fieldType, site
1400 +
                );
1401 +
                set symbolic = symbolic or containsGenericParameter(fieldType);
1402 +
                fields.append(RecordField {
1403 +
                    name: field.name,
1404 +
                    fieldType,
1405 +
                    offset: field.offset,
1406 +
                }, a);
1407 +
            }
1408 +
            let updatedRec = try! alloc::alloc(
1409 +
                &mut self.arena,
1410 +
                @sizeOf(GenericRecordType),
1411 +
                @alignOf(GenericRecordType),
1412 +
            ) as *mut GenericRecordType;
1413 +
            set *updatedRec = GenericRecordType {
1414 +
                fields: &fields[..],
1415 +
                labeled: rec.labeled,
1416 +
            };
1417 +
            let updated = Type::GenericRecord(updatedRec);
1418 +
            if symbolic {
1419 +
                return updated;
1420 +
            }
1421 +
            let empty = Substitution { params: &[], args: &[] };
1422 +
            return try substituteType(self, updated, &empty, site);
1423 +
        }
1424 +
        else => return ty,
1425 +
    }
1426 +
}
1427 +
1428 +
/// Look up the concrete replacement for a rigid parameter.
1429 +
export fn substitutionArg(sub: *Substitution, param: *GenericParamType) -> Type {
1430 +
    assert sub.params.len == sub.args.len, "substitution length mismatch";
1431 +
    for candidate, i in sub.params {
1432 +
        if candidate == param {
1433 +
            return *sub.args[i];
1434 +
        }
1435 +
    }
1436 +
    if param.constType <> nil {
1437 +
        return Type::ConstParameter(param);
1438 +
    }
1439 +
    return Type::Parameter(param);
1440 +
}
1441 +
1442 +
/// Recursively replace rigid parameters in a resolved type.
1443 +
export fn substituteType(
1444 +
    self: *mut Resolver,
1445 +
    ty: Type,
1446 +
    sub: *Substitution,
1447 +
    site: *ast::Node,
1448 +
) -> Type throws (ResolveError) {
1449 +
    if not containsGenericParameter(ty) {
1450 +
        return ty;
1451 +
    }
1452 +
    match ty {
1453 +
        case Type::Parameter(param) => return substitutionArg(sub, param),
1454 +
        case Type::ConstParameter(param) => return substitutionArg(sub, param),
1455 +
        case Type::GenericConstExpr { type, expr } => {
1456 +
            let value = constValueWithSubstitution(self, expr, sub)
1457 +
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
1458 +
            let case ConstValue::Int(int) = value
1459 +
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
1460 +
            if not validateConstIntRange(value, *type) {
1461 +
                throw emitError(self, expr, ErrorKind::NumericLiteralOverflow);
1462 +
            }
1463 +
            let case ConstValue::Int(canonical) = castConstInt(int, *type)
1464 +
                else throw emitError(self, expr, ErrorKind::Internal);
1465 +
            return Type::ConstArgument { type, value: canonical };
1466 +
        }
1467 +
        case Type::Pointer(pointer) => {
1468 +
            let inner = try substituteType(self, *pointer.target, sub, site);
1469 +
            return Type::Pointer(PointerType {
1470 +
                class: pointer.class,
1471 +
                target: allocType(self, inner),
1472 +
                mutable: pointer.mutable,
1473 +
            });
1474 +
        }
1475 +
        case Type::Slice(slice) => {
1476 +
            let inner = try substituteType(self, *slice.item, sub, site);
1477 +
            return Type::Slice(SliceType {
1478 +
                class: slice.class,
1479 +
                item: allocType(self, inner),
1480 +
                mutable: slice.mutable,
1481 +
            });
1482 +
        }
1483 +
        case Type::Array(array) => {
1484 +
            let item = try substituteType(self, *array.item, sub, site);
1485 +
            return Type::Array(ArrayType {
1486 +
                item: allocType(self, item),
1487 +
                length: array.length,
1488 +
            });
1489 +
        }
1490 +
        case Type::GenericArray { item, length } => {
1491 +
            let concreteItem = try substituteType(self, *item, sub, site);
1492 +
            let value = constValueWithSubstitution(self, length, sub)
1493 +
                else throw emitError(self, length, ErrorKind::ConstExprRequired);
1494 +
            if not validateConstIntRange(value, Type::U32) {
1495 +
                throw emitError(self, length, ErrorKind::NumericLiteralOverflow);
1496 +
            }
1497 +
            let case ConstValue::Int(int) = value
1498 +
                else throw emitError(self, length, ErrorKind::ConstExprRequired);
1499 +
            return Type::Array(ArrayType {
1500 +
                item: allocType(self, concreteItem),
1501 +
                length: int.magnitude as u32,
1502 +
            });
1503 +
        }
1504 +
        case Type::Optional(inner) => {
1505 +
            let value = try substituteType(self, *inner, sub, site);
1506 +
            return Type::Optional(allocType(self, value));
1507 +
        }
1508 +
        case Type::GenericDataApply(app) => {
1509 +
            let a = alloc::arenaAllocator(&mut self.arena);
1510 +
            let mut args: *mut [*Type] = &mut [];
1511 +
            let mut symbolic = false;
1512 +
            for arg in app.args {
1513 +
                let replacement = try substituteType(self, *arg, sub, site);
1514 +
                set symbolic = symbolic or containsGenericParameter(replacement);
1515 +
                args.append(allocType(self, replacement), a);
1516 +
            }
1517 +
            if symbolic {
1518 +
                let application = try! alloc::alloc(
1519 +
                    &mut self.arena,
1520 +
                    @sizeOf(GenericDataApplyType),
1521 +
                    @alignOf(GenericDataApplyType),
1522 +
                ) as *mut GenericDataApplyType;
1523 +
                set *application = GenericDataApplyType {
1524 +
                    template: app.template,
1525 +
                    args: &args[..],
1526 +
                    site: app.site,
1527 +
                };
1528 +
                return Type::GenericDataApply(application);
1529 +
            }
1530 +
            let nominal = try specializeGenericData(
1531 +
                self, app.site, app.template, &args[..], false
1532 +
            );
1533 +
            return Type::Nominal(nominal);
1534 +
        }
1535 +
        case Type::GenericRecord(rec) => {
1536 +
            let a = alloc::arenaAllocator(&mut self.arena);
1537 +
            let mut fields: *mut [RecordField] = &mut [];
1538 +
            let mut offset: u32 = 0;
1539 +
            let mut alignment: u32 = 1;
1540 +
            for field in rec.fields {
1541 +
                let fieldType = try substituteType(self, field.fieldType, sub, site);
1542 +
                if hasUnresolvedNominalLayout(fieldType) {
1543 +
                    throw emitError(self, site, ErrorKind::GenericRecursiveLayout);
1544 +
                }
1545 +
                try ensureStorableType(self, site, fieldType);
1546 +
                try ensureTypeResolved(self, fieldType, site);
1547 +
                let fieldLayout = getTypeLayout(fieldType);
1548 +
                set offset = mem::alignUp(offset, fieldLayout.alignment);
1549 +
                fields.append(RecordField {
1550 +
                    name: field.name,
1551 +
                    fieldType,
1552 +
                    offset: offset as i32,
1553 +
                }, a);
1554 +
                set offset += fieldLayout.size;
1555 +
                set alignment = max(alignment, fieldLayout.alignment);
1556 +
            }
1557 +
            let layout = Layout {
1558 +
                size: mem::alignUp(offset, alignment),
1559 +
                alignment,
1560 +
            };
1561 +
            return Type::Nominal(allocNominalType(self, NominalType::Record(RecordType {
1562 +
                fields: &fields[..],
1563 +
                labeled: rec.labeled,
1564 +
                layout,
1565 +
                declaredLinear: false,
1566 +
            })));
1567 +
        }
1568 +
        case Type::Fn(info) => {
1569 +
            let a = alloc::arenaAllocator(&mut self.arena);
1570 +
            let mut params: *mut [*Type] = &mut [];
1571 +
            let mut throwTypes: *mut [*Type] = &mut [];
1572 +
            for param in info.paramTypes {
1573 +
                let concrete = try substituteType(self, *param, sub, site);
1574 +
                params.append(allocType(self, concrete), a);
1575 +
            }
1576 +
            for thrown in info.throwList {
1577 +
                let concrete = try substituteType(self, *thrown, sub, site);
1578 +
                throwTypes.append(allocType(self, concrete), a);
1579 +
            }
1580 +
            let result = try substituteType(self, *info.returnType, sub, site);
1581 +
            return Type::Fn(allocFnType(self, FnType {
1582 +
                paramTypes: &params[..],
1583 +
                returnType: allocType(self, result),
1584 +
                throwList: &throwTypes[..],
1585 +
                isUnsafe: info.isUnsafe,
1586 +
                localCount: info.localCount,
1587 +
            }));
1588 +
        }
1589 +
        case Type::Range { start, end } => {
1590 +
            let mut newStart: ?*Type = nil;
1591 +
            let mut newEnd: ?*Type = nil;
1592 +
            if let value = start {
1593 +
                let concrete = try substituteType(self, *value, sub, site);
1594 +
                set newStart = allocType(self, concrete);
1595 +
            }
1596 +
            if let value = end {
1597 +
                let concrete = try substituteType(self, *value, sub, site);
1598 +
                set newEnd = allocType(self, concrete);
1599 +
            }
1600 +
            return Type::Range { start: newStart, end: newEnd };
1601 +
        }
1602 +
        else => return ty,
1603 +
    }
1604 +
}
1605 +
900 1606
/// Allocate a nominal type descriptor and return a pointer to it.
901 1607
fn allocNominalType(self: *mut Resolver, info: NominalType) -> *mut NominalType {
902 1608
    // Nb. We don't attempt to de-duplicate nominal type entries,
903 1609
    // since they don't carry node information and we create
904 1610
    // placeholder entries when binding symbols.
995 1701
        scope: storage.pkgScope,
996 1702
        pkgScope: storage.pkgScope,
997 1703
        loopStack: undefined,
998 1704
        loopDepth: 0,
999 1705
        currentFn: nil,
1706 +
        currentGenericTemplate: nil,
1707 +
        currentTraitSelf: nil,
1000 1708
        currentMod: 0,
1001 1709
        unsafeDepth: 0,
1002 1710
        config,
1003 1711
        arena,
1004 1712
        nodeData: NodeDataTable { entries: storage.nodeData },
1009 1717
        moduleScopes,
1010 1718
        instances: undefined,
1011 1719
        instancesLen: 0,
1012 1720
        methods: undefined,
1013 1721
        methodsLen: 0,
1722 +
        genericTemplates: nil,
1723 +
        genericFnSpecializations: nil,
1724 +
        genericFnDependencies: nil,
1725 +
        genericFnDependencyResolutions: nil,
1726 +
        genericDataSpecializations: nil,
1727 +
        genericRoots: 0,
1728 +
        genericSpecializationCount: 0,
1014 1729
    };
1015 1730
}
1016 1731
1017 1732
/// Return `true` if there are no errors in the diagnostics.
1018 1733
export fn success(diag: *Diagnostics) -> bool {
1191 1906
    let case ast::NodeValue::Ident(name) = node.value
1192 1907
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
1193 1908
    return name;
1194 1909
}
1195 1910
1911 +
/// Record a symbolic type that lowering will consume from a generic body.
1912 +
fn recordGenericTypeUse(self: *mut Resolver, site: *ast::Node, ty: Type) {
1913 +
    if not containsGenericParameter(ty) {
1914 +
        return;
1915 +
    }
1916 +
    let current = self.currentGenericTemplate else return;
1917 +
    current.typeUses.append(
1918 +
        GenericTypeUse { site, ty },
1919 +
        alloc::arenaAllocator(&mut self.arena),
1920 +
    );
1921 +
}
1922 +
1196 1923
/// Associate a resolved symbol with an AST node.
1197 1924
fn setNodeSymbol(self: *mut Resolver, node: *ast::Node, symbol: *mut Symbol) {
1198 1925
    if let existingSym = self.nodeData.entries[node.id].sym {
1199 1926
        panic "setNodeSymbol: a symbol is already associated with this node";
1200 1927
    }
1205 1932
fn setNodeType(self: *mut Resolver, node: *ast::Node, ty: Type) -> Type {
1206 1933
    if ty == Type::Unknown {
1207 1934
        // In this case, we simply don't associate a type.
1208 1935
        return ty;
1209 1936
    }
1937 +
    recordGenericTypeUse(self, node, ty);
1210 1938
    set self.nodeData.entries[node.id].ty = ty;
1211 1939
1212 1940
    return ty;
1213 1941
}
1214 1942
1227 1955
/// Associate a coercion plan with an AST node.
1228 1956
fn setNodeCoercion(self: *mut Resolver, node: *ast::Node, coercion: Coercion) -> Coercion {
1229 1957
    if coercion == Coercion::Identity {
1230 1958
        return coercion;
1231 1959
    }
1960 +
    match coercion {
1961 +
        case Coercion::NumericCast { from, to } => {
1962 +
            recordGenericTypeUse(self, node, from);
1963 +
            recordGenericTypeUse(self, node, to);
1964 +
        }
1965 +
        case Coercion::OptionalLift(ty) =>
1966 +
            recordGenericTypeUse(self, node, ty),
1967 +
        else => {}
1968 +
    }
1232 1969
    set self.nodeData.entries[node.id].coercion = coercion;
1233 1970
1234 1971
    return coercion;
1235 1972
}
1236 1973
1244 1981
    set self.nodeData.entries[node.id].extra = NodeExtra::RecordField { index };
1245 1982
}
1246 1983
1247 1984
/// Associate slice range metadata with a subscript expression.
1248 1985
fn setSliceRangeInfo(self: *mut Resolver, node: *ast::Node, info: SliceRangeInfo) {
1986 +
    recordGenericTypeUse(self, node, *info.itemType);
1249 1987
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info);
1250 1988
}
1251 1989
1252 1990
/// Associate union variant metadata with a pattern or constructor node.
1253 1991
fn setVariantInfo(self: *mut Resolver, node: *ast::Node, ordinal: u32, tag: u32) {
1257 1995
/// Associate trait method call metadata with a call node.
1258 1996
fn setTraitMethodCall(self: *mut Resolver, node: *ast::Node, traitInfo: *TraitType, methodIndex: u32) {
1259 1997
    set self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex };
1260 1998
}
1261 1999
2000 +
/// Associate static generic-bound dispatch metadata with a call node.
2001 +
fn setGenericBoundMethodCall(
2002 +
    self: *mut Resolver,
2003 +
    node: *ast::Node,
2004 +
    param: *GenericParamType,
2005 +
    traitInfo: *TraitType,
2006 +
    methodIndex: u32,
2007 +
    explicitReceiver: bool,
2008 +
) {
2009 +
    set self.nodeData.entries[node.id].extra = NodeExtra::GenericBoundMethodCall {
2010 +
        param, traitInfo, methodIndex, explicitReceiver,
2011 +
    };
2012 +
}
2013 +
1262 2014
/// Associate for-loop metadata with a for-loop node.
1263 2015
fn setForLoopInfo(self: *mut Resolver, node: *ast::Node, info: ForLoopInfo) {
1264 2016
    set self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info);
2017 +
    match info {
2018 +
        case ForLoopInfo::Range { valType, .. } =>
2019 +
            recordGenericTypeUse(self, node, *valType),
2020 +
        case ForLoopInfo::Collection { elemType, .. } =>
2021 +
            recordGenericTypeUse(self, node, *elemType),
2022 +
    }
1265 2023
}
1266 2024
1267 2025
/// Retrieve the constant value associated with a node, if any.
1268 2026
export fn constValueEntry(self: *Resolver, node: *ast::Node) -> ?ConstValue {
1269 2027
    return self.nodeData.entries[node.id].constValue;
1439 2197
}
1440 2198
1441 2199
/// Get the layout of a type.
1442 2200
export fn getTypeLayout(ty: Type) -> Layout {
1443 2201
    match ty {
1444 -
        case Type::Pointer { .. } => return Layout { size: PTR_SIZE, alignment: PTR_SIZE },
1445 -
        case Type::Slice { .. }, Type::TraitObject { .. } =>
2202 +
        case Type::Pointer(_) => return Layout { size: PTR_SIZE, alignment: PTR_SIZE },
2203 +
        case Type::Slice(_), Type::TraitObject(_) =>
1446 2204
            return Layout { size: PTR_SIZE * 2, alignment: PTR_SIZE },
1447 2205
        case Type::Void, Type::Never => return Layout { size: 0, alignment: 0 },
1448 2206
        case Type::Bool, Type::U8, Type::I8 => return Layout { size: 1, alignment: 1 },
1449 2207
        case Type::U16, Type::I16 => return Layout { size: 2, alignment: 2 },
1450 2208
        case Type::U32, Type::I32 => return Layout { size: 4, alignment: 4 },
1534 2292
1535 2293
/// Check if a type can use null to represent `nil`.
1536 2294
/// Pointers and slices have a data pointer that is never null when valid.
1537 2295
export fn isNullableType(ty: Type) -> bool {
1538 2296
    match ty {
1539 -
        case Type::Pointer { .. }, Type::Slice { .. } => return true,
2297 +
        case Type::Pointer(_), Type::Slice(_) => return true,
1540 2298
        else => return false,
1541 2299
    }
1542 2300
}
1543 2301
1544 2302
/// Get the layout of a nominal type.
1596 2354
    };
1597 2355
    return UnionLayoutInfo { layout: unionLayout, valOffset: unionValOffset, isAllVoid };
1598 2356
}
1599 2357
1600 2358
/// Compute the discriminant tag for a variant, advancing the iota counter.
1601 -
/// If the variant has an explicit `= N` value, uses that; otherwise uses iota.
1602 -
fn variantTag(variantDecl: ast::UnionDeclVariant, iota: *mut u32) -> u32 {
2359 +
fn variantTag(
2360 +
    self: *mut Resolver,
2361 +
    variantDecl: ast::UnionDeclVariant,
2362 +
    iota: *mut u32,
2363 +
    sub: ?*Substitution,
2364 +
) -> u32 throws (ResolveError) {
1603 2365
    let mut tag: u32 = *iota;
1604 2366
    if let valueNode = variantDecl.value {
1605 -
        let case ast::NodeValue::Number(lit) = valueNode.value
1606 -
            else panic "variantTag: expected number literal";
1607 -
        set tag = lit.magnitude as u32;
2367 +
        let mut value: ?ConstValue = nil;
2368 +
        if let substitution = sub {
2369 +
            set value = constValueWithSubstitution(self, valueNode, substitution);
2370 +
        } else {
2371 +
            set value = constValueEntry(self, valueNode);
2372 +
        }
2373 +
        let resolved = value
2374 +
            else throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
2375 +
        if not validateConstIntRange(resolved, Type::U32) {
2376 +
            throw emitError(self, valueNode, ErrorKind::NumericLiteralOverflow);
2377 +
        }
2378 +
        let case ConstValue::Int(int) = resolved
2379 +
            else throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
2380 +
        set tag = int.magnitude as u32;
1608 2381
    }
1609 2382
    set *iota = tag + 1;
1610 2383
    return tag;
1611 2384
}
1612 2385
1617 2390
    return unionType.isAllVoid;
1618 2391
}
1619 2392
1620 2393
/// Check if a type should be treated as an address-like value.
1621 2394
fn isAddressType(ty: Type) -> bool {
1622 -
    if isNullableType(ty) {
1623 -
        return true;
1624 -
    }
1625 2395
    match ty {
1626 -
        case Type::Fn(_) => return true,
2396 +
        case Type::Pointer(_), Type::Slice(_), Type::Fn(_) => return true,
1627 2397
        else => return false,
1628 2398
    }
1629 2399
}
1630 2400
1631 2401
/// Return the representable range for an integer type.
1694 2464
1695 2465
/// Ensure all nested nominal types in a type are resolved.
1696 2466
fn ensureTypeResolved(self: *mut Resolver, ty: Type, site: *ast::Node) throws (ResolveError) {
1697 2467
    match ty {
1698 2468
        case Type::Nominal(info) => try ensureNominalResolved(self, info, site),
1699 -
        case Type::Slice { item, .. } => try ensureTypeResolved(self, *item, site),
1700 -
        case Type::Pointer { .. } => {}, // Pointers have fixed layout, don't recurse.
2469 +
        case Type::Slice(slice) => try ensureTypeResolved(self, *slice.item, site),
2470 +
        case Type::Pointer(_) => {}, // Pointers have fixed layout, don't recurse.
1701 2471
        case Type::Array(arr) => try ensureTypeResolved(self, *arr.item, site),
1702 2472
        case Type::Optional(inner) => try ensureTypeResolved(self, *inner, site),
1703 2473
        else => {},
1704 2474
    }
1705 2475
}
1778 2548
    // The "never" type can always be assigned, since the code path is never
1779 2549
    // executed.
1780 2550
    if from == Type::Never {
1781 2551
        return Coercion::Identity;
1782 2552
    }
1783 -
    if to == from {
2553 +
    if typesEqual(to, from) {
1784 2554
        return Coercion::Identity;
1785 2555
    }
1786 -
    if let case Type::Pointer { class: lhsClass, target: lhsTarget, mutable: lhsMutable } = to {
1787 -
        let case Type::Pointer { class: rhsClass, target: rhsTarget, mutable: rhsMutable } = from
1788 -
            else return nil;
1789 -
        if not pointerClassesAssignable(lhsClass, rhsClass) {
2556 +
    if let case Type::Pointer(lhs) = to {
2557 +
        let case Type::Pointer(rhs) = from else return nil;
2558 +
        if not pointerClassesAssignable(lhs.class, rhs.class) {
1790 2559
            return nil;
1791 2560
        }
1792 2561
        // Allow coercion from `*T` to `*opaque`, and mutable counterparts.
1793 -
        if *lhsTarget == Type::Opaque {
1794 -
            if lhsMutable and not rhsMutable {
2562 +
        if *lhs.target == Type::Opaque {
2563 +
            if lhs.mutable and not rhs.mutable {
1795 2564
                return nil;
1796 2565
            }
1797 2566
            return Coercion::Identity;
1798 2567
        }
1799 -
        if lhsMutable and not rhsMutable {
2568 +
        if lhs.mutable and not rhs.mutable {
1800 2569
            return nil;
1801 2570
        }
1802 -
        return isAssignable(self, *lhsTarget, *rhsTarget, rval);
2571 +
        return isAssignable(self, *lhs.target, *rhs.target, rval);
1803 2572
    }
1804 -
    if let case Type::TraitObject { class: lhsClass, traitInfo: lhsTraitInfo, mutable: lhsMutable } = to {
1805 -
        if let case Type::Pointer { class: rhsClass, target: rhsTarget, mutable: rhsMutable } = from {
1806 -
            if not pointerClassesAssignable(lhsClass, rhsClass)
1807 -
                or (lhsMutable and not rhsMutable)
2573 +
    if let case Type::TraitObject(lhs) = to {
2574 +
        if let case Type::Pointer(rhs) = from {
2575 +
            if not pointerClassesAssignable(lhs.class, rhs.class)
2576 +
                or (lhs.mutable and not rhs.mutable)
1808 2577
            {
1809 2578
                return nil;
1810 2579
            }
1811 -
            if let inst = findInstance(self, lhsTraitInfo, *rhsTarget) {
1812 -
                return Coercion::TraitObject { traitInfo: lhsTraitInfo, inst };
2580 +
            if let inst = findInstance(self, lhs.traitInfo, *rhs.target) {
2581 +
                return Coercion::TraitObject { traitInfo: lhs.traitInfo, inst };
1813 2582
            }
1814 2583
        }
1815 -
        if let case Type::TraitObject { class: rhsClass, traitInfo: rhsTraitInfo, mutable: rhsMutable } = from {
1816 -
            if not pointerClassesAssignable(lhsClass, rhsClass)
1817 -
                or lhsTraitInfo <> rhsTraitInfo
2584 +
        if let case Type::TraitObject(rhs) = from {
2585 +
            if not pointerClassesAssignable(lhs.class, rhs.class)
2586 +
                or lhs.traitInfo <> rhs.traitInfo
1818 2587
            {
1819 2588
                return nil;
1820 2589
            }
1821 -
            if lhsMutable and not rhsMutable {
2590 +
            if lhs.mutable and not rhs.mutable {
1822 2591
                return nil;
1823 2592
            }
1824 2593
            return Coercion::Identity;
1825 2594
        }
1826 2595
        return nil;
1827 2596
    }
1828 -
    if let case Type::Slice { class: lhsClass, item: lhsItem, mutable: lhsMutable } = to {
1829 -
        let case Type::Slice { class: rhsClass, item: rhsItem, mutable: rhsMutable } = from
1830 -
            else return nil;
1831 -
        if not pointerClassesAssignable(lhsClass, rhsClass)
1832 -
            or (lhsMutable and not rhsMutable)
2597 +
    if let case Type::Slice(lhs) = to {
2598 +
        let case Type::Slice(rhs) = from else return nil;
2599 +
        if not pointerClassesAssignable(lhs.class, rhs.class)
2600 +
            or (lhs.mutable and not rhs.mutable)
1833 2601
        {
1834 2602
            return nil;
1835 2603
        }
1836 2604
        // Allow coercion from `*[T]` to `*[opaque]`, and mutable counterparts.
1837 -
        if *lhsItem == Type::Opaque {
2605 +
        if *lhs.item == Type::Opaque {
1838 2606
            return Coercion::Identity;
1839 2607
        }
1840 -
        return isAssignable(self, *lhsItem, *rhsItem, rval);
2608 +
        return isAssignable(self, *lhs.item, *rhs.item, rval);
1841 2609
    }
1842 2610
    match to {
1843 2611
        case Type::Array(lhs) => {
1844 2612
            let case Type::Array(rhs) = from
1845 2613
                else return nil;
1959 2727
/// Check if two types are structurally equal.
1960 2728
export fn typesEqual(a: Type, b: Type) -> bool {
1961 2729
    if a == b {
1962 2730
        return true;
1963 2731
    }
1964 -
    if let case Type::Pointer { class: aClass, target: aTarget, mutable: aMutable } = a {
1965 -
        let case Type::Pointer { class: bClass, target: bTarget, mutable: bMutable } = b
1966 -
            else return false;
1967 -
        return aClass == bClass and aMutable == bMutable
1968 -
            and typesEqual(*aTarget, *bTarget);
2732 +
    if let case Type::Pointer(av) = a {
2733 +
        let case Type::Pointer(bv) = b else return false;
2734 +
        return av.class == bv.class and av.mutable == bv.mutable
2735 +
            and typesEqual(*av.target, *bv.target);
1969 2736
    }
1970 -
    if let case Type::Slice { class: aClass, item: aItem, mutable: aMutable } = a {
1971 -
        let case Type::Slice { class: bClass, item: bItem, mutable: bMutable } = b
1972 -
            else return false;
1973 -
        return aClass == bClass and aMutable == bMutable
1974 -
            and typesEqual(*aItem, *bItem);
2737 +
    if let case Type::Slice(av) = a {
2738 +
        let case Type::Slice(bv) = b else return false;
2739 +
        return av.class == bv.class and av.mutable == bv.mutable
2740 +
            and typesEqual(*av.item, *bv.item);
1975 2741
    }
1976 -
    if let case Type::TraitObject { class: aClass, traitInfo: aTraitInfo, mutable: aMutable } = a {
1977 -
        let case Type::TraitObject { class: bClass, traitInfo: bTraitInfo, mutable: bMutable } = b
1978 -
            else return false;
1979 -
        return aClass == bClass and aMutable == bMutable
1980 -
            and aTraitInfo == bTraitInfo;
2742 +
    if let case Type::TraitObject(av) = a {
2743 +
        let case Type::TraitObject(bv) = b else return false;
2744 +
        return av.class == bv.class and av.mutable == bv.mutable
2745 +
            and av.traitInfo == bv.traitInfo;
1981 2746
    }
1982 2747
    match a {
2748 +
        case Type::Range { start: aStart, end: aEnd } => {
2749 +
            let case Type::Range { start: bStart, end: bEnd } = b
2750 +
                else return false;
2751 +
            if let aValue = aStart {
2752 +
                let bValue = bStart else return false;
2753 +
                if not typesEqual(*aValue, *bValue) {
2754 +
                    return false;
2755 +
                }
2756 +
            } else if bStart <> nil {
2757 +
                return false;
2758 +
            }
2759 +
            if let aValue = aEnd {
2760 +
                let bValue = bEnd else return false;
2761 +
                return typesEqual(*aValue, *bValue);
2762 +
            }
2763 +
            return bEnd == nil;
2764 +
        }
1983 2765
        case Type::Array(aa) => {
1984 2766
            let case Type::Array(ab) = b else return false;
1985 2767
            return aa.length == ab.length and typesEqual(*aa.item, *ab.item);
1986 2768
        }
1987 2769
        case Type::Optional(oa) => {
1990 2772
        }
1991 2773
        case Type::Fn(fa) => {
1992 2774
            let case Type::Fn(fb) = b else return false;
1993 2775
            return fnTypeEqual(fa, fb);
1994 2776
        }
2777 +
        case Type::GenericDataApply(aa) => {
2778 +
            let case Type::GenericDataApply(ab) = b else return false;
2779 +
            if aa.template <> ab.template or aa.args.len <> ab.args.len {
2780 +
                return false;
2781 +
            }
2782 +
            for i in 0..aa.args.len {
2783 +
                if not typesEqual(*aa.args[i], *ab.args[i]) {
2784 +
                    return false;
2785 +
                }
2786 +
            }
2787 +
            return true;
2788 +
        }
1995 2789
        else => return false,
1996 2790
    }
1997 2791
}
1998 2792
1999 2793
/// Return whether `ty` is a direct reference.
2000 2794
export fn isRefType(ty: Type) -> bool {
2001 2795
    match ty {
2002 -
        case Type::Pointer { class: types::PointerClass::Ref, .. },
2003 -
             Type::Slice { class: types::PointerClass::Ref, .. },
2004 -
             Type::TraitObject { class: types::PointerClass::Ref, .. } => return true,
2796 +
        case Type::Pointer(PointerType { class: types::PointerClass::Ref, .. }),
2797 +
             Type::Slice(SliceType { class: types::PointerClass::Ref, .. }),
2798 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Ref, .. }) => return true,
2005 2799
        else => return false,
2006 2800
    }
2007 2801
}
2008 2802
2009 2803
/// Return whether a type contains a reference.
2010 2804
fn containsRef(ty: Type) -> bool {
2011 2805
    if isRefType(ty) {
2012 2806
        return true;
2013 2807
    }
2014 -
    if let case Type::Pointer { target, .. } = ty {
2015 -
        return containsRef(*target);
2808 +
    if let case Type::Pointer(pointer) = ty {
2809 +
        return containsRef(*pointer.target);
2016 2810
    }
2017 -
    if let case Type::Slice { item, .. } = ty {
2018 -
        return containsRef(*item);
2811 +
    if let case Type::Slice(slice) = ty {
2812 +
        return containsRef(*slice.item);
2019 2813
    }
2020 2814
    match ty {
2021 2815
        case Type::Array(array) => return containsRef(*array.item),
2022 2816
        case Type::Optional(inner) => return containsRef(*inner),
2817 +
        case Type::GenericRecord(rec) => {
2818 +
            for field in rec.fields {
2819 +
                if containsRef(field.fieldType) {
2820 +
                    return true;
2821 +
                }
2822 +
            }
2823 +
            return false;
2824 +
        }
2023 2825
        // Nominal declarations validate their own fields and variants.
2024 2826
        // Treating them as leaves also terminates recursive pointer types.
2025 2827
        case Type::Nominal(_) => return false,
2026 2828
        else => return false,
2027 2829
    }
2028 2830
}
2029 2831
2030 2832
/// Return whether a type is exact-linear.
2031 2833
export fn isLinear(ty: Type) -> bool {
2032 2834
    match ty {
2033 -
        case Type::Pointer { class: types::PointerClass::Owned, .. },
2034 -
             Type::Slice { class: types::PointerClass::Owned, .. },
2035 -
             Type::TraitObject { class: types::PointerClass::Owned, .. } => return true,
2036 -
        case Type::Pointer { class: types::PointerClass::Ref, .. },
2037 -
             Type::Pointer { class: types::PointerClass::Unsafe, .. },
2038 -
             Type::Slice { class: types::PointerClass::Ref, .. },
2039 -
             Type::Slice { class: types::PointerClass::Unsafe, .. },
2040 -
             Type::TraitObject { class: types::PointerClass::Ref, .. },
2041 -
             Type::TraitObject { class: types::PointerClass::Unsafe, .. } => return false,
2835 +
        case Type::Pointer(PointerType { class: types::PointerClass::Owned, .. }),
2836 +
             Type::Slice(SliceType { class: types::PointerClass::Owned, .. }),
2837 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Owned, .. }) => return true,
2838 +
        case Type::Pointer(PointerType { class: types::PointerClass::Ref, .. }),
2839 +
             Type::Pointer(PointerType { class: types::PointerClass::Unsafe, .. }),
2840 +
             Type::Slice(SliceType { class: types::PointerClass::Ref, .. }),
2841 +
             Type::Slice(SliceType { class: types::PointerClass::Unsafe, .. }),
2842 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Ref, .. }),
2843 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Unsafe, .. }) => return false,
2042 2844
2043 2845
        case Type::Array(array) => return isLinear(*array.item),
2044 2846
        case Type::Optional(inner) => return isLinear(*inner),
2045 2847
        case Type::Nominal(NominalType::Record(recInfo)) => {
2046 2848
            if recInfo.declaredLinear {
2069 2871
}
2070 2872
2071 2873
/// Return whether `ty` is a direct unsafe pointer-like value.
2072 2874
fn isUnsafePointerType(ty: Type) -> bool {
2073 2875
    match ty {
2074 -
        case Type::Pointer { class: types::PointerClass::Unsafe, .. },
2075 -
             Type::Slice { class: types::PointerClass::Unsafe, .. },
2076 -
             Type::TraitObject { class: types::PointerClass::Unsafe, .. } => return true,
2876 +
        case Type::Pointer(PointerType { class: types::PointerClass::Unsafe, .. }),
2877 +
             Type::Slice(SliceType { class: types::PointerClass::Unsafe, .. }),
2878 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Unsafe, .. }) => return true,
2077 2879
        else => return false,
2078 2880
    }
2079 2881
}
2080 2882
2081 2883
/// Get the record info from a record type.
2084 2886
    return recInfo;
2085 2887
}
2086 2888
2087 2889
/// Auto-dereference a type: if it's a pointer, return the target type.
2088 2890
export fn autoDeref(ty: Type) -> Type {
2089 -
    if let case Type::Pointer { target, .. } = ty {
2090 -
        return *target;
2891 +
    if let case Type::Pointer(view) = ty {
2892 +
        return *view.target;
2091 2893
    }
2092 2894
    return ty;
2093 2895
}
2094 2896
2095 2897
/// Get field info for a record-like type (records, slices) by field index.
2096 2898
export fn getRecordField(ty: Type, index: u32) -> ?RecordField {
2097 -
    if let case Type::Slice { class, item, mutable } = ty {
2899 +
    if let case Type::Slice(slice) = ty {
2098 2900
        match index {
2099 2901
            case 0 => return RecordField {
2100 2902
                name: PTR_FIELD,
2101 -
                fieldType: Type::Pointer { class, target: item, mutable },
2903 +
                fieldType: Type::Pointer(PointerType {
2904 +
                    class: slice.class,
2905 +
                    target: slice.item,
2906 +
                    mutable: slice.mutable,
2907 +
                }),
2102 2908
                offset: 0,
2103 2909
            },
2104 2910
            case 1 => return RecordField {
2105 2911
                name: LEN_FIELD,
2106 2912
                fieldType: Type::U32,
2140 2946
        return isComparable(*l, right);
2141 2947
    } else if let case Type::Optional(_) = right {
2142 2948
        return isComparable(right, left); // Flip order.
2143 2949
    }
2144 2950
    // Pointer comparisons ignore mutability.
2145 -
    if let case Type::Pointer { target: lTarget, .. } = left {
2146 -
        if let case Type::Pointer { target: rTarget, .. } = right {
2147 -
            return typesEqual(*lTarget, *rTarget);
2951 +
    if let case Type::Pointer(l) = left {
2952 +
        if let case Type::Pointer(r) = right {
2953 +
            return typesEqual(*l.target, *r.target);
2148 2954
        }
2149 2955
    }
2150 2956
    // Numeric types.
2151 2957
    if isNumericType(left) and isNumericType(right) {
2152 2958
        return true;
2318 3124
    return false;
2319 3125
}
2320 3126
2321 3127
/// Predicate that matches type symbols.
2322 3128
fn isTypeSymbol(sym: *mut Symbol) -> bool {
2323 -
    if let case SymbolData::Type(_) = sym.data {
2324 -
        return true;
3129 +
    match sym.data {
3130 +
        case SymbolData::Type(_), SymbolData::TypeParameter(_) => return true,
3131 +
        else => return false,
2325 3132
    }
2326 -
    return false;
2327 3133
}
2328 3134
2329 3135
/// Find a symbol by name in a specific scope, filtered by a predicate.
2330 3136
fn findInScope(scope: *Scope, name: *[u8], predicate: fn(*mut Symbol) -> bool) -> ?*mut Symbol {
2331 3137
    for i in 0..scope.symbolsLen {
2491 3297
    self: *mut Resolver,
2492 3298
    node: *ast::Node,
2493 3299
    access: ast::Access,
2494 3300
    scope: *Scope
2495 3301
) -> *mut Symbol throws (ResolveError) {
2496 -
    // Handle `super` access by adjusting scope and node.
3302 +
    // A specialized union application introduces the variant namespace.
3303 +
    if let case ast::NodeValue::GenericApply(app) = access.parent.value {
3304 +
        let nominal = try resolveGenericDataApply(self, access.parent, app, false);
3305 +
        let case NominalType::Union(unionType) = *nominal
3306 +
            else throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3307 +
        let variantName = try nodeName(self, access.child);
3308 +
        let variant = try resolveUnionVariantAccess(
3309 +
            self, node, access, unionType, variantName
3310 +
        );
3311 +
        setNodeType(self, node, Type::Nominal(nominal));
3312 +
        return variant;
3313 +
    }
2497 3314
    let mut startScope = scope;
2498 3315
    let mut pathNode = node;
2499 3316
    if let superAccess = try checkSuperAccess(self, node) {
2500 3317
        set startScope = superAccess.scope;
2501 3318
        set pathNode = superAccess.child;
2618 3435
        &path[1..],
2619 3436
        childSym
2620 3437
    );
2621 3438
}
2622 3439
2623 -
/// Resolve a type name, which could be an identifier or scoped path.
2624 -
fn resolveTypeName(self: *mut Resolver, node: *ast::Node) -> *NominalType throws (ResolveError) {
3440 +
/// Return whether a declaration requires generic arguments.
3441 +
fn isGenericDeclaration(node: *ast::Node) -> bool {
2625 3442
    match node.value {
2626 -
        case ast::NodeValue::Ident(name) => {
2627 -
            let sym = findTypeSymbol(self.scope, name)
2628 -
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
2629 -
            let case SymbolData::Type(ty) = sym.data
2630 -
                else throw emitError(self, node, ErrorKind::Internal);
2631 -
2632 -
            setNodeSymbol(self, node, sym);
3443 +
        case ast::NodeValue::RecordDecl(decl) => return decl.params.len > 0,
3444 +
        case ast::NodeValue::UnionDecl(decl) => return decl.params.len > 0,
3445 +
        case ast::NodeValue::FnDecl(decl) => return decl.params.len > 0,
3446 +
        else => return false,
3447 +
    }
3448 +
}
2633 3449
2634 -
            return ty;
3450 +
/// Return whether a nominal type is present in the visit stack.
3451 +
fn genericRootVisited(visit: ?*GenericRootVisit, nominal: *NominalType) -> bool {
3452 +
    let mut cursor = visit;
3453 +
    while let entry = cursor {
3454 +
        if entry.nominal == nominal {
3455 +
            return true;
2635 3456
        }
2636 -
        case ast::NodeValue::ScopeAccess(access) => {
2637 -
            let sym = try resolveAccess(self, node, access, self.scope);
2638 -
            let case SymbolData::Type(ty) = sym.data
2639 -
                else throw emitError(self, node, ErrorKind::Internal);
2640 -
2641 -
            setNodeSymbol(self, node, sym);
2642 3457
2643 -
            return ty;
2644 -
        }
2645 -
        else => panic "resolveTypeName: unsupported node value",
3458 +
        set cursor = entry.parent;
2646 3459
    }
3460 +
    return false;
2647 3461
}
2648 3462
2649 -
/// Visit a top-level declaration in the declaration phase.
2650 -
/// This binds all names and analyzes signatures, types, and initializers.
2651 -
/// Function bodies are deferred to the definition phase.
2652 -
///
2653 -
/// Nb. User-defined types are already handled by this point.
2654 -
fn visitDecl(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
2655 -
    match node.value {
2656 -
        case ast::NodeValue::FnDecl(_),
2657 -
             ast::NodeValue::ConstDecl(_),
2658 -
             ast::NodeValue::Mod(_),
2659 -
             ast::NodeValue::Use(_) => {
2660 -
            // Handled in previous passes.
2661 -
        }
2662 -
        case ast::NodeValue::StaticDecl(_) => {
2663 -
            try infer(self, node);
2664 -
        }
3463 +
/// Mark generic specializations reached through one concrete type.
3464 +
fn markGenericDataTypeRootedInner(
3465 +
    self: *mut Resolver,
3466 +
    ty: Type,
3467 +
    visited: ?*GenericRootVisit,
3468 +
) -> bool {
3469 +
    match ty {
3470 +
        case Type::Pointer(pointer) =>
3471 +
            return markGenericDataTypeRootedInner(self, *pointer.target, visited),
3472 +
        case Type::Slice(slice) =>
3473 +
            return markGenericDataTypeRootedInner(self, *slice.item, visited),
3474 +
        case Type::Array(array) =>
3475 +
            return markGenericDataTypeRootedInner(self, *array.item, visited),
3476 +
        case Type::Optional(inner) =>
3477 +
            return markGenericDataTypeRootedInner(self, *inner, visited),
3478 +
        case Type::Fn(info) => {
3479 +
            let mut changed = markGenericDataTypeRootedInner(
3480 +
                self, *info.returnType, visited
3481 +
            );
3482 +
            for param in info.paramTypes {
3483 +
                set changed = markGenericDataTypeRootedInner(
3484 +
                    self, *param, visited
3485 +
                ) or changed;
3486 +
            }
3487 +
            for thrown in info.throwList {
3488 +
                set changed = markGenericDataTypeRootedInner(
3489 +
                    self, *thrown, visited
3490 +
                ) or changed;
3491 +
            }
3492 +
            return changed;
3493 +
        }
3494 +
        case Type::Range { start, end } => {
3495 +
            let mut changed = false;
3496 +
            if let value = start {
3497 +
                set changed = markGenericDataTypeRootedInner(
3498 +
                    self, *value, visited
3499 +
                ) or changed;
3500 +
            }
3501 +
            if let value = end {
3502 +
                set changed = markGenericDataTypeRootedInner(
3503 +
                    self, *value, visited
3504 +
                ) or changed;
3505 +
            }
3506 +
            return changed;
3507 +
        }
3508 +
        case Type::Nominal(nominal) => {
3509 +
            let mut cursor = self.genericDataSpecializations;
3510 +
            while let specialization = cursor {
3511 +
                if specialization.nominal == nominal {
3512 +
                    if not specialization.rooted {
3513 +
                        set specialization.rooted = true;
3514 +
                        return true;
3515 +
                    }
3516 +
                    return false;
3517 +
                }
3518 +
                set cursor = specialization.next;
3519 +
            }
3520 +
            if genericRootVisited(visited, nominal) {
3521 +
                return false;
3522 +
            }
3523 +
            let visit = GenericRootVisit { nominal, parent: visited };
3524 +
            let mut changed = false;
3525 +
            match *nominal {
3526 +
                case NominalType::Record(recordType) => {
3527 +
                    for field in recordType.fields {
3528 +
                        set changed = markGenericDataTypeRootedInner(
3529 +
                            self, field.fieldType, &visit
3530 +
                        ) or changed;
3531 +
                    }
3532 +
                }
3533 +
                case NominalType::Union(unionType) => {
3534 +
                    for variant in unionType.variants {
3535 +
                        set changed = markGenericDataTypeRootedInner(
3536 +
                            self, variant.valueType, &visit
3537 +
                        ) or changed;
3538 +
                    }
3539 +
                }
3540 +
                case NominalType::Placeholder(_) => {}
3541 +
            }
3542 +
            return changed;
3543 +
        }
3544 +
        else => return false,
3545 +
    }
3546 +
}
3547 +
3548 +
/// Mark generic data specializations reachable from a concrete type.
3549 +
fn markGenericDataTypeRooted(self: *mut Resolver, ty: Type) -> bool {
3550 +
    return markGenericDataTypeRootedInner(self, ty, nil);
3551 +
}
3552 +
3553 +
/// Propagate explicit roots through arguments and specialized data members.
3554 +
fn validateGenericDataRoots(self: *mut Resolver) throws (ResolveError) {
3555 +
    loop {
3556 +
        let mut changed = false;
3557 +
        let mut cursor = self.genericDataSpecializations;
3558 +
        while let specialization = cursor {
3559 +
            if specialization.rooted {
3560 +
                for arg in specialization.args {
3561 +
                    set changed = markGenericDataTypeRooted(self, *arg) or changed;
3562 +
                }
3563 +
                match *specialization.nominal {
3564 +
                    case NominalType::Record(recordType) => {
3565 +
                        for field in recordType.fields {
3566 +
                            set changed = markGenericDataTypeRooted(
3567 +
                                self, field.fieldType
3568 +
                            ) or changed;
3569 +
                        }
3570 +
                    }
3571 +
                    case NominalType::Union(unionType) => {
3572 +
                        for variant in unionType.variants {
3573 +
                            set changed = markGenericDataTypeRooted(
3574 +
                                self, variant.valueType
3575 +
                            ) or changed;
3576 +
                        }
3577 +
                    }
3578 +
                    case NominalType::Placeholder(_) => {}
3579 +
                }
3580 +
            }
3581 +
            set cursor = specialization.next;
3582 +
        }
3583 +
        if not changed {
3584 +
            break;
3585 +
        }
3586 +
    }
3587 +
    let mut cursor = self.genericDataSpecializations;
3588 +
    while let specialization = cursor {
3589 +
        if not specialization.rooted {
3590 +
            throw emitError(
3591 +
                self, specialization.site, ErrorKind::GenericInstantiationRequired
3592 +
            );
3593 +
        }
3594 +
        set cursor = specialization.next;
3595 +
    }
3596 +
}
3597 +
3598 +
/// Return whether two ordered generic argument lists are equivalent.
3599 +
fn genericArgumentsEqual(left: *[*Type], right: *[*Type]) -> bool {
3600 +
    if left.len <> right.len {
3601 +
        return false;
3602 +
    }
3603 +
    for arg, i in right {
3604 +
        if not typesEqual(*left[i], *arg) {
3605 +
            return false;
3606 +
        }
3607 +
    }
3608 +
    return true;
3609 +
}
3610 +
3611 +
/// Look up mutable data specialization storage.
3612 +
fn findGenericDataSpecializationMut(
3613 +
    self: *Resolver,
3614 +
    template: *Symbol,
3615 +
    args: *[*Type],
3616 +
) -> ?*mut GenericDataSpecialization {
3617 +
    let mut cursor = self.genericDataSpecializations;
3618 +
    while let entry = cursor {
3619 +
        if entry.template == template and genericArgumentsEqual(entry.args, args) {
3620 +
            return entry;
3621 +
        }
3622 +
        set cursor = entry.next;
3623 +
    }
3624 +
    return nil;
3625 +
}
3626 +
3627 +
/// Look up a cached specialization by template and ordered arguments.
3628 +
export fn findGenericDataSpecialization(
3629 +
    self: *Resolver,
3630 +
    template: *Symbol,
3631 +
    args: *[*Type],
3632 +
) -> ?*GenericDataSpecialization {
3633 +
    return findGenericDataSpecializationMut(self, template, args);
3634 +
}
3635 +
3636 +
/// Look up a generic data specialization by its concrete nominal identity.
3637 +
export fn genericDataSpecializationForNominal(
3638 +
    self: *Resolver,
3639 +
    nominal: *NominalType,
3640 +
) -> ?*GenericDataSpecialization {
3641 +
    let mut cursor = self.genericDataSpecializations;
3642 +
    while let specialization = cursor {
3643 +
        if specialization.nominal == nominal {
3644 +
            return specialization;
3645 +
        }
3646 +
        set cursor = specialization.next;
3647 +
    }
3648 +
    return nil;
3649 +
}
3650 +
3651 +
/// Find the declaration symbol that owns an ordinary nominal type.
3652 +
export fn symbolForNominal(
3653 +
    self: *Resolver,
3654 +
    nominal: *NominalType,
3655 +
) -> ?*Symbol {
3656 +
    for data in self.nodeData.entries {
3657 +
        if let sym = data.sym {
3658 +
            if let case SymbolData::Type(candidate) = sym.data; candidate == nominal {
3659 +
                return sym;
3660 +
            }
3661 +
        }
3662 +
    }
3663 +
    return nil;
3664 +
}
3665 +
3666 +
/// Resolve generic metadata lazily so applications are source-order independent.
3667 +
fn ensureGenericDataTemplate(self: *mut Resolver, sym: *mut Symbol)
3668 +
    throws (ResolveError)
3669 +
{
3670 +
    if genericTemplateFor(self, sym) <> nil {
3671 +
        return;
3672 +
    }
3673 +
    let prevScope = self.scope;
3674 +
    let prevMod = self.currentMod;
3675 +
    if let mid = moduleIdForSymbol(self, sym) {
3676 +
        if let moduleScope = self.moduleScopes[mid as u32] {
3677 +
            set self.scope = moduleScope;
3678 +
            set self.currentMod = mid;
3679 +
        }
3680 +
    }
3681 +
    match sym.node.value {
3682 +
        case ast::NodeValue::RecordDecl(decl) => {
3683 +
            try resolveGenericDataTemplate(
3684 +
                self, sym.node, decl.params, decl.fields, decl.derives
3685 +
            ) catch e {
3686 +
                set self.scope = prevScope;
3687 +
                set self.currentMod = prevMod;
3688 +
                throw e;
3689 +
            };
3690 +
        }
3691 +
        case ast::NodeValue::UnionDecl(decl) => {
3692 +
            try resolveGenericDataTemplate(
3693 +
                self, sym.node, decl.params, decl.variants, decl.derives
3694 +
            ) catch e {
3695 +
                set self.scope = prevScope;
3696 +
                set self.currentMod = prevMod;
3697 +
                throw e;
3698 +
            };
3699 +
        }
3700 +
        else => {
3701 +
            set self.scope = prevScope;
3702 +
            set self.currentMod = prevMod;
3703 +
            throw emitError(self, sym.node, ErrorKind::GenericDataExpected);
3704 +
        }
3705 +
    }
3706 +
    set self.scope = prevScope;
3707 +
    set self.currentMod = prevMod;
3708 +
}
3709 +
3710 +
/// Look up a possible inferred generic call target without emitting diagnostics.
3711 +
fn findGenericCandidateSymbol(
3712 +
    self: *Resolver,
3713 +
    node: *ast::Node,
3714 +
) -> ?*mut Symbol {
3715 +
    if let sym = symbolFor(self, node) {
3716 +
        return sym;
3717 +
    }
3718 +
    match node.value {
3719 +
        case ast::NodeValue::Ident(name) =>
3720 +
            return findAnySymbol(self.scope, name),
3721 +
        case ast::NodeValue::ScopeAccess(access) => {
3722 +
            let case ast::NodeValue::Ident(childName) = access.child.value
3723 +
                else return nil;
3724 +
            if let case ast::NodeValue::Super = access.parent.value {
3725 +
                let current = module::get(self.moduleGraph, self.currentMod) else return nil;
3726 +
                let parentId = current.parent else return nil;
3727 +
                let parentScope = self.moduleScopes[parentId as u32] else return nil;
3728 +
                return findSymbolInScope(parentScope, childName);
3729 +
            }
3730 +
            let sym = findGenericCandidateSymbol(self, access.parent) else return nil;
3731 +
            let case SymbolData::Module { scope, .. } = sym.data else return nil;
3732 +
            return findSymbolInScope(scope, childName);
3733 +
        }
3734 +
        else => return nil,
3735 +
    }
3736 +
}
3737 +
3738 +
/// Resolve a generic application's declaration symbol without requiring arguments.
3739 +
fn resolveGenericTarget(
3740 +
    self: *mut Resolver,
3741 +
    node: *ast::Node,
3742 +
) -> *mut Symbol throws (ResolveError) {
3743 +
    if let existing = symbolFor(self, node) {
3744 +
        return existing;
3745 +
    }
3746 +
    let mut sym: *mut Symbol = undefined;
3747 +
    match node.value {
3748 +
        case ast::NodeValue::Ident(name) => {
3749 +
            let found = findAnySymbol(self.scope, name) else {
3750 +
                throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
3751 +
            };
3752 +
            set sym = found;
3753 +
        }
3754 +
        case ast::NodeValue::ScopeAccess(access) => {
3755 +
            set sym = try resolveAccess(self, node, access, self.scope);
3756 +
        }
3757 +
        else => throw emitError(self, node, ErrorKind::GenericUnsupported),
3758 +
    }
3759 +
    if not isGenericDeclaration(sym.node) {
3760 +
        throw emitError(self, node, ErrorKind::GenericUnsupported);
3761 +
    }
3762 +
    setNodeSymbol(self, node, sym);
3763 +
    return sym;
3764 +
}
3765 +
3766 +
/// Resolve a generic record or union target.
3767 +
fn resolveGenericDataTarget(
3768 +
    self: *mut Resolver,
3769 +
    node: *ast::Node,
3770 +
) -> *mut Symbol throws (ResolveError) {
3771 +
    let sym = try resolveGenericTarget(self, node);
3772 +
    let case SymbolData::Type(_) = sym.data
3773 +
        else throw emitError(self, node, ErrorKind::GenericDataExpected);
3774 +
    match sym.node.value {
3775 +
        case ast::NodeValue::RecordDecl(_), ast::NodeValue::UnionDecl(_) => {}
3776 +
        else => throw emitError(self, node, ErrorKind::GenericDataExpected),
3777 +
    }
3778 +
    return sym;
3779 +
}
3780 +
3781 +
/// Build record fields and layout from ordinary or substituted member types.
3782 +
fn buildRecordType(
3783 +
    self: *mut Resolver,
3784 +
    node: *ast::Node,
3785 +
    fields: *mut [*ast::Node],
3786 +
    labeled: bool,
3787 +
    declaredLinear: bool,
3788 +
    source: AggregateMemberSource,
3789 +
) -> RecordType throws (ResolveError) {
3790 +
    if fields.len > parser::MAX_RECORD_FIELDS {
3791 +
        throw emitError(self, node, ErrorKind::Internal);
3792 +
    }
3793 +
    let a = alloc::arenaAllocator(&mut self.arena);
3794 +
    let mut result: *mut [RecordField] = &mut [];
3795 +
    let mut offset: u32 = 0;
3796 +
    let mut alignment: u32 = 1;
3797 +
    for fieldNode, i in fields {
3798 +
        let case ast::NodeValue::RecordField {
3799 +
            field: nameNode,
3800 +
            type: typeNode,
3801 +
            value,
3802 +
        } = fieldNode.value else {
3803 +
            panic "buildRecordType: invalid record field";
3804 +
        };
3805 +
        let mut fieldType: Type = undefined;
3806 +
        match source {
3807 +
            case AggregateMemberSource::Ordinary => {
3808 +
                set fieldType = try resolveValueType(self, typeNode);
3809 +
                try ensureStorableType(self, typeNode, fieldType);
3810 +
                if let initializer = value {
3811 +
                    let _ = try checkAssignable(self, initializer, fieldType);
3812 +
                }
3813 +
            }
3814 +
            case AggregateMemberSource::Generic {
3815 +
                members, substitution
3816 +
            } => {
3817 +
                set fieldType = try substituteType(
3818 +
                    self, *members[i], substitution, typeNode
3819 +
                );
3820 +
                if hasUnresolvedNominalLayout(fieldType) {
3821 +
                    throw emitError(
3822 +
                        self, typeNode, ErrorKind::GenericRecursiveLayout
3823 +
                    );
3824 +
                }
3825 +
                try ensureStorableType(self, typeNode, fieldType);
3826 +
            }
3827 +
        }
3828 +
        try ensureTypeResolved(self, fieldType, typeNode);
3829 +
        let layout = getTypeLayout(fieldType);
3830 +
        set offset = mem::alignUp(offset, layout.alignment);
3831 +
        let mut name: ?*[u8] = nil;
3832 +
        if labeled {
3833 +
            let requiredName = nameNode
3834 +
                else panic "buildRecordType: labeled record field missing name";
3835 +
            set name = try nodeName(self, requiredName);
3836 +
        }
3837 +
        result.append(RecordField {
3838 +
            name,
3839 +
            fieldType,
3840 +
            offset: offset as i32,
3841 +
        }, a);
3842 +
        set offset += layout.size;
3843 +
        set alignment = max(alignment, layout.alignment);
3844 +
    }
3845 +
    return RecordType {
3846 +
        fields: &result[..],
3847 +
        labeled,
3848 +
        layout: Layout {
3849 +
            size: mem::alignUp(offset, alignment),
3850 +
            alignment,
3851 +
        },
3852 +
        declaredLinear,
3853 +
    };
3854 +
}
3855 +
3856 +
/// Build union variants and layout from ordinary or substituted member types.
3857 +
fn buildUnionType(
3858 +
    self: *mut Resolver,
3859 +
    owner: *mut Symbol,
3860 +
    decl: ast::UnionDecl,
3861 +
    declaredLinear: bool,
3862 +
    source: AggregateMemberSource,
3863 +
) -> UnionType throws (ResolveError) {
3864 +
    assert decl.variants.len <= MAX_UNION_VARIANTS,
3865 +
        "buildUnionType: maximum union variants exceeded";
3866 +
    let a = alloc::arenaAllocator(&mut self.arena);
3867 +
    let mut variants: *mut [UnionVariant] = &mut [];
3868 +
    let mut iota: u32 = 0;
3869 +
    let mut tagSubstitution: ?*Substitution = nil;
3870 +
    if let case AggregateMemberSource::Generic {
3871 +
        substitution, ..
3872 +
    } = source {
3873 +
        set tagSubstitution = substitution;
3874 +
    }
3875 +
    for variantNode, i in decl.variants {
3876 +
        let case ast::NodeValue::UnionDeclVariant(variantDecl) = variantNode.value
3877 +
            else panic "buildUnionType: invalid union variant";
3878 +
        let mut valueType = Type::Void;
3879 +
        match source {
3880 +
            case AggregateMemberSource::Ordinary => {
3881 +
                if let typeNode = variantDecl.type {
3882 +
                    set valueType = try infer(self, typeNode);
3883 +
                    try ensureStorableType(self, typeNode, valueType);
3884 +
                }
3885 +
                if let value = variantDecl.value {
3886 +
                    let _ = try checkSizeInt(self, value);
3887 +
                }
3888 +
            }
3889 +
            case AggregateMemberSource::Generic {
3890 +
                members, substitution
3891 +
            } => {
3892 +
                set valueType = try substituteType(
3893 +
                    self, *members[i], substitution, variantNode
3894 +
                );
3895 +
                if hasUnresolvedNominalLayout(valueType) {
3896 +
                    throw emitError(
3897 +
                        self, variantNode, ErrorKind::GenericRecursiveLayout
3898 +
                    );
3899 +
                }
3900 +
                if let typeNode = variantDecl.type {
3901 +
                    try ensureStorableType(self, typeNode, valueType);
3902 +
                    try ensureTypeResolved(self, valueType, typeNode);
3903 +
                }
3904 +
            }
3905 +
        }
3906 +
        let name = try nodeName(self, variantDecl.name);
3907 +
        let tag = try variantTag(
3908 +
            self, variantDecl, &mut iota, tagSubstitution
3909 +
        );
3910 +
        let symbol = allocSymbol(
3911 +
            self,
3912 +
            SymbolData::Variant {
3913 +
                type: valueType,
3914 +
                decl: owner.node,
3915 +
                ordinal: i,
3916 +
                index: tag,
3917 +
            },
3918 +
            name,
3919 +
            variantNode,
3920 +
            0,
3921 +
        );
3922 +
        set symbol.moduleId = owner.moduleId;
3923 +
        variants.append(UnionVariant { name, valueType, symbol }, a);
3924 +
    }
3925 +
    let info = computeUnionLayout(&variants[..]);
3926 +
    return UnionType {
3927 +
        variants: &variants[..],
3928 +
        layout: info.layout,
3929 +
        valOffset: info.valOffset,
3930 +
        isAllVoid: info.isAllVoid,
3931 +
        declaredLinear,
3932 +
    };
3933 +
}
3934 +
3935 +
/// Return one canonical concrete specialization for a generic data application.
3936 +
fn specializeGenericData(
3937 +
    self: *mut Resolver,
3938 +
    site: *ast::Node,
3939 +
    templateSym: *mut Symbol,
3940 +
    args: *[*Type],
3941 +
    rooted: bool,
3942 +
) -> *mut NominalType throws (ResolveError) {
3943 +
    if let existing = findGenericDataSpecializationMut(self, templateSym, args) {
3944 +
        if rooted {
3945 +
            set existing.rooted = true;
3946 +
        }
3947 +
        return existing.nominal;
3948 +
    }
3949 +
    if self.genericSpecializationCount >= MAX_GENERIC_SPECIALIZATIONS {
3950 +
        throw emitError(self, site, ErrorKind::GenericSpecializationLimit);
3951 +
    }
3952 +
    set self.genericSpecializationCount += 1;
3953 +
    let template = genericTemplateFor(self, templateSym)
3954 +
        else throw emitError(self, site, ErrorKind::Internal);
3955 +
    let a = alloc::arenaAllocator(&mut self.arena);
3956 +
    let mut storedArgs: *mut [*Type] = &mut [];
3957 +
    for arg in args {
3958 +
        storedArgs.append(arg, a);
3959 +
    }
3960 +
    let nominal = allocNominalType(
3961 +
        self, NominalType::Placeholder(templateSym.node)
3962 +
    );
3963 +
    let specialization = try! alloc::alloc(
3964 +
        &mut self.arena,
3965 +
        @sizeOf(GenericDataSpecialization),
3966 +
        @alignOf(GenericDataSpecialization),
3967 +
    ) as *mut GenericDataSpecialization;
3968 +
    set *specialization = GenericDataSpecialization {
3969 +
        template: templateSym,
3970 +
        args: &storedArgs[..],
3971 +
        nominal,
3972 +
        rooted,
3973 +
        site,
3974 +
        next: self.genericDataSpecializations,
3975 +
    };
3976 +
    set self.genericDataSpecializations = specialization;
3977 +
    let sub = Substitution { params: template.params, args: &storedArgs[..] };
3978 +
    let source = AggregateMemberSource::Generic {
3979 +
        members: template.members,
3980 +
        substitution: &sub,
3981 +
    };
3982 +
    match templateSym.node.value {
3983 +
        case ast::NodeValue::RecordDecl(decl) => {
3984 +
            let recordType = try buildRecordType(
3985 +
                self,
3986 +
                templateSym.node,
3987 +
                decl.fields,
3988 +
                decl.labeled,
3989 +
                template.declaredLinear,
3990 +
                source,
3991 +
            );
3992 +
            set *nominal = NominalType::Record(recordType);
3993 +
        }
3994 +
        case ast::NodeValue::UnionDecl(decl) => {
3995 +
            let unionType = try buildUnionType(
3996 +
                self, templateSym, decl, template.declaredLinear, source
3997 +
            );
3998 +
            set *nominal = NominalType::Union(unionType);
3999 +
        }
4000 +
        else => throw emitError(self, site, ErrorKind::GenericDataExpected),
4001 +
    }
4002 +
    return nominal;
4003 +
}
4004 +
4005 +
/// Resolve one generic argument according to its declaration kind.
4006 +
fn resolveGenericArgument(
4007 +
    self: *mut Resolver,
4008 +
    argNode: *ast::Node,
4009 +
    param: *GenericParamType,
4010 +
) -> Type throws (ResolveError) {
4011 +
    if let constType = param.constType {
4012 +
        let mut expr = argNode;
4013 +
        if let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(name)) = argNode.value {
4014 +
            set expr = name;
4015 +
        }
4016 +
        let actual = try visit(self, expr, *constType);
4017 +
        if let value = constValueEntry(self, expr) {
4018 +
            let case ConstValue::Int(int) = value
4019 +
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
4020 +
            if not validateConstIntRange(value, *constType) {
4021 +
                throw emitError(self, expr, ErrorKind::NumericLiteralOverflow);
4022 +
            }
4023 +
            let _ = try expectAssignable(self, *constType, actual, expr);
4024 +
            let case ConstValue::Int(canonical) = castConstInt(int, *constType)
4025 +
                else throw emitError(self, expr, ErrorKind::Internal);
4026 +
            return Type::ConstArgument { type: constType, value: canonical };
4027 +
        }
4028 +
        let _ = try expectAssignable(self, *constType, actual, expr);
4029 +
        if isConstExpr(self, expr) and containsGenericConstExpr(self, expr) {
4030 +
            return Type::GenericConstExpr { type: constType, expr };
4031 +
        }
4032 +
        throw emitError(self, expr, ErrorKind::ConstExprRequired);
4033 +
    }
4034 +
    if let case ast::NodeValue::TypeSig(_) = argNode.value {
4035 +
        let arg = try resolveTypeSyntax(
4036 +
            self, argNode, TypeSyntaxContext::Symbolic
4037 +
        );
4038 +
        return try materializeConcreteGenericData(self, arg, argNode);
4039 +
    }
4040 +
    throw emitError(self, argNode, ErrorKind::GenericUnsupported);
4041 +
}
4042 +
4043 +
/// Resolve and canonicalize one generic data type application.
4044 +
fn resolveGenericDataApply(
4045 +
    self: *mut Resolver,
4046 +
    node: *ast::Node,
4047 +
    app: ast::GenericApply,
4048 +
    rooted: bool,
4049 +
) -> *mut NominalType throws (ResolveError) {
4050 +
    let templateSym = try resolveGenericDataTarget(self, app.target);
4051 +
    try ensureGenericDataTemplate(self, templateSym);
4052 +
    let template = genericTemplateFor(self, templateSym)
4053 +
        else throw emitError(self, node, ErrorKind::Internal);
4054 +
    if app.args.len <> template.params.len {
4055 +
        throw emitError(self, node, ErrorKind::GenericArgumentCount(CountMismatch {
4056 +
            expected: template.params.len,
4057 +
            actual: app.args.len,
4058 +
        }));
4059 +
    }
4060 +
    let a = alloc::arenaAllocator(&mut self.arena);
4061 +
    let mut args: *mut [*Type] = &mut [];
4062 +
    for argNode, i in app.args {
4063 +
        let argType = try resolveGenericArgument(self, argNode, template.params[i]);
4064 +
        if containsGenericParameter(argType) {
4065 +
            throw emitError(self, argNode, ErrorKind::GenericConcreteArgumentsRequired);
4066 +
        }
4067 +
        args.append(allocType(self, argType), a);
4068 +
    }
4069 +
    let nominal = try specializeGenericData(
4070 +
        self, node, templateSym, &args[..], rooted
4071 +
    );
4072 +
4073 +
    setNodeSymbol(self, node, templateSym);
4074 +
    setNodeType(self, node, Type::Nominal(nominal));
4075 +
    return nominal;
4076 +
}
4077 +
4078 +
/// Return the function specialization list for lowering.
4079 +
export fn genericFnSpecializations(
4080 +
    self: *Resolver,
4081 +
) -> ?*GenericFnSpecialization {
4082 +
    return self.genericFnSpecializations;
4083 +
}
4084 +
4085 +
/// Look up a canonical function specialization.
4086 +
export fn findGenericFnSpecialization(
4087 +
    self: *Resolver,
4088 +
    template: *Symbol,
4089 +
    args: *[*Type],
4090 +
) -> ?*GenericFnSpecialization {
4091 +
    let mut cursor = self.genericFnSpecializations;
4092 +
    while let entry = cursor {
4093 +
        if entry.template == template and genericArgumentsEqual(entry.args, args) {
4094 +
            return entry;
4095 +
        }
4096 +
        set cursor = entry.next;
4097 +
    }
4098 +
    return nil;
4099 +
}
4100 +
4101 +
/// Create or retrieve one concrete generic function specialization.
4102 +
fn internGenericFnSpecialization(
4103 +
    self: *mut Resolver,
4104 +
    templateSym: *mut Symbol,
4105 +
    args: *[*Type],
4106 +
    site: *ast::Node,
4107 +
    depth: u16,
4108 +
) -> *GenericFnSpecialization throws (ResolveError) {
4109 +
    if let existing = findGenericFnSpecialization(self, templateSym, args) {
4110 +
        return existing;
4111 +
    }
4112 +
    if self.genericSpecializationCount >= MAX_GENERIC_SPECIALIZATIONS {
4113 +
        throw emitError(self, site, ErrorKind::GenericSpecializationLimit);
4114 +
    }
4115 +
    set self.genericSpecializationCount += 1;
4116 +
    let template = genericTemplateFor(self, templateSym)
4117 +
        else throw emitError(self, site, ErrorKind::Internal);
4118 +
    let signature = template.signature
4119 +
        else throw emitError(self, site, ErrorKind::GenericFunctionExpected);
4120 +
    let a = alloc::arenaAllocator(&mut self.arena);
4121 +
    let mut storedArgs: *mut [*Type] = &mut [];
4122 +
    for arg in args {
4123 +
        storedArgs.append(allocType(self, *arg), a);
4124 +
    }
4125 +
    let sub = Substitution { params: template.params, args: &storedArgs[..] };
4126 +
    let concrete = try substituteType(self, Type::Fn(signature), &sub, site);
4127 +
    let case Type::Fn(fnType) = concrete
4128 +
        else throw emitError(self, site, ErrorKind::Internal);
4129 +
    let _ = markGenericDataTypeRooted(self, concrete);
4130 +
    let specialization = try! alloc::alloc(
4131 +
        &mut self.arena,
4132 +
        @sizeOf(GenericFnSpecialization),
4133 +
        @alignOf(GenericFnSpecialization),
4134 +
    ) as *mut GenericFnSpecialization;
4135 +
    set *specialization = GenericFnSpecialization {
4136 +
        template: templateSym,
4137 +
        args: &storedArgs[..],
4138 +
        fnType,
4139 +
        site,
4140 +
        state: GenericFnState::Queued,
4141 +
        depth,
4142 +
        typesMaterialized: false,
4143 +
        next: self.genericFnSpecializations,
4144 +
    };
4145 +
    set self.genericFnSpecializations = specialization;
4146 +
    return specialization;
4147 +
}
4148 +
4149 +
/// Retain a generic call edge for package-wide specialization closure.
4150 +
fn recordGenericFnDependency(
4151 +
    self: *mut Resolver,
4152 +
    node: *ast::Node,
4153 +
    caller: ?*mut Symbol,
4154 +
    callee: *mut Symbol,
4155 +
    args: *[*Type],
4156 +
    fnType: *FnType,
4157 +
) {
4158 +
    let a = alloc::arenaAllocator(&mut self.arena);
4159 +
    let mut storedArgs: *mut [*Type] = &mut [];
4160 +
    for arg in args {
4161 +
        storedArgs.append(allocType(self, *arg), a);
4162 +
    }
4163 +
    let dependency = try! alloc::alloc(
4164 +
        &mut self.arena,
4165 +
        @sizeOf(GenericFnDependency),
4166 +
        @alignOf(GenericFnDependency),
4167 +
    ) as *mut GenericFnDependency;
4168 +
    set *dependency = GenericFnDependency {
4169 +
        caller,
4170 +
        callee,
4171 +
        args: &storedArgs[..],
4172 +
        site: node,
4173 +
        next: self.genericFnDependencies,
4174 +
    };
4175 +
    set self.genericFnDependencies = dependency;
4176 +
    setNodeSymbol(self, node, callee);
4177 +
    setNodeType(self, node, Type::Fn(fnType));
4178 +
    set self.nodeData.entries[node.id].extra =
4179 +
        NodeExtra::GenericFnDependency(dependency);
4180 +
}
4181 +
4182 +
/// Resolve a generic function application as a root, concrete call, or symbolic edge.
4183 +
fn resolveGenericFnApply(
4184 +
    self: *mut Resolver,
4185 +
    node: *ast::Node,
4186 +
    app: ast::GenericApply,
4187 +
    rooted: bool,
4188 +
) -> *FnType throws (ResolveError) {
4189 +
    let templateSym = try resolveGenericTarget(self, app.target);
4190 +
    let case SymbolData::Value { type: Type::Fn(_), .. } = templateSym.data
4191 +
        else throw emitError(self, app.target, ErrorKind::GenericFunctionExpected);
4192 +
    let template = genericTemplateFor(self, templateSym)
4193 +
        else throw emitError(self, node, ErrorKind::Internal);
4194 +
    let signature = template.signature
4195 +
        else throw emitError(self, app.target, ErrorKind::GenericFunctionExpected);
4196 +
    if app.args.len <> template.params.len {
4197 +
        throw emitError(self, node, ErrorKind::GenericArgumentCount(CountMismatch {
4198 +
            expected: template.params.len,
4199 +
            actual: app.args.len,
4200 +
        }));
4201 +
    }
4202 +
    let a = alloc::arenaAllocator(&mut self.arena);
4203 +
    let mut args: *mut [*Type] = &mut [];
4204 +
    let caller = currentGenericTemplateSymbol(self);
4205 +
    for argNode, i in app.args {
4206 +
        let argType = try resolveGenericArgument(self, argNode, template.params[i]);
4207 +
        let symbolic = containsGenericParameter(argType);
4208 +
        if symbolic and caller == nil {
4209 +
            throw emitError(
4210 +
                self, argNode, ErrorKind::GenericConcreteArgumentsRequired
4211 +
            );
4212 +
        }
4213 +
        if not symbolic {
4214 +
            for bound in template.params[i].bounds {
4215 +
                if findInstance(self, bound, argType) == nil {
4216 +
                    throw emitError(
4217 +
                        self, argNode, ErrorKind::GenericBoundUnsatisfied(bound.name)
4218 +
                    );
4219 +
                }
4220 +
            }
4221 +
        }
4222 +
        args.append(allocType(self, argType), a);
4223 +
    }
4224 +
    let sub = Substitution { params: template.params, args: &args[..] };
4225 +
    let applied = try substituteType(self, Type::Fn(signature), &sub, node);
4226 +
    let case Type::Fn(appliedFn) = applied
4227 +
        else throw emitError(self, node, ErrorKind::Internal);
4228 +
    if rooted {
4229 +
        if caller <> nil {
4230 +
            throw emitError(self, node, ErrorKind::GenericConcreteArgumentsRequired);
4231 +
        }
4232 +
        let specialization = try internGenericFnSpecialization(
4233 +
            self, templateSym, &args[..], node, 0
4234 +
        );
4235 +
        setNodeSymbol(self, node, templateSym);
4236 +
        setNodeType(self, node, Type::Fn(specialization.fnType));
4237 +
        set self.nodeData.entries[node.id].extra =
4238 +
            NodeExtra::GenericFnCall(specialization);
4239 +
        return specialization.fnType;
4240 +
    }
4241 +
    if caller == nil {
4242 +
        if let existing = findGenericFnSpecialization(self, templateSym, &args[..]) {
4243 +
            setNodeSymbol(self, node, templateSym);
4244 +
            setNodeType(self, node, Type::Fn(existing.fnType));
4245 +
            set self.nodeData.entries[node.id].extra =
4246 +
                NodeExtra::GenericFnCall(existing);
4247 +
            return existing.fnType;
4248 +
        }
4249 +
    }
4250 +
    recordGenericFnDependency(
4251 +
        self, node, caller, templateSym, &args[..], appliedFn
4252 +
    );
4253 +
    return appliedFn;
4254 +
}
4255 +
4256 +
/// Expand explicit roots through symbolic generic calls to a fixed point.
4257 +
fn closeGenericFnSpecializations(self: *mut Resolver) throws (ResolveError) {
4258 +
    loop {
4259 +
        let mut queued: ?*mut GenericFnSpecialization = nil;
4260 +
        let mut cursor = self.genericFnSpecializations;
4261 +
        while let specialization = cursor {
4262 +
            if let case GenericFnState::Queued = specialization.state {
4263 +
                set queued = specialization;
4264 +
                break;
4265 +
            }
4266 +
            set cursor = specialization.next;
4267 +
        }
4268 +
        let specialization = queued else break;
4269 +
        set specialization.state = GenericFnState::Lowering;
4270 +
        let callerTemplate = genericTemplateFor(self, specialization.template)
4271 +
            else throw emitError(self, specialization.site, ErrorKind::Internal);
4272 +
        let callerSub = Substitution {
4273 +
            params: callerTemplate.params,
4274 +
            args: specialization.args,
4275 +
        };
4276 +
        let mut edge = self.genericFnDependencies;
4277 +
        while let dependency = edge {
4278 +
            if dependency.caller == specialization.template {
4279 +
                let a = alloc::arenaAllocator(&mut self.arena);
4280 +
                let mut concreteArgs: *mut [*Type] = &mut [];
4281 +
                for arg in dependency.args {
4282 +
                    let concrete = try substituteType(
4283 +
                        self, *arg, &callerSub, dependency.site
4284 +
                    );
4285 +
                    if containsGenericParameter(concrete) {
4286 +
                        throw emitError(
4287 +
                            self,
4288 +
                            dependency.site,
4289 +
                            ErrorKind::GenericConcreteArgumentsRequired,
4290 +
                        );
4291 +
                    }
4292 +
                    concreteArgs.append(allocType(self, concrete), a);
4293 +
                }
4294 +
                let calleeTemplate = genericTemplateFor(self, dependency.callee)
4295 +
                    else throw emitError(
4296 +
                        self, dependency.site, ErrorKind::Internal
4297 +
                    );
4298 +
                for arg, i in concreteArgs {
4299 +
                    for bound in calleeTemplate.params[i].bounds {
4300 +
                        if findInstance(self, bound, *arg) == nil {
4301 +
                            throw emitError(
4302 +
                                self,
4303 +
                                dependency.site,
4304 +
                                ErrorKind::GenericBoundUnsatisfied(bound.name),
4305 +
                            );
4306 +
                        }
4307 +
                    }
4308 +
                }
4309 +
                let mut callee = findGenericFnSpecialization(
4310 +
                    self, dependency.callee, &concreteArgs[..]
4311 +
                );
4312 +
                if callee == nil {
4313 +
                    if specialization.depth >= MAX_GENERIC_SPECIALIZATION_DEPTH {
4314 +
                        throw emitError(
4315 +
                            self,
4316 +
                            dependency.site,
4317 +
                            ErrorKind::GenericSpecializationChain,
4318 +
                        );
4319 +
                    }
4320 +
                    set callee = try internGenericFnSpecialization(
4321 +
                        self,
4322 +
                        dependency.callee,
4323 +
                        &concreteArgs[..],
4324 +
                        dependency.site,
4325 +
                        specialization.depth + 1,
4326 +
                    );
4327 +
                }
4328 +
                let concreteCallee = callee
4329 +
                    else throw emitError(
4330 +
                        self, dependency.site, ErrorKind::Internal
4331 +
                    );
4332 +
                let resolution = try! alloc::alloc(
4333 +
                    &mut self.arena,
4334 +
                    @sizeOf(GenericFnDependencyResolution),
4335 +
                    @alignOf(GenericFnDependencyResolution),
4336 +
                ) as *mut GenericFnDependencyResolution;
4337 +
                set *resolution = GenericFnDependencyResolution {
4338 +
                    dependency,
4339 +
                    caller: specialization,
4340 +
                    callee: concreteCallee,
4341 +
                    next: self.genericFnDependencyResolutions,
4342 +
                };
4343 +
                set self.genericFnDependencyResolutions = resolution;
4344 +
            }
4345 +
            set edge = dependency.next;
4346 +
        }
4347 +
        set specialization.state = GenericFnState::Complete;
4348 +
    }
4349 +
4350 +
    // Non-generic calls may only select entries made reachable by the closure.
4351 +
    let mut edge = self.genericFnDependencies;
4352 +
    while let dependency = edge {
4353 +
        if dependency.caller == nil {
4354 +
            let specialization = findGenericFnSpecialization(
4355 +
                self, dependency.callee, dependency.args
4356 +
            ) else {
4357 +
                throw emitError(
4358 +
                    self,
4359 +
                    dependency.site,
4360 +
                    ErrorKind::GenericFunctionInstantiationRequired,
4361 +
                );
4362 +
            };
4363 +
            set self.nodeData.entries[dependency.site.id].extra =
4364 +
                NodeExtra::GenericFnCall(specialization);
4365 +
            set self.nodeData.entries[dependency.site.id].ty =
4366 +
                Type::Fn(specialization.fnType);
4367 +
        }
4368 +
        set edge = dependency.next;
4369 +
    }
4370 +
}
4371 +
4372 +
/// Materialize symbolic body types for newly closed generic functions.
4373 +
///
4374 +
/// Each specialization is processed once, while its package's specialization
4375 +
/// limit is active. This closes resolver-owned generic data caches before
4376 +
/// lowering receives an immutable resolver.
4377 +
fn materializeGenericFnTypeUses(self: *mut Resolver) throws (ResolveError) {
4378 +
    let mut cursor = self.genericFnSpecializations;
4379 +
    while let specialization = cursor {
4380 +
        if specialization.typesMaterialized {
4381 +
            set cursor = specialization.next;
4382 +
            continue;
4383 +
        }
4384 +
        let template = genericTemplateForMut(
4385 +
            self, specialization.template
4386 +
        ) else throw emitError(
4387 +
            self, specialization.site, ErrorKind::Internal
4388 +
        );
4389 +
        let sub = Substitution {
4390 +
            params: template.params,
4391 +
            args: specialization.args,
4392 +
        };
4393 +
        for typeUse in template.typeUses {
4394 +
            let concrete = try substituteType(
4395 +
                self, typeUse.ty, &sub, typeUse.site
4396 +
            );
4397 +
            if containsGenericParameter(concrete) {
4398 +
                throw emitError(
4399 +
                    self,
4400 +
                    typeUse.site,
4401 +
                    ErrorKind::GenericConcreteArgumentsRequired,
4402 +
                );
4403 +
            }
4404 +
            let _ = markGenericDataTypeRooted(self, concrete);
4405 +
        }
4406 +
        set specialization.typesMaterialized = true;
4407 +
        set cursor = specialization.next;
4408 +
    }
4409 +
}
4410 +
4411 +
/// Select the concrete callee for a symbolic edge while lowering a specialization.
4412 +
export fn genericFnSpecializationForDependency(
4413 +
    self: *Resolver,
4414 +
    dependency: *GenericFnDependency,
4415 +
    caller: *GenericFnSpecialization,
4416 +
) -> ?*GenericFnSpecialization {
4417 +
    let mut resolution = self.genericFnDependencyResolutions;
4418 +
    while let entry = resolution {
4419 +
        if entry.dependency == dependency and entry.caller == caller {
4420 +
            return entry.callee;
4421 +
        }
4422 +
        set resolution = entry.next;
4423 +
    }
4424 +
    return nil;
4425 +
}
4426 +
4427 +
/// Resolve a type name, which could be an identifier or scoped path.
4428 +
fn resolveTypeName(self: *mut Resolver, node: *ast::Node) -> *NominalType throws (ResolveError) {
4429 +
    match node.value {
4430 +
        case ast::NodeValue::Ident(name) => {
4431 +
            let sym = findTypeSymbol(self.scope, name)
4432 +
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
4433 +
            let case SymbolData::Type(ty) = sym.data
4434 +
                else throw emitError(self, node, ErrorKind::Internal);
4435 +
            if isGenericDeclaration(sym.node) {
4436 +
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4437 +
            }
4438 +
4439 +
            setNodeSymbol(self, node, sym);
4440 +
4441 +
            return ty;
4442 +
        }
4443 +
        case ast::NodeValue::ScopeAccess(access) => {
4444 +
            let sym = try resolveAccess(self, node, access, self.scope);
4445 +
            let case SymbolData::Type(ty) = sym.data
4446 +
                else throw emitError(self, node, ErrorKind::Internal);
4447 +
            if isGenericDeclaration(sym.node) {
4448 +
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4449 +
            }
4450 +
4451 +
            setNodeSymbol(self, node, sym);
4452 +
4453 +
            return ty;
4454 +
        }
4455 +
        case ast::NodeValue::GenericApply(app) =>
4456 +
            return try resolveGenericDataApply(self, node, app, false),
4457 +
        else => panic "resolveTypeName: unsupported node value",
4458 +
    }
4459 +
}
4460 +
4461 +
/// Visit a top-level declaration in the declaration phase.
4462 +
/// This binds all names and analyzes signatures, types, and initializers.
4463 +
/// Function bodies are deferred to the definition phase.
4464 +
///
4465 +
/// Nb. User-defined types are already handled by this point.
4466 +
fn visitDecl(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
4467 +
    match node.value {
4468 +
        case ast::NodeValue::FnDecl(_),
4469 +
             ast::NodeValue::ConstDecl(_),
4470 +
             ast::NodeValue::Mod(_),
4471 +
             ast::NodeValue::Use(_) => {
4472 +
            // Handled in previous passes.
4473 +
        }
4474 +
        case ast::NodeValue::StaticDecl(_) => {
4475 +
            try infer(self, node);
4476 +
        }
2665 4477
        case ast::NodeValue::InstanceDecl { traitName, targetType, methods } => {
2666 4478
            try resolveInstanceDecl(self, node, traitName, targetType, methods);
2667 4479
        }
2668 4480
        case ast::NodeValue::MethodDecl { name, receiverName, receiverType, sig, body, attrs } => {
2669 4481
            try resolveMethodDecl(self, node, name, receiverName, receiverType, sig, attrs);
2670 4482
        }
4483 +
        case ast::NodeValue::Instantiate(applications) => {
4484 +
            for application in applications {
4485 +
                let case ast::NodeValue::GenericApply(app) = application.value
4486 +
                    else throw emitError(self, application, ErrorKind::GenericUnsupported);
4487 +
                if self.genericRoots >= MAX_GENERIC_ROOTS {
4488 +
                    throw emitError(self, application, ErrorKind::GenericRootLimit);
4489 +
                }
4490 +
                set self.genericRoots += 1;
4491 +
                let target = try resolveGenericTarget(self, app.target);
4492 +
                match target.data {
4493 +
                    case SymbolData::Type(_) => {
4494 +
                        let _ = try resolveGenericDataApply(self, application, app, true);
4495 +
                    }
4496 +
                    case SymbolData::Value { type: Type::Fn(_), .. } => {
4497 +
                        let _ = try resolveGenericFnApply(self, application, app, true);
4498 +
                    }
4499 +
                    else => {
4500 +
                        throw emitError(self, app.target, ErrorKind::GenericUnsupported);
4501 +
                    }
4502 +
                }
4503 +
            }
4504 +
            setNodeType(self, node, Type::Void);
4505 +
        }
2671 4506
        else => {
2672 4507
            // Ignore non-declaration nodes.
2673 4508
        }
2674 4509
    }
2675 4510
}
2755 4590
/// Reject nested references while allowing a direct parameter reference.
2756 4591
fn validateValueTypeReferences(self: *mut Resolver, node: *ast::Node, ty: Type)
2757 4592
    throws (ResolveError)
2758 4593
{
2759 4594
    if isRefType(ty) {
2760 -
        if let case Type::Pointer { target, .. } = ty {
2761 -
            if containsRef(*target) {
4595 +
        if let case Type::Pointer(pointer) = ty {
4596 +
            if containsRef(*pointer.target) {
2762 4597
                throw emitError(self, node, ErrorKind::InvalidRefPosition);
2763 4598
            }
2764 -
        } else if let case Type::Slice { item, .. } = ty {
2765 -
            if containsRef(*item) {
4599 +
        } else if let case Type::Slice(slice) = ty {
4600 +
            if containsRef(*slice.item) {
2766 4601
                throw emitError(self, node, ErrorKind::InvalidRefPosition);
2767 4602
            }
2768 4603
        }
2769 4604
    } else if containsRef(ty) {
2770 4605
        throw emitError(self, node, ErrorKind::InvalidRefPosition);
2789 4624
    }
2790 4625
    try validateValueTypeReferences(self, node, ty);
2791 4626
    return ty;
2792 4627
}
2793 4628
4629 +
/// Resolve a nested value type according to its syntax context.
4630 +
fn resolveContextualValueType(
4631 +
    self: *mut Resolver,
4632 +
    node: *ast::Node,
4633 +
    context: TypeSyntaxContext,
4634 +
) -> Type throws (ResolveError) {
4635 +
    if let case TypeSyntaxContext::Symbolic = context {
4636 +
        return try resolveTypeSyntax(self, node, context);
4637 +
    }
4638 +
    return try resolveValueType(self, node);
4639 +
}
4640 +
2794 4641
/// Analyze a node's type and check that it can be assigned to the expected type.
2795 4642
fn checkAssignable(self: *mut Resolver, node: *ast::Node, expected: Type) -> Type throws (ResolveError) {
2796 4643
    let actual = try visit(self, node, expected);
2797 4644
    let _ = try expectAssignable(self, expected, actual, node);
2798 4645
    return actual;
2811 4658
        case ast::NodeValue::Ident(name) => {
2812 4659
            let sym = findAnySymbol(self.scope, name)
2813 4660
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
2814 4661
            setNodeSymbol(self, node, sym);
2815 4662
            match sym.data {
2816 -
                case SymbolData::Value { type, .. } =>
2817 -
                    return setNodeType(self, node, type),
4663 +
                case SymbolData::Value { type, .. } => {
4664 +
                    if isGenericDeclaration(sym.node) {
4665 +
                        throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4666 +
                    }
4667 +
                    return setNodeType(self, node, type);
4668 +
                }
2818 4669
                case SymbolData::Constant { type, value } => {
2819 4670
                    if let val = value {
2820 4671
                        setNodeConstValue(self, node, val);
2821 4672
                    }
2822 4673
                    return setNodeType(self, node, type);
2823 4674
                },
2824 -
                case SymbolData::Type(t) =>
2825 -
                    return setNodeType(self, node, Type::Nominal(t)),
4675 +
                case SymbolData::Type(t) => {
4676 +
                    if isGenericDeclaration(sym.node) {
4677 +
                        throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4678 +
                    }
4679 +
                    return setNodeType(self, node, Type::Nominal(t));
4680 +
                }
4681 +
                case SymbolData::TypeParameter(param) => {
4682 +
                    set *param.used = true;
4683 +
                    return setNodeType(self, node, Type::Parameter(param));
4684 +
                }
4685 +
                case SymbolData::ConstParameter(param) => {
4686 +
                    set *param.used = true;
4687 +
                    let ty = param.constType else {
4688 +
                        throw emitError(self, node, ErrorKind::Internal);
4689 +
                    };
4690 +
                    return setNodeType(self, node, *ty);
4691 +
                }
2826 4692
                case SymbolData::Variant { .. } =>
2827 4693
                    return Type::Void,
2828 4694
                case SymbolData::Module { .. } =>
2829 4695
                    throw emitError(self, node, ErrorKind::UnexpectedModuleName),
2830 4696
                case SymbolData::Trait(_) =>
2831 4697
                    throw emitError(self, node, ErrorKind::UnexpectedTraitName),
2832 4698
            }
2833 4699
        },
2834 -
        case ast::NodeValue::Call(call) => return try resolveCall(self, node, call, CallCtx::Normal),
4700 +
        case ast::NodeValue::Call(call) =>
4701 +
            return try resolveCall(self, node, call, CallCtx::Normal, hint),
2835 4702
        case ast::NodeValue::FieldAccess(access) => return try resolveFieldAccess(self, node, access),
2836 4703
        case ast::NodeValue::BinOp(binop) => return try resolveBinOp(self, node, binop),
2837 4704
        case ast::NodeValue::Block(block) => return try resolveBlock(self, node, block),
4705 +
        case ast::NodeValue::FnDecl(decl) => {
4706 +
            if decl.params.len > 0 {
4707 +
                throw emitError(self, node, ErrorKind::GenericFnNested);
4708 +
            }
4709 +
            throw emitError(self, node, ErrorKind::UnexpectedNode(node));
4710 +
        }
2838 4711
        case ast::NodeValue::Let(decl) => return try resolveLet(self, node, decl),
2839 4712
        case ast::NodeValue::ConstDecl(decl) => return try resolveConstOrStatic(
2840 4713
            self, node, decl.ident, decl.type, decl.value, decl.attrs, true
2841 4714
        ),
2842 4715
        case ast::NodeValue::StaticDecl(decl) => return try resolveConstOrStatic(
2871 4744
        case ast::NodeValue::Assign(assign) => return try resolveAssign(self, node, assign),
2872 4745
        case ast::NodeValue::RecordLit(lit) => return try resolveRecordLit(self, node, lit, hint),
2873 4746
        case ast::NodeValue::ArrayLit(items) => return try resolveArrayLit(self, node, items, hint),
2874 4747
        case ast::NodeValue::ArrayRepeatLit(lit) => return try resolveArrayRepeat(self, node, lit, hint),
2875 4748
        case ast::NodeValue::Subscript { container, index } => return try resolveSubscript(self, node, container, index),
4749 +
        case ast::NodeValue::GenericApply(app) => {
4750 +
            let fnType = try resolveGenericFnApply(self, node, app, false);
4751 +
            return setNodeType(self, node, Type::Fn(fnType));
4752 +
        }
4753 +
        case ast::NodeValue::Instantiate(_) =>
4754 +
            throw emitError(self, node, ErrorKind::GenericUnsupported),
2876 4755
        case ast::NodeValue::ScopeAccess(access) => return try resolveScopeAccess(self, node, access),
2877 4756
        case ast::NodeValue::AddressOf(addr) => return try resolveAddressOf(self, node, addr, hint),
2878 4757
        case ast::NodeValue::Deref(target) => return try resolveDeref(self, node, target, hint),
2879 4758
        case ast::NodeValue::As(expr) => return try resolveAs(self, node, expr),
2880 4759
        case ast::NodeValue::Range(range) => return try resolveRange(self, node, range),
2881 4760
        case ast::NodeValue::Try(expr) => return try resolveTry(self, node, expr, hint),
2882 4761
        case ast::NodeValue::Return { value } => return try resolveReturn(self, node, value),
2883 4762
        case ast::NodeValue::Throw { expr } => return try resolveThrow(self, node, expr),
2884 4763
        case ast::NodeValue::Panic { message } => {
2885 -
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
4764 +
            // TODO: Have easy access to string type.
4765 +
            try visitOptional(self, message, Type::Slice(SliceType {
2886 4766
                class: types::PointerClass::Owned,
2887 4767
                item: allocType(self, Type::U8),
2888 4768
                mutable: false,
2889 -
            });
4769 +
            }));
2890 4770
            return setNodeType(self, node, Type::Never);
2891 4771
        },
2892 4772
        case ast::NodeValue::Assert { condition, message } => {
2893 4773
            try visit(self, condition, Type::Bool);
2894 -
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
4774 +
            // TODO: Have easy access to string type.
4775 +
            try visitOptional(self, message, Type::Slice(SliceType {
2895 4776
                class: types::PointerClass::Owned,
2896 4777
                item: allocType(self, Type::U8),
2897 4778
                mutable: false,
2898 -
            });
4779 +
            }));
2899 4780
            return setNodeType(self, node, Type::Void);
2900 4781
        },
2901 4782
        case ast::NodeValue::UnOp(unop) => return try resolveUnOp(self, node, unop),
2902 4783
        case ast::NodeValue::ExprStmt(expr) => {
2903 4784
            // Pass `Void` as expected type to indicate value is discarded.
2904 4785
            let exprTy = try visit(self, expr, Type::Void);
2905 4786
            return setNodeType(self, node, unifyBranches(exprTy, Type::Void));
2906 4787
        },
2907 -
        case ast::NodeValue::TypeSig(sig) => return try inferTypeSig(self, node, sig),
4788 +
        case ast::NodeValue::TypeSig(_) =>
4789 +
            return try resolveTypeSyntax(self, node, TypeSyntaxContext::Concrete),
2908 4790
        case ast::NodeValue::Super => {
2909 4791
            // `super` by itself is invalid, must be used in scope access.
2910 4792
            throw emitError(self, node, ErrorKind::InvalidModulePath);
2911 4793
        },
2912 4794
        case ast::NodeValue::Nil => {
2928 4810
            return setNodeType(self, node, Type::U8);
2929 4811
        }
2930 4812
        case ast::NodeValue::String(text) => {
2931 4813
            setNodeConstValue(self, node, ConstValue::String(text));
2932 4814
            let byteTy = allocType(self, Type::U8);
2933 -
            let sliceTy = allocType(self, Type::Slice {
4815 +
            let sliceTy = allocType(self, Type::Slice(SliceType {
2934 4816
                class: types::PointerClass::Owned,
2935 4817
                item: byteTy,
2936 4818
                mutable: false,
2937 -
            });
4819 +
            }));
2938 4820
            return setNodeType(self, node, *sliceTy);
2939 4821
        },
2940 4822
        case ast::NodeValue::Number(lit) => {
2941 4823
            setNodeConstValue(self, node, ConstValue::Int(ConstInt {
2942 4824
                magnitude: lit.magnitude,
3107 4989
        },
3108 4990
        case ast::NodeValue::AddressOf(addr) => {
3109 4991
            let ty = typeFor(self, node) else {
3110 4992
                return false;
3111 4993
            };
3112 -
            if let case Type::Slice { .. } = ty {
4994 +
            if let case Type::Slice(_) = ty {
3113 4995
                return isConstExpr(self, addr.target);
3114 4996
            }
3115 4997
            return false;
3116 4998
        },
3117 4999
        case ast::NodeValue::RecordLit(lit) => {
3130 5012
            // Identifiers and scope accesses referencing constants, union
3131 5013
            // variants, or function values are constant expressions.
3132 5014
            if let sym = symbolFor(self, node) {
3133 5015
                match sym.data {
3134 5016
                    case SymbolData::Variant { .. },
3135 -
                         SymbolData::Constant { .. } => return true,
5017 +
                         SymbolData::Constant { .. },
5018 +
                         SymbolData::ConstParameter(_) => return true,
3136 5019
                    case SymbolData::Value { type, .. } => {
3137 5020
                        if let case Type::Fn(_) = type {
3138 5021
                            return true;
3139 5022
                        }
3140 5023
                    }
3201 5084
        case IntegerRange::Signed { bits, .. } =>
3202 5085
            return ConstValue::Int(constIntFromBits(raw, bits, true)),
3203 5086
    }
3204 5087
}
3205 5088
5089 +
/// Return whether a constant expression depends on a rigid constant parameter.
5090 +
fn containsGenericConstExpr(self: *Resolver, node: *ast::Node) -> bool {
5091 +
    match node.value {
5092 +
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) => {
5093 +
            let sym = symbolFor(self, node) else return false;
5094 +
            if let case SymbolData::ConstParameter(_) = sym.data {
5095 +
                return true;
5096 +
            }
5097 +
            return false;
5098 +
        }
5099 +
        case ast::NodeValue::BinOp(binop) =>
5100 +
            return containsGenericConstExpr(self, binop.left) or
5101 +
                   containsGenericConstExpr(self, binop.right),
5102 +
        case ast::NodeValue::UnOp(unop) =>
5103 +
            return containsGenericConstExpr(self, unop.value),
5104 +
        case ast::NodeValue::As(expr) =>
5105 +
            return containsGenericConstExpr(self, expr.value),
5106 +
        else => return false,
5107 +
    }
5108 +
}
5109 +
5110 +
/// Evaluate an integer constant expression after replacing rigid parameters.
5111 +
fn constValueWithSubstitution(
5112 +
    self: *Resolver,
5113 +
    node: *ast::Node,
5114 +
    sub: *Substitution,
5115 +
) -> ?ConstValue {
5116 +
    if let value = constValueEntry(self, node) {
5117 +
        return value;
5118 +
    }
5119 +
    match node.value {
5120 +
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) => {
5121 +
            let sym = symbolFor(self, node) else return nil;
5122 +
            let case SymbolData::ConstParameter(param) = sym.data else return nil;
5123 +
            let arg = substitutionArg(sub, param);
5124 +
            let case Type::ConstArgument { value, .. } = arg else return nil;
5125 +
            return ConstValue::Int(value);
5126 +
        }
5127 +
        case ast::NodeValue::BinOp(binop) => {
5128 +
            let left = constValueWithSubstitution(self, binop.left, sub)
5129 +
                else return nil;
5130 +
            let right = constValueWithSubstitution(self, binop.right, sub)
5131 +
                else return nil;
5132 +
            let case ConstValue::Int(leftInt) = left else return nil;
5133 +
            let case ConstValue::Int(rightInt) = right else return nil;
5134 +
            return foldIntBinOp(binop.op, leftInt, rightInt);
5135 +
        }
5136 +
        case ast::NodeValue::UnOp(unop) => {
5137 +
            let value = constValueWithSubstitution(self, unop.value, sub)
5138 +
                else return nil;
5139 +
            match unop.op {
5140 +
                case ast::UnaryOp::Not => {
5141 +
                    let case ConstValue::Bool(v) = value else return nil;
5142 +
                    return ConstValue::Bool(not v);
5143 +
                }
5144 +
                case ast::UnaryOp::Neg => {
5145 +
                    let case ConstValue::Int(v) = value else return nil;
5146 +
                    return constInt(v.magnitude, v.bits, true, not v.negative);
5147 +
                }
5148 +
                case ast::UnaryOp::BitNot => {
5149 +
                    let case ConstValue::Int(v) = value else return nil;
5150 +
                    return ConstValue::Int(
5151 +
                        constIntFromSigned(
5152 +
                            -(constIntToSigned(v) + 1), v.bits, v.signed
5153 +
                        )
5154 +
                    );
5155 +
                }
5156 +
            }
5157 +
        }
5158 +
        case ast::NodeValue::As(expr) => {
5159 +
            let value = constValueWithSubstitution(self, expr.value, sub)
5160 +
                else return nil;
5161 +
            let case ConstValue::Int(v) = value else return nil;
5162 +
            let target = typeFor(self, node) else return nil;
5163 +
            if integerRange(target) == nil {
5164 +
                return nil;
5165 +
            }
5166 +
            return castConstInt(v, target);
5167 +
        }
5168 +
        else => return nil,
5169 +
    }
5170 +
}
5171 +
5172 +
/// Evaluate and canonicalize an integer constant under a generic substitution.
5173 +
///
5174 +
/// This read-only query is used by lowering to reconstruct concrete structural
5175 +
/// types in its own arena after resolution has validated every specialization.
5176 +
export fn constIntWithSubstitution(
5177 +
    self: *Resolver,
5178 +
    node: *ast::Node,
5179 +
    target: Type,
5180 +
    sub: *Substitution,
5181 +
) -> ?ConstInt {
5182 +
    let value = constValueWithSubstitution(self, node, sub) else return nil;
5183 +
    let case ConstValue::Int(int) = value else return nil;
5184 +
    if not validateConstIntRange(value, target) {
5185 +
        return nil;
5186 +
    }
5187 +
    let case ConstValue::Int(canonical) = castConstInt(int, target)
5188 +
        else return nil;
5189 +
    return canonical;
5190 +
}
5191 +
3206 5192
/// Return the constant `u32` value for a slice bound when known.
3207 5193
fn constSliceIndex(self: *mut Resolver, node: *ast::Node) -> ?u32 {
3208 5194
    let value = constValueEntry(self, node)
3209 5195
        else return nil;
3210 5196
    let case ConstValue::Int(int) = value
3299 5285
        if not isConstExpr(self, valueNode) {
3300 5286
            throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
3301 5287
        }
3302 5288
        try bindValueIdent(self, ident, node, bindingTy, true, 0, attrs);
3303 5289
    }
3304 -
    setNodeType(self, valueNode, bindingTy);
5290 +
    setNodeType(self, valueNode, bindingTy);
5291 +
5292 +
    return Type::Void;
5293 +
}
5294 +
5295 +
/// Bind one declaration's rigid generic parameters in its child scope.
5296 +
fn resolveGenericParams(
5297 +
    self: *mut Resolver,
5298 +
    owner: *ast::Node,
5299 +
    nodes: *mut [*ast::Node],
5300 +
) -> *[*GenericParamType] throws (ResolveError) {
5301 +
    if nodes.len > MAX_GENERIC_PARAMS {
5302 +
        throw emitError(self, owner, ErrorKind::GenericParameterLimit);
5303 +
    }
5304 +
    let a = alloc::arenaAllocator(&mut self.arena);
5305 +
    let mut result: *mut [*GenericParamType] = &mut [];
5306 +
    for paramNode, index in nodes {
5307 +
        let case ast::NodeValue::GenericParam(param) = paramNode.value
5308 +
            else throw emitError(self, paramNode, ErrorKind::Internal);
5309 +
        let mut paramName: *[u8] = undefined;
5310 +
        let mut nameNode: *ast::Node = undefined;
5311 +
        let mut traitBounds: *mut [*TraitType] = &mut [];
5312 +
        let mut constType: ?*Type = nil;
5313 +
        match param {
5314 +
            case ast::GenericParam::Const { name, type } => {
5315 +
                set nameNode = name;
5316 +
                set paramName = try nodeName(self, name);
5317 +
                let ty = try resolveValueType(self, type);
5318 +
                if integerRange(ty) == nil or ty == Type::Int {
5319 +
                    throw emitError(self, type, ErrorKind::GenericConstUnsupported);
5320 +
                }
5321 +
                set constType = allocType(self, ty);
5322 +
            }
5323 +
            case ast::GenericParam::Type { name, bounds } => {
5324 +
                set nameNode = name;
5325 +
                set paramName = try nodeName(self, name);
5326 +
                for bound in bounds {
5327 +
                    let boundSym = try resolveNamePath(self, bound);
5328 +
                    let case SymbolData::Trait(traitInfo) = boundSym.data else {
5329 +
                        throw emitError(self, bound, ErrorKind::GenericBoundNotTrait);
5330 +
                    };
5331 +
                    setNodeSymbol(self, bound, boundSym);
5332 +
                    traitBounds.append(traitInfo, a);
5333 +
                }
5334 +
            }
5335 +
        }
5336 +
        let used = try! alloc::alloc(
5337 +
            &mut self.arena, @sizeOf(bool), @alignOf(bool)
5338 +
        ) as *mut bool;
5339 +
        set *used = false;
5340 +
        let p = try! alloc::alloc(
5341 +
            &mut self.arena,
5342 +
            @sizeOf(GenericParamType),
5343 +
            @alignOf(GenericParamType),
5344 +
        ) as *mut GenericParamType;
5345 +
        set *p = GenericParamType {
5346 +
            owner,
5347 +
            node: paramNode,
5348 +
            name: paramName,
5349 +
            index,
5350 +
            bounds: &traitBounds[..],
5351 +
            used,
5352 +
            constType,
5353 +
        };
5354 +
        let data = SymbolData::ConstParameter(p) if constType <> nil
5355 +
            else SymbolData::TypeParameter(p);
5356 +
        let sym = try bindIdent(
5357 +
            self, paramName, paramNode, data, 0, self.scope
5358 +
        );
5359 +
        setNodeSymbol(self, nameNode, sym);
5360 +
        if let ty = constType {
5361 +
            setNodeType(self, nameNode, *ty);
5362 +
            setNodeType(self, paramNode, *ty);
5363 +
        } else {
5364 +
            setNodeType(self, nameNode, Type::Parameter(p));
5365 +
            setNodeType(self, paramNode, Type::Parameter(p));
5366 +
        }
5367 +
        result.append(p, a);
5368 +
    }
5369 +
    return &result[..];
5370 +
}
5371 +
5372 +
/// Retrieve sparse metadata for a generic declaration symbol.
5373 +
export fn genericTemplateFor(self: *Resolver, symbol: *Symbol) -> ?*GenericTemplate {
5374 +
    let mut cursor = self.genericTemplates;
5375 +
    while let template = cursor {
5376 +
        if template.symbol == symbol {
5377 +
            return template;
5378 +
        }
5379 +
        set cursor = template.next;
5380 +
    }
5381 +
    return nil;
5382 +
}
5383 +
5384 +
/// Retrieve mutable sparse metadata for resolver-owned bookkeeping.
5385 +
fn genericTemplateForMut(
5386 +
    self: *mut Resolver,
5387 +
    symbol: *Symbol,
5388 +
) -> ?*mut GenericTemplate {
5389 +
    let mut cursor = self.genericTemplates;
5390 +
    while let template = cursor {
5391 +
        if template.symbol == symbol {
5392 +
            return template;
5393 +
        }
5394 +
        set cursor = template.next;
5395 +
    }
5396 +
    return nil;
5397 +
}
5398 +
5399 +
/// Return the generic template whose symbolic body is currently being checked.
5400 +
fn currentGenericTemplateSymbol(self: *Resolver) -> ?*mut Symbol {
5401 +
    let current = self.currentGenericTemplate else return nil;
5402 +
    return current.symbol;
5403 +
}
5404 +
5405 +
/// Attach generic metadata without increasing every symbol's allocation.
5406 +
fn registerGenericTemplate(
5407 +
    self: *mut Resolver,
5408 +
    template: GenericTemplate,
5409 +
) -> *mut GenericTemplate {
5410 +
    let entry = try! alloc::alloc(
5411 +
        &mut self.arena,
5412 +
        @sizeOf(GenericTemplate),
5413 +
        @alignOf(GenericTemplate),
5414 +
    ) as *mut GenericTemplate;
5415 +
    set *entry = template;
5416 +
    set entry.next = self.genericTemplates;
5417 +
    set self.genericTemplates = entry;
5418 +
    return entry;
5419 +
}
5420 +
5421 +
/// Resolve a function signature type without laying out generic aggregates.
5422 +
fn resolveFnSignatureType(
5423 +
    self: *mut Resolver,
5424 +
    node: *ast::Node,
5425 +
    context: TypeSyntaxContext,
5426 +
) -> Type throws (ResolveError) {
5427 +
    if let case TypeSyntaxContext::Symbolic = context {
5428 +
        return try resolveTypeSyntax(self, node, context);
5429 +
    }
5430 +
    return try infer(self, node);
5431 +
}
3305 5432
3306 -
    return Type::Void;
5433 +
/// Resolve and bind a function parameter using its signature mode.
5434 +
fn resolveFnSignatureParam(
5435 +
    self: *mut Resolver,
5436 +
    node: *ast::Node,
5437 +
    context: TypeSyntaxContext,
5438 +
) -> Type throws (ResolveError) {
5439 +
    if let case TypeSyntaxContext::Concrete = context {
5440 +
        return try infer(self, node);
5441 +
    }
5442 +
    let case ast::NodeValue::FnParam(param) = node.value
5443 +
        else throw emitError(self, node, ErrorKind::Internal);
5444 +
    let ty = try resolveTypeSyntax(self, param.type, context);
5445 +
    let _ = try bindValueIdent(self, param.name, node, ty, false, 0, 0);
5446 +
    return setNodeType(self, node, ty);
3307 5447
}
3308 5448
3309 5449
/// Analyze a function declaration signature and bind the function name.
3310 5450
fn resolveFnDecl(self: *mut Resolver, node: *ast::Node, decl: ast::FnDecl) -> Type
3311 5451
    throws (ResolveError)
3312 5452
{
3313 5453
    let attrMask = resolveAttributes(self, decl.attrs);
3314 -
    let mut retTy = Type::Void;
3315 -
    if let retNode = decl.sig.returnType {
3316 -
        set retTy = try infer(self, retNode);
3317 -
        try ensureStorableType(self, retNode, retTy);
5454 +
    if decl.params.len > 0 {
5455 +
        if self.currentFn <> nil {
5456 +
            throw emitError(self, node, ErrorKind::GenericFnNested);
5457 +
        }
5458 +
        if ast::hasAttribute(attrMask, ast::Attribute::Extern)
5459 +
            or ast::hasAttribute(attrMask, ast::Attribute::Default)
5460 +
            or ast::hasAttribute(attrMask, ast::Attribute::Intrinsic)
5461 +
        {
5462 +
            throw emitError(self, node, ErrorKind::GenericFnAttribute);
5463 +
        }
3318 5464
    }
3319 5465
    let a = alloc::arenaAllocator(&mut self.arena);
3320 5466
    let mut paramTypes: *mut [*Type] = &mut [];
3321 5467
    let mut throwList: *mut [*Type] = &mut [];
3322 5468
    let mut fnType = FnType {
3323 5469
        paramTypes: &[],
3324 -
        returnType: allocType(self, retTy),
5470 +
        returnType: allocType(self, Type::Void),
3325 5471
        throwList: &[],
3326 5472
        isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe),
3327 5473
        localCount: 0,
3328 5474
    };
3329 -
    // Enter the function scope to process parameters.
3330 5475
    enterFn(self, node, &fnType);
3331 5476
5477 +
    let genericParams = try resolveGenericParams(self, node, decl.params) catch e {
5478 +
        exitFn(self);
5479 +
        throw e;
5480 +
    };
5481 +
    let typeContext = TypeSyntaxContext::Symbolic if genericParams.len > 0
5482 +
        else TypeSyntaxContext::Concrete;
5483 +
    if let retNode = decl.sig.returnType {
5484 +
        let retTy = try resolveFnSignatureType(
5485 +
            self, retNode, typeContext
5486 +
        ) catch e {
5487 +
            exitFn(self);
5488 +
            throw e;
5489 +
        };
5490 +
        try ensureStorableType(self, retNode, retTy) catch e {
5491 +
            exitFn(self);
5492 +
            throw e;
5493 +
        };
5494 +
        set fnType.returnType = allocType(self, retTy);
5495 +
    }
3332 5496
    if decl.sig.params.len > MAX_FN_PARAMS {
3333 5497
        exitFn(self);
3334 5498
        throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
3335 5499
            expected: MAX_FN_PARAMS,
3336 5500
            actual: decl.sig.params.len,
3337 5501
        }));
3338 5502
    }
3339 5503
    for paramNode in decl.sig.params {
3340 -
        let paramTy = try infer(self, paramNode) catch e {
5504 +
        let paramTy = try resolveFnSignatureParam(
5505 +
            self, paramNode, typeContext
5506 +
        ) catch e {
3341 5507
            exitFn(self);
3342 5508
            throw e;
3343 5509
        };
3344 5510
        paramTypes.append(allocType(self, paramTy), a);
3345 5511
    }
3350 5516
            expected: MAX_FN_THROWS,
3351 5517
            actual: decl.sig.throwList.len,
3352 5518
        }));
3353 5519
    }
3354 5520
    for throwNode in decl.sig.throwList {
3355 -
        let throwTy = try infer(self, throwNode) catch e {
5521 +
        let throwTy = try resolveFnSignatureType(
5522 +
            self, throwNode, typeContext
5523 +
        ) catch e {
5524 +
            exitFn(self);
5525 +
            throw e;
5526 +
        };
5527 +
        try ensureStorableType(self, throwNode, throwTy) catch e {
3356 5528
            exitFn(self);
3357 5529
            throw e;
3358 5530
        };
3359 5531
        throwList.append(allocType(self, throwTy), a);
3360 -
        try ensureStorableType(self, throwNode, throwTy);
3361 5532
    }
3362 5533
    exitFn(self);
3363 5534
    set fnType.paramTypes = &paramTypes[..];
3364 5535
    set fnType.throwList = &throwList[..];
3365 5536
3366 -
    // Bind the function name.
3367 -
    let ty = Type::Fn(allocFnType(self, fnType));
5537 +
    let fnInfo = allocFnType(self, fnType);
5538 +
    let ty = Type::Fn(fnInfo);
3368 5539
    let sym = try bindValueIdent(self, decl.name, node, ty, false, 0, attrMask)
3369 5540
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
3370 5541
5542 +
    if genericParams.len > 0 {
5543 +
        registerGenericTemplate(self, GenericTemplate {
5544 +
            symbol: sym,
5545 +
            params: genericParams,
5546 +
            signature: fnInfo,
5547 +
            members: &[],
5548 +
            declaredLinear: false,
5549 +
            bodyResolved: false,
5550 +
            typeUses: &mut [],
5551 +
            next: nil,
5552 +
        });
5553 +
    }
3371 5554
    return ty;
3372 5555
}
3373 5556
3374 5557
/// Analyze a function body.
3375 5558
fn resolveFnDeclBody(self: *mut Resolver, node: *ast::Node, decl: ast::FnDecl) throws (ResolveError) {
3376 5559
    let sym = symbolFor(self, node) else {
3377 5560
        // The function declaration failed to type check, therefore
3378 5561
        // no symbol was associated with it.
3379 5562
        return;
3380 5563
    };
5564 +
    let generic = genericTemplateForMut(self, sym);
5565 +
    if let template = generic {
5566 +
        if template.bodyResolved {
5567 +
            return;
5568 +
        }
5569 +
        set template.bodyResolved = true;
5570 +
    }
3381 5571
    let case SymbolData::Value { type: Type::Fn(fnType), .. } = sym.data else {
3382 5572
        panic "resolveFnDeclBody: unexpected symbol data for function";
3383 5573
    };
3384 5574
    let retTy = *fnType.returnType;
3385 5575
    let isExtern = ast::hasAttribute(sym.attrs, ast::Attribute::Extern);
3395 5585
        }
3396 5586
        if isUnsafe {
3397 5587
            set self.unsafeDepth += 1;
3398 5588
        }
3399 5589
        enterFn(self, node, fnType); // Enter function scope for body analysis.
5590 +
        set self.currentGenericTemplate = generic;
3400 5591
3401 5592
        let bodyTy = try checkAssignable(self, body, Type::Void) catch e {
5593 +
            set self.currentGenericTemplate = nil;
3402 5594
            exitFn(self);
3403 5595
            if isUnsafe { set self.unsafeDepth -= 1; }
3404 5596
            throw e;
3405 5597
        };
3406 5598
        if retTy <> Type::Void and bodyTy <> Type::Never {
5599 +
            set self.currentGenericTemplate = nil;
3407 5600
            exitFn(self);
3408 5601
            if isUnsafe { set self.unsafeDepth -= 1; }
3409 5602
            throw emitError(self, body, ErrorKind::FnMissingReturn);
3410 5603
        }
5604 +
        set self.currentGenericTemplate = nil;
3411 5605
        exitFn(self);
3412 5606
        if isUnsafe {
3413 5607
            set self.unsafeDepth -= 1;
3414 5608
        }
5609 +
5610 +
        if let entry = generic {
5611 +
            for param in entry.params {
5612 +
                if not *param.used {
5613 +
                    throw emitError(
5614 +
                        self,
5615 +
                        param.node,
5616 +
                        ErrorKind::GenericFnUnusedParameter(param.name),
5617 +
                    );
5618 +
                }
5619 +
            }
5620 +
        }
3415 5621
    } else if not isExtern {
3416 5622
        throw emitError(self, node, ErrorKind::FnMissingBody);
3417 5623
    }
3418 5624
}
3419 5625
3445 5651
        }
3446 5652
    }
3447 5653
    return linear;
3448 5654
}
3449 5655
3450 -
/// Resolve record fields from a node list.
3451 -
fn resolveRecordFields(self: *mut Resolver, node: *ast::Node, fields: *mut [*ast::Node], labeled: bool) -> RecordType
3452 -
    throws (ResolveError)
3453 -
{
3454 -
    let a = alloc::arenaAllocator(&mut self.arena);
3455 -
    let mut result: *mut [RecordField] = &mut [];
3456 -
    let mut currentOffset: u32 = 0;
3457 -
    let mut maxAlignment: u32 = 1;
3458 -
3459 -
    if fields.len > parser::MAX_RECORD_FIELDS {
3460 -
        throw emitError(self, node, ErrorKind::Internal);
3461 -
    }
3462 -
    // TODO: Add cycle detection to catch invalid recursive types like `record A { a: A }`.
3463 -
    for field in fields {
3464 -
        let case ast::NodeValue::RecordField {
3465 -
            field: fieldNode,
3466 -
            type: typeNode,
3467 -
            value: valueNode
3468 -
        } = field.value else panic "resolveRecordFields: invalid record field";
3469 -
        let fieldTy = try resolveValueType(self, typeNode);
3470 -
        try ensureStorableType(self, typeNode, fieldTy);
3471 -
3472 -
        if let v = valueNode {
3473 -
            let _valTy = try checkAssignable(self, v, fieldTy);
5656 +
/// Resolve one symbolic generic data member.
5657 +
fn resolveGenericDataMember(
5658 +
    self: *mut Resolver,
5659 +
    member: *ast::Node,
5660 +
) -> Type throws (ResolveError) {
5661 +
    match member.value {
5662 +
        case ast::NodeValue::RecordField { type, value, .. } => {
5663 +
            let ty = try resolveTypeSyntax(
5664 +
                self, type, TypeSyntaxContext::Symbolic
5665 +
            );
5666 +
            try ensureStorableType(self, type, ty);
5667 +
            if let initializer = value {
5668 +
                let _ = try checkAssignable(self, initializer, ty);
5669 +
            }
5670 +
            return ty;
3474 5671
        }
3475 -
        // Get field name for labeled records.
3476 -
        let mut fieldName: ?*[u8] = nil;
3477 -
        if labeled {
3478 -
            let n = fieldNode
3479 -
                else panic "resolveRecordFields: labeled record field missing name";
3480 -
            set fieldName = try nodeName(self, n);
5672 +
        case ast::NodeValue::UnionDeclVariant(variant) => {
5673 +
            let mut ty = Type::Void;
5674 +
            if let type = variant.type {
5675 +
                set ty = try resolveTypeSyntax(
5676 +
                    self, type, TypeSyntaxContext::Symbolic
5677 +
                );
5678 +
                try ensureStorableType(self, type, ty);
5679 +
            }
5680 +
            if let value = variant.value {
5681 +
                let _ = try checkNumeric(self, value);
5682 +
                if constValueEntry(self, value) == nil and
5683 +
                   (not isConstExpr(self, value) or
5684 +
                    not containsGenericConstExpr(self, value))
5685 +
                {
5686 +
                    throw emitError(
5687 +
                        self, value, ErrorKind::ConstExprRequired
5688 +
                    );
5689 +
                }
5690 +
            }
5691 +
            return ty;
3481 5692
        }
3482 -
        let fieldType = typeFor(self, typeNode)
3483 -
            else throw emitError(self, typeNode, ErrorKind::CannotInferType);
3484 -
3485 -
        // Ensure field type is fully resolved before computing layout.
3486 -
        try ensureTypeResolved(self, fieldType, typeNode);
3487 -
3488 -
        // Compute field offset by aligning to field's alignment.
3489 -
        let fieldLayout = getTypeLayout(fieldType);
3490 -
        set currentOffset = mem::alignUp(currentOffset, fieldLayout.alignment);
3491 -
3492 -
        result.append(RecordField { name: fieldName, fieldType, offset: currentOffset as i32 }, a);
3493 -
3494 -
        // Advance offset past this field.
3495 -
        set currentOffset += fieldLayout.size;
5693 +
        else => panic "resolveGenericDataMember: invalid member",
5694 +
    }
5695 +
}
3496 5696
3497 -
        // Track max alignment for record layout.
3498 -
        set maxAlignment = max(maxAlignment, fieldLayout.alignment);
5697 +
/// Resolve symbolic field or variant types for a generic data template.
5698 +
fn resolveGenericDataTemplate(
5699 +
    self: *mut Resolver,
5700 +
    node: *ast::Node,
5701 +
    params: *mut [*ast::Node],
5702 +
    members: *mut [*ast::Node],
5703 +
    derives: *mut [*ast::Node],
5704 +
) throws (ResolveError) {
5705 +
    let sym = symbolFor(self, node) else return;
5706 +
    if genericTemplateFor(self, sym) <> nil {
5707 +
        return;
3499 5708
    }
3500 -
    // Compute cached layout.
3501 -
    let recordLayout = Layout {
3502 -
        size: mem::alignUp(currentOffset, maxAlignment),
3503 -
        alignment: maxAlignment
5709 +
    enterScope(self, node);
5710 +
    let genericParams = try resolveGenericParams(self, node, params) catch e {
5711 +
        exitScope(self);
5712 +
        throw e;
3504 5713
    };
3505 -
    return RecordType {
3506 -
        fields: &result[..],
3507 -
        labeled,
3508 -
        layout: recordLayout,
3509 -
        declaredLinear: false,
5714 +
    let declaredLinear = try resolveLinearDerive(self, derives) catch e {
5715 +
        exitScope(self);
5716 +
        throw e;
3510 5717
    };
5718 +
    // Publish the rigid parameters before resolving members so recursive and
5719 +
    // mutually recursive applications can observe the in-progress template.
5720 +
    let metadata = registerGenericTemplate(self, GenericTemplate {
5721 +
        symbol: sym,
5722 +
        params: genericParams,
5723 +
        signature: nil,
5724 +
        members: &[],
5725 +
        declaredLinear,
5726 +
        bodyResolved: true,
5727 +
        typeUses: &mut [],
5728 +
        next: nil,
5729 +
    });
5730 +
    let a = alloc::arenaAllocator(&mut self.arena);
5731 +
    let mut memberTypes: *mut [*Type] = &mut [];
5732 +
    for member in members {
5733 +
        let memberTy = try resolveGenericDataMember(self, member) catch e {
5734 +
            exitScope(self);
5735 +
            throw e;
5736 +
        };
5737 +
        memberTypes.append(allocType(self, memberTy), a);
5738 +
    }
5739 +
    exitScope(self);
5740 +
    set metadata.members = &memberTypes[..];
3511 5741
}
3512 5742
3513 5743
/// Resolve record field types for a named record declaration.
3514 5744
fn resolveRecordBody(self: *mut Resolver, node: *ast::Node, decl: ast::RecordDecl)
3515 5745
    throws (ResolveError)
3524 5754
    // Skip if already resolved.
3525 5755
    if let case NominalType::Record(_) = *nominalTy {
3526 5756
        return;
3527 5757
    }
3528 5758
    let declaredLinear = try resolveLinearDerive(self, decl.derives);
3529 -
    let mut recordType = try resolveRecordFields(self, node, decl.fields, decl.labeled);
3530 -
    set recordType.declaredLinear = declaredLinear;
5759 +
    let recordType = try buildRecordType(
5760 +
        self,
5761 +
        node,
5762 +
        decl.fields,
5763 +
        decl.labeled,
5764 +
        declaredLinear,
5765 +
        AggregateMemberSource::Ordinary,
5766 +
    );
3531 5767
3532 5768
    set *nominalTy = NominalType::Record(recordType);
3533 5769
}
3534 5770
3535 5771
/// Bind a type name.
3545 5781
3546 5782
    return try bindTypeIdent(self, name, node, nominalTy, attrMask);
3547 5783
}
3548 5784
3549 5785
/// Allocate a trait type descriptor and return a pointer to it.
3550 -
fn allocTraitType(self: *mut Resolver, name: *[u8]) -> *mut TraitType {
5786 +
fn allocTraitType(
5787 +
    self: *mut Resolver,
5788 +
    name: *[u8],
5789 +
    node: *ast::Node,
5790 +
) -> *mut TraitType {
3551 5791
    let p = try! alloc::alloc(&mut self.arena, @sizeOf(TraitType), @alignOf(TraitType));
3552 5792
    let entry = p as *mut TraitType;
3553 -
    set *entry = TraitType { name, methods: &mut [], supertraits: &mut [] };
3554 5793
5794 +
    let used = try! alloc::alloc(
5795 +
        &mut self.arena, @sizeOf(bool), @alignOf(bool)
5796 +
    ) as *mut bool;
5797 +
    set *used = false;
5798 +
    let selfType = try! alloc::alloc(
5799 +
        &mut self.arena, @sizeOf(GenericParamType), @alignOf(GenericParamType)
5800 +
    ) as *mut GenericParamType;
5801 +
    set *selfType = GenericParamType {
5802 +
        owner: node,
5803 +
        node,
5804 +
        name: "Self",
5805 +
        index: 0,
5806 +
        bounds: &[],
5807 +
        used,
5808 +
        constType: nil,
5809 +
    };
5810 +
    set *entry = TraitType {
5811 +
        name,
5812 +
        moduleId: self.currentMod,
5813 +
        nodeId: node.id,
5814 +
        methods: &mut [],
5815 +
        supertraits: &mut [],
5816 +
        selfType,
5817 +
        state: TraitState::Queued,
5818 +
        objectSafe: true,
5819 +
    };
3555 5820
    return entry;
3556 5821
}
3557 5822
3558 5823
/// Bind a trait name in the current scope.
3559 -
fn bindTraitName(self: *mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol
3560 -
    throws (ResolveError)
3561 -
{
5824 +
fn bindTraitName(
5825 +
    self: *mut Resolver,
5826 +
    node: *ast::Node,
5827 +
    name: *ast::Node,
5828 +
    attrs: ?ast::Attributes,
5829 +
) -> *mut Symbol throws (ResolveError) {
3562 5830
    let attrMask = resolveAttributes(self, attrs);
3563 5831
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
3564 5832
3565 5833
    let traitName = try nodeName(self, name);
3566 -
    let traitType = allocTraitType(self, traitName);
5834 +
    let traitType = allocTraitType(self, traitName, node);
3567 5835
    let data = SymbolData::Trait(traitType);
3568 5836
    let sym = try bindIdent(self, traitName, node, data, attrMask, self.scope);
3569 5837
3570 5838
    setNodeType(self, node, Type::Void);
3571 5839
    setNodeType(self, name, Type::Void);
3581 5849
        }
3582 5850
    }
3583 5851
    return nil;
3584 5852
}
3585 5853
5854 +
/// Resolve one trait signature type with the declaring trait's rigid `Self`.
5855 +
fn resolveTraitSignatureType(
5856 +
    self: *mut Resolver,
5857 +
    traitType: *TraitType,
5858 +
    node: *ast::Node,
5859 +
) -> Type throws (ResolveError) {
5860 +
    let previous = self.currentTraitSelf;
5861 +
    set self.currentTraitSelf = traitType.selfType;
5862 +
    let resolved = try resolveValueType(self, node) catch {
5863 +
        set self.currentTraitSelf = previous;
5864 +
        throw ResolveError::Failure;
5865 +
    };
5866 +
    set self.currentTraitSelf = previous;
5867 +
    return resolved;
5868 +
}
5869 +
3586 5870
/// Resolve a trait declaration body: supertrait methods, then own methods.
3587 5871
fn resolveTraitBody(self: *mut Resolver, node: *ast::Node, supertraits: *mut [*ast::Node], methods: *mut [*ast::Node])
3588 5872
    throws (ResolveError)
3589 5873
{
3590 5874
    let sym = symbolFor(self, node)
3591 5875
        else return;
3592 5876
    let case SymbolData::Trait(traitType) = sym.data
3593 5877
        else return;
3594 -
    if traitType.methods.len > 0 {
3595 -
        return;
5878 +
    match traitType.state {
5879 +
        case TraitState::Complete, TraitState::Resolving => return,
5880 +
        case TraitState::Queued => set traitType.state = TraitState::Resolving,
3596 5881
    }
3597 5882
3598 5883
    // Resolve supertrait bounds and copy their methods into this trait.
3599 5884
    for superNode in supertraits {
3600 5885
        let superSym = try resolveNamePath(self, superNode);
3601 5886
        let case SymbolData::Trait(superTrait) = superSym.data
3602 5887
            else throw emitError(self, superNode, ErrorKind::Internal);
3603 -
        // Trait bodies are otherwise resolved in source order. Recursively
3604 -
        // resolve a supertrait only when it is declared later.
3605 -
        if superSym.node.id > node.id {
3606 -
            let case ast::NodeValue::TraitDecl {
3607 -
                supertraits: inheritedTraits, methods: inheritedMethods, ..
3608 -
            } = superSym.node.value else throw emitError(self, superNode, ErrorKind::Internal);
3609 -
            try resolveTraitBody(self, superSym.node, inheritedTraits, inheritedMethods);
5888 +
        // Resolve queued supertraits before consuming their method tables.
5889 +
        match superTrait.state {
5890 +
            case TraitState::Queued => {
5891 +
                let case ast::NodeValue::TraitDecl {
5892 +
                    supertraits: inheritedTraits, methods: inheritedMethods, ..
5893 +
                } = superSym.node.value
5894 +
                    else throw emitError(self, superNode, ErrorKind::Internal);
5895 +
                try resolveTraitBody(
5896 +
                    self, superSym.node, inheritedTraits, inheritedMethods
5897 +
                );
5898 +
            }
5899 +
            case TraitState::Resolving => {
5900 +
                throw emitError(self, superNode, ErrorKind::TraitInheritanceCycle);
5901 +
            }
5902 +
            case TraitState::Complete => {}
3610 5903
        }
3611 5904
3612 5905
        setNodeSymbol(self, superNode, superSym);
3613 5906
3614 5907
        let a = alloc::arenaAllocator(&mut self.arena);
3626 5919
            traitType.methods.append(TraitMethod {
3627 5920
                name: inherited.name,
3628 5921
                fnType: inherited.fnType,
3629 5922
                mutable: inherited.mutable,
3630 5923
                receiverClass: inherited.receiverClass,
5924 +
                owner: inherited.owner,
3631 5925
                index: traitType.methods.len as u32,
3632 5926
            }, a);
3633 5927
        }
3634 5928
        traitType.supertraits.append(superTrait, a);
5929 +
        if not superTrait.objectSafe {
5930 +
            set traitType.objectSafe = false;
5931 +
        }
3635 5932
    }
3636 5933
3637 5934
    if traitType.methods.len + methods.len > ast::MAX_TRAIT_METHODS {
3638 5935
        throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
3639 5936
            expected: ast::MAX_TRAIT_METHODS,
3679 5976
                expected: MAX_FN_PARAMS,
3680 5977
                actual: sig.params.len,
3681 5978
            }));
3682 5979
        }
3683 5980
        for paramNode in sig.params {
3684 -
            let paramTy = try infer(self, paramNode);
5981 +
            let case ast::NodeValue::FnParam(param) = paramNode.value
5982 +
                else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
5983 +
            let paramTy = try resolveTraitSignatureType(self, traitType, param.type);
3685 5984
            paramTypes.append(allocType(self, paramTy), a);
3686 5985
        }
3687 5986
        if let ret = sig.returnType {
3688 -
            set retType = allocType(self, try infer(self, ret));
5987 +
            set retType = allocType(
5988 +
                self, try resolveTraitSignatureType(self, traitType, ret)
5989 +
            );
3689 5990
        }
3690 5991
        // Resolve throws list.
3691 5992
        if sig.throwList.len > MAX_FN_THROWS {
3692 5993
            throw emitError(self, methodNode, ErrorKind::FnThrowOverflow(CountMismatch {
3693 5994
                expected: MAX_FN_THROWS,
3694 5995
                actual: sig.throwList.len,
3695 5996
            }));
3696 5997
        }
3697 5998
        for throwNode in sig.throwList {
3698 -
            let throwTy = try infer(self, throwNode);
5999 +
            let throwTy = try resolveTraitSignatureType(self, traitType, throwNode);
3699 6000
            throwList.append(allocType(self, throwTy), a);
3700 6001
        }
3701 6002
        let fnType = FnType {
3702 6003
            paramTypes: &paramTypes[..],
3703 6004
            returnType: retType,
3704 6005
            throwList: &throwList[..],
3705 6006
            isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe),
3706 6007
            localCount: 0,
3707 6008
        };
6009 +
        if containsGenericParameter(Type::Fn(&fnType)) {
6010 +
            set traitType.objectSafe = false;
6011 +
        }
3708 6012
        traitType.methods.append(TraitMethod {
3709 6013
            name: methodName,
3710 6014
            fnType: allocFnType(self, fnType),
3711 6015
            mutable,
3712 6016
            receiverClass,
6017 +
            owner: traitType,
3713 6018
            index: traitType.methods.len as u32,
3714 6019
        }, a);
3715 6020
3716 6021
        setNodeType(self, methodNode, Type::Void);
3717 6022
    }
6023 +
    set traitType.state = TraitState::Complete;
3718 6024
}
3719 6025
3720 6026
/// Resolve a name path node to a symbol.
3721 6027
/// Used for trait and type references in instance declarations and trait objects.
3722 6028
fn resolveNamePath(self: *mut Resolver, node: *ast::Node) -> *mut Symbol
3752 6058
    let case SymbolData::Trait(traitInfo) = traitSym.data
3753 6059
        else throw emitError(self, traitName, ErrorKind::Internal);
3754 6060
3755 6061
    setNodeSymbol(self, traitName, traitSym);
3756 6062
3757 -
    // Look up the target type.
3758 -
    let typeSym = try resolveNamePath(self, targetType);
3759 -
    let case SymbolData::Type(nominalTy) = typeSym.data
3760 -
        else throw emitError(self, targetType, ErrorKind::Internal);
3761 -
    setNodeSymbol(self, targetType, typeSym);
3762 -
    // Ensure the concrete type body is resolved.
3763 -
    try ensureNominalResolved(self, nominalTy, targetType);
3764 -
3765 -
    // Reject duplicate instance for the same (trait, type) pair.
3766 -
    let concreteType = Type::Nominal(nominalTy);
6063 +
    // Resolve a concrete target type, including built-in scalar types.
6064 +
    let concreteType = try resolveValueType(self, targetType);
6065 +
    if containsGenericParameter(concreteType) {
6066 +
        throw emitError(self, targetType, ErrorKind::InvalidInstanceTarget);
6067 +
    }
6068 +
    if let case Type::Nominal(nominalTy) = concreteType {
6069 +
        try ensureNominalResolved(self, nominalTy, targetType);
6070 +
    }
3767 6071
    if let _ = findInstance(self, traitInfo, concreteType) {
3768 6072
        throw emitError(self, node, ErrorKind::DuplicateInstance);
3769 6073
    }
3770 6074
3771 6075
    // Build the instance entry.
3776 6080
        &mut self.arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), traitInfo.methods.len as u32
3777 6081
    ) as *mut [*mut Symbol];
3778 6082
    let mut entry = InstanceEntry {
3779 6083
        traitType: traitInfo,
3780 6084
        concreteType,
3781 -
        concreteTypeName: typeSym.name,
3782 6085
        moduleId: self.currentMod,
3783 6086
        methods: methodSlice,
3784 6087
    };
3785 6088
    // Track which trait methods are covered by the instance.
3786 6089
    let mut covered: [bool; ast::MAX_TRAIT_METHODS] = [false; ast::MAX_TRAIT_METHODS];
3795 6098
        let attrMask = resolveAttributes(self, attrs);
3796 6099
3797 6100
        // Find the matching trait method.
3798 6101
        let tm = findTraitMethod(traitInfo, methodName)
3799 6102
            else throw emitError(self, name, ErrorKind::UnresolvedSymbol(methodName));
6103 +
        if tm.owner <> traitInfo {
6104 +
            throw emitError(self, name, ErrorKind::InheritedTraitMethod(methodName));
6105 +
        }
6106 +
        let selfArg = allocType(self, concreteType);
6107 +
        let selfParams: [*GenericParamType; 1] = [tm.owner.selfType];
6108 +
        let selfArgs: [*Type; 1] = [selfArg];
6109 +
        let selfSub = Substitution {
6110 +
            params: &selfParams[..],
6111 +
            args: &selfArgs[..],
6112 +
        };
6113 +
        let concreteMethodType = try substituteType(
6114 +
            self, Type::Fn(tm.fnType), &selfSub, methodNode
6115 +
        );
6116 +
        let case Type::Fn(expectedFn) = concreteMethodType
6117 +
            else throw emitError(self, methodNode, ErrorKind::Internal);
3800 6118
        let instanceUnsafe = ast::hasAttribute(attrMask, ast::Attribute::Unsafe);
3801 6119
        if instanceUnsafe <> tm.fnType.isUnsafe {
3802 6120
            throw emitError(self, methodNode, ErrorKind::TraitMethodSafetyMismatch);
3803 6121
        }
3804 6122
3832 6150
            throw emitError(self, receiverType, ErrorKind::ReceiverMutabilityMismatch);
3833 6151
        }
3834 6152
3835 6153
        // Build the function type for the instance method.
3836 6154
        // The receiver becomes the first parameter.
3837 -
        let receiverPtrType = Type::Pointer {
6155 +
        let receiverPtrType = Type::Pointer(PointerType {
3838 6156
            class: receiverClass,
3839 6157
            target: allocType(self, concreteType),
3840 6158
            mutable: receiverMut,
3841 -
        };
6159 +
        });
3842 6160
3843 6161
        // Validate that the instance method's signature matches the
3844 6162
        // trait method's signature exactly (params, return type, throws).
3845 -
        if sig.params.len <> tm.fnType.paramTypes.len {
6163 +
        if sig.params.len <> expectedFn.paramTypes.len {
3846 6164
            throw emitError(self, methodNode, ErrorKind::FnArgCountMismatch(CountMismatch {
3847 -
                expected: tm.fnType.paramTypes.len as u32,
6165 +
                expected: expectedFn.paramTypes.len as u32,
3848 6166
                actual: sig.params.len,
3849 6167
            }));
3850 6168
        }
3851 6169
        for paramNode, j in sig.params {
3852 6170
            let case ast::NodeValue::FnParam(param) = paramNode.value
3853 6171
                else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
3854 6172
            let instanceParamTy = try resolveValueType(self, param.type);
3855 -
            if not typesEqual(instanceParamTy, *tm.fnType.paramTypes[j]) {
6173 +
            if not typesEqual(instanceParamTy, *expectedFn.paramTypes[j]) {
3856 6174
                throw emitTypeMismatch(self, paramNode, TypeMismatch {
3857 -
                    expected: *tm.fnType.paramTypes[j],
6175 +
                    expected: *expectedFn.paramTypes[j],
3858 6176
                    actual: instanceParamTy,
3859 6177
                });
3860 6178
            }
3861 6179
        }
3862 6180
        let mut instanceRetTy = Type::Void;
3863 6181
        if let retNode = sig.returnType {
3864 6182
            set instanceRetTy = try resolveValueType(self, retNode);
3865 6183
        }
3866 -
        if not typesEqual(instanceRetTy, *tm.fnType.returnType) {
6184 +
        if not typesEqual(instanceRetTy, *expectedFn.returnType) {
3867 6185
            throw emitTypeMismatch(self, methodNode, TypeMismatch {
3868 -
                expected: *tm.fnType.returnType,
6186 +
                expected: *expectedFn.returnType,
3869 6187
                actual: instanceRetTy,
3870 6188
            });
3871 6189
        }
3872 -
        if sig.throwList.len <> tm.fnType.throwList.len {
6190 +
        if sig.throwList.len <> expectedFn.throwList.len {
3873 6191
            throw emitError(self, methodNode, ErrorKind::FnThrowCountMismatch(CountMismatch {
3874 -
                expected: tm.fnType.throwList.len as u32,
6192 +
                expected: expectedFn.throwList.len as u32,
3875 6193
                actual: sig.throwList.len,
3876 6194
            }));
3877 6195
        }
3878 6196
        for throwNode, j in sig.throwList {
3879 6197
            let instanceThrowTy = try resolveValueType(self, throwNode);
3880 -
            if not typesEqual(instanceThrowTy, *tm.fnType.throwList[j]) {
6198 +
            if not typesEqual(instanceThrowTy, *expectedFn.throwList[j]) {
3881 6199
                throw emitTypeMismatch(self, throwNode, TypeMismatch {
3882 -
                    expected: *tm.fnType.throwList[j],
6200 +
                    expected: *expectedFn.throwList[j],
3883 6201
                    actual: instanceThrowTy,
3884 6202
                });
3885 6203
            }
3886 6204
        }
3887 6205
3889 6207
        let a = alloc::arenaAllocator(&mut self.arena);
3890 6208
        // TODO: Improve this pattern, maybe via something like `(&[]).append(..)`?
3891 6209
        let mut paramTypes: *mut [*Type] = &mut [];
3892 6210
        paramTypes.append(allocType(self, receiverPtrType), a);
3893 6211
3894 -
        for ty in tm.fnType.paramTypes {
6212 +
        for ty in expectedFn.paramTypes {
3895 6213
            paramTypes.append(ty, a);
3896 6214
        }
3897 6215
        let fnType = FnType {
3898 6216
            paramTypes: &paramTypes[..],
3899 -
            returnType: tm.fnType.returnType,
3900 -
            throwList: tm.fnType.throwList,
3901 -
            isUnsafe: tm.fnType.isUnsafe,
6217 +
            returnType: expectedFn.returnType,
6218 +
            throwList: expectedFn.throwList,
6219 +
            isUnsafe: expectedFn.isUnsafe,
3902 6220
            localCount: 0,
3903 6221
        };
3904 6222
3905 6223
        // Create a symbol for the instance method without binding it into the
3906 6224
        // module scope. Instance methods are dispatched via v-table, so they
4019 6337
    }
4020 6338
}
4021 6339
4022 6340
/// Resolve a standalone method declaration (signature only).
4023 6341
/// Validates the receiver type and registers the method in the method table.
4024 -
4025 -
/// Extract the type name from a resolved receiver type node.
4026 -
fn receiverTypeName(
4027 -
    self: *mut Resolver,
4028 -
    receiverType: *ast::Node,
4029 -
) -> *[u8] throws (ResolveError) {
4030 -
    let case ast::NodeValue::TypeSig(ast::TypeSig::Pointer { valueType, .. }) =
4031 -
        receiverType.value
4032 -
        else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
4033 -
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(nameNode)) = valueType.value
4034 -
        else throw emitError(self, receiverType, ErrorKind::Internal);
4035 -
    let sym = symbolFor(self, nameNode)
4036 -
        else throw emitError(self, receiverType, ErrorKind::Internal);
4037 -
4038 -
    return sym.name;
4039 -
}
4040 -
4041 6342
/// Resolve and register a standalone method declaration.
4042 6343
fn resolveMethodDecl(
4043 6344
    self: *mut Resolver,
4044 6345
    node: *ast::Node,
4045 6346
    name: *ast::Node,
4049 6350
    attrs: ?ast::Attributes,
4050 6351
) throws (ResolveError) {
4051 6352
    // Resolve the receiver type: must be `*Type` or `*mut Type` pointing to a
4052 6353
    // nominal type.
4053 6354
    let fullReceiverTy = try infer(self, receiverType);
4054 -
    let case Type::Pointer {
4055 -
        class: receiverClass, target: receiverTarget, mutable: receiverMut,
4056 -
    } = fullReceiverTy
6355 +
    let case Type::Pointer(receiver) = fullReceiverTy
4057 6356
        else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
4058 -
    let concreteType = *receiverTarget;
6357 +
    let concreteType = *receiver.target;
4059 6358
    let case Type::Nominal(nominalTy) = concreteType
4060 6359
        else throw emitError(self, receiverType, ErrorKind::ExpectedRecord);
4061 6360
    try ensureNominalResolved(self, nominalTy, receiverType);
4062 6361
4063 -
    // Get the type name from the inner type node's symbol.
4064 -
    let typeName = try receiverTypeName(self, receiverType);
4065 6362
    let methodName = try nodeName(self, name);
4066 6363
    let attrMask = resolveAttributes(self, attrs);
4067 6364
4068 6365
    // Reject duplicate method for the same (type, name).
4069 6366
    if let _ = findMethod(self, concreteType, methodName) {
4073 6370
    // Resolve parameter types.
4074 6371
    let a = alloc::arenaAllocator(&mut self.arena);
4075 6372
    let mut paramTypes: *mut [*Type] = &mut [];
4076 6373
4077 6374
    // Receiver is the first parameter.
4078 -
    let receiverPtrType = Type::Pointer {
4079 -
        class: receiverClass,
6375 +
    let receiverPtrType = Type::Pointer(PointerType {
6376 +
        class: receiver.class,
4080 6377
        target: allocType(self, concreteType),
4081 -
        mutable: receiverMut,
4082 -
    };
6378 +
        mutable: receiver.mutable,
6379 +
    });
4083 6380
    paramTypes.append(allocType(self, receiverPtrType), a);
4084 6381
4085 6382
    for paramNode in sig.params {
4086 6383
        let case ast::NodeValue::FnParam(param) = paramNode.value
4087 6384
            else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
4138 6435
    if self.methodsLen >= MAX_METHODS {
4139 6436
        throw emitError(self, node, ErrorKind::Internal);
4140 6437
    }
4141 6438
    set self.methods[self.methodsLen] = MethodEntry {
4142 6439
        concreteType,
4143 -
        concreteTypeName: typeName,
4144 6440
        name: methodName,
4145 6441
        fnType: allocFnType(self, checkFnType),
4146 -
        mutable: receiverMut,
4147 -
        receiverClass,
6442 +
        mutable: receiver.mutable,
6443 +
        receiverClass: receiver.class,
4148 6444
        symbol: sym,
4149 6445
    };
4150 6446
    set self.methodsLen += 1;
4151 6447
}
4152 6448
4153 6449
/// Look up an instance entry by trait and concrete type.
4154 -
fn findInstance(self: *Resolver, traitInfo: *TraitType, concreteType: Type) -> ?*InstanceEntry {
6450 +
export fn findInstance(self: *Resolver, traitInfo: *TraitType, concreteType: Type) -> ?*InstanceEntry {
4155 6451
    for i in 0..self.instancesLen {
4156 6452
        let entry = &self.instances[i];
4157 6453
        if entry.traitType == traitInfo and typesEqual(entry.concreteType, concreteType) {
4158 6454
            return entry;
4159 6455
        }
4197 6493
    // Check if already resolved, in which case there's no need to
4198 6494
    // do it again.
4199 6495
    if let case NominalType::Union(_) = *nominalTy {
4200 6496
        return;
4201 6497
    }
4202 -
    let a = alloc::arenaAllocator(&mut self.arena);
4203 -
    let mut variants: *mut [UnionVariant] = &mut [];
4204 -
4205 -
    // Create a temporary nominal type to replace the placeholder.This prevents infinite recursion
4206 -
    // when a variant references this union type (e.g. record payloads with `*[Self]`).
4207 -
    // TODO: It would be best to have a resolving state eg. `Visiting` for this situation.
4208 6498
    let declaredLinear = try resolveLinearDerive(self, decl.derives);
6499 +
    // Publish a temporary union so pointer-recursive variants can resolve it.
4209 6500
    set *nominalTy = NominalType::Union(UnionType {
4210 6501
        variants: &[],
4211 6502
        layout: Layout { size: 0, alignment: 0 },
4212 6503
        valOffset: 0,
4213 6504
        isAllVoid: true,
4214 6505
        declaredLinear,
4215 6506
    });
4216 -
4217 -
    assert decl.variants.len <= MAX_UNION_VARIANTS, "resolveUnionBody: maximum union variants exceeded";
4218 -
    let mut iota: u32 = 0;
4219 -
    for variantNode, i in decl.variants {
4220 -
        let case ast::NodeValue::UnionDeclVariant(variantDecl) = variantNode.value
4221 -
            else panic "resolveUnionBody: invalid union variant";
4222 -
        let variantName = try nodeName(self, variantDecl.name);
4223 -
        // Resolve the variant's payload type if present.
4224 -
        let mut variantType = Type::Void;
4225 -
        if let typeNode = variantDecl.type {
4226 -
            set variantType = try infer(self, typeNode);
4227 -
            try ensureStorableType(self, typeNode, variantType);
4228 -
        }
4229 -
        // Process the variant's explicit discriminant value if present.
4230 -
        try visitOptional(self, variantDecl.value, variantType);
4231 -
        let tag = variantTag(variantDecl, &mut iota);
4232 -
        // Create a symbol for this variant.
4233 -
        let data = SymbolData::Variant { type: variantType, decl: node, ordinal: i, index: tag };
4234 -
        let variantSym = allocSymbol(self, data, variantName, variantNode, 0);
4235 -
4236 -
        variants.append(UnionVariant {
4237 -
            name: variantName,
4238 -
            valueType: variantType,
4239 -
            symbol: variantSym,
4240 -
        }, a);
4241 -
    }
4242 -
    let info = computeUnionLayout(&variants[..]);
4243 -
4244 -
    // Update the nominal type with the resolved variants.
4245 -
    set *nominalTy = NominalType::Union(UnionType {
4246 -
        variants: &variants[..],
4247 -
        layout: info.layout,
4248 -
        valOffset: info.valOffset,
4249 -
        isAllVoid: info.isAllVoid,
4250 -
        declaredLinear,
4251 -
    });
6507 +
    let unionType = try buildUnionType(
6508 +
        self, sym, decl, declaredLinear, AggregateMemberSource::Ordinary
6509 +
    );
6510 +
    set *nominalTy = NominalType::Union(unionType);
4252 6511
}
4253 6512
4254 6513
/// Check if a module should be analyzed based on its attributes and build configuration.
4255 6514
fn shouldAnalyzeModule(self: *Resolver, attrs: ?ast::Attributes) -> bool {
4256 6515
    if let attributes = attrs {
4430 6689
    pattern: *ast::Node,
4431 6690
    scrutineeTy: Type,
4432 6691
    mode: IdentMode,
4433 6692
    matchBy: MatchBy
4434 6693
) throws (ResolveError) {
4435 -
    if let case Type::Pointer { target, .. } = scrutineeTy; isDestructuringPattern(pattern) {
4436 -
        try resolveCasePattern(self, pattern, *target, mode, matchBy);
6694 +
    if let case Type::Pointer(pointer) = scrutineeTy; isDestructuringPattern(pattern) {
6695 +
        try resolveCasePattern(self, pattern, *pointer.target, mode, matchBy);
4437 6696
        return;
4438 6697
    }
4439 6698
    // TODO: Collapse these nested matches.
4440 6699
    match scrutineeTy {
4441 6700
        case Type::Nominal(info) => {
4534 6793
        }
4535 6794
    }
4536 6795
    // Extract item type and store pre-computed loop metadata for the lowerer.
4537 6796
    let mut itemTy: Type = undefined;
4538 6797
    match iterableTy {
4539 -
        case Type::Slice { item, .. } => {
4540 -
            set itemTy = *item;
6798 +
        case Type::Slice(slice) => {
6799 +
            set itemTy = *slice.item;
4541 6800
            setForLoopInfo(self, node, ForLoopInfo::Collection {
4542 -
                elemType: item, length: nil, bindingName, indexName
6801 +
                elemType: slice.item, length: nil, bindingName, indexName
4543 6802
            });
4544 6803
        }
4545 6804
        case Type::Range { start, .. } => {
4546 6805
            // Iterable ranges must have a start, and since we enforce type
4547 6806
            // equality for start and end, that is always the item type.
5100 7359
    throws (ResolveError)
5101 7360
{
5102 7361
    let mut bindTy = ty;
5103 7362
    match matchBy {
5104 7363
        case MatchBy::Value => {}
5105 -
        case MatchBy::Ref => set bindTy = Type::Pointer {
7364 +
        case MatchBy::Ref => set bindTy = Type::Pointer(PointerType {
5106 7365
            class: types::PointerClass::Ref,
5107 7366
            target: allocType(self, ty),
5108 7367
            mutable: false,
5109 -
        },
5110 -
        case MatchBy::MutRef => set bindTy = Type::Pointer {
7368 +
        }),
7369 +
        case MatchBy::MutRef => set bindTy = Type::Pointer(PointerType {
5111 7370
            class: types::PointerClass::Ref,
5112 7371
            target: allocType(self, ty),
5113 7372
            mutable: true,
5114 -
        },
7373 +
        }),
5115 7374
    }
5116 7375
    match binding.value {
5117 7376
        case ast::NodeValue::Placeholder => {
5118 7377
            // Nothing to do.
5119 7378
        }
5324 7583
                expected: 2,
5325 7584
                actual: args.len as u32,
5326 7585
            }));
5327 7586
        }
5328 7587
        let ptrType = try visit(self, args[0], Type::Unknown);
5329 -
        let case Type::Pointer { class, target, mutable } = ptrType else {
7588 +
        let case Type::Pointer(ptr) = ptrType else {
5330 7589
            throw emitError(self, node, ErrorKind::ExpectedPointer);
5331 7590
        };
5332 7591
        let _ = try checkAssignable(self, args[1], Type::U32);
5333 7592
        if args.len == 3 {
5334 7593
            let _ = try checkAssignable(self, args[2], Type::U32);
5335 7594
        }
5336 -
        return setNodeType(self, node, Type::Slice { class, item: target, mutable });
7595 +
        return setNodeType(self, node, Type::Slice(SliceType {
7596 +
            class: ptr.class,
7597 +
            item: ptr.target,
7598 +
            mutable: ptr.mutable,
7599 +
        }));
5337 7600
    }
5338 7601
    if args.len <> 1 {
5339 7602
        throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch {
5340 7603
            expected: 1,
5341 7604
            actual: args.len as u32,
5345 7608
    let ty = try resolveValueType(self, args[0]);
5346 7609
    // Ensure the type body is resolved before computing layout.
5347 7610
    // TODO: Somehow, ensuring the type is resolved should just happen all
5348 7611
    // the time, lazily.
5349 7612
    try ensureTypeResolved(self, ty, args[0]);
7613 +
    if containsGenericParameter(ty) {
7614 +
        throw emitError(self, args[0], ErrorKind::GenericLayoutRequired);
7615 +
    }
5350 7616
    // TODO: This should be stored in `symbol` instead of having to recompute it.
5351 7617
    // That way there's a canonical place to look for code gen.
5352 7618
    let layout = getTypeLayout(ty);
5353 7619
5354 7620
    // Evaluate the built-in.
5362 7628
        },
5363 7629
        case ast::Builtin::SliceOf => {
5364 7630
            panic "unreachable: @sliceOf handled above";
5365 7631
        }
5366 7632
    }
5367 -
    // Record as constant value for constant folding.
5368 -
    setNodeConstValue(self, node, ConstValue::Int(ConstInt {
5369 -
        magnitude: value as u64,
5370 -
        bits: 32,
5371 -
        signed: false,
5372 -
        negative: false,
5373 -
    }));
5374 -
    return setNodeType(self, node, Type::U32);
7633 +
    // Record as constant value for constant folding.
7634 +
    setNodeConstValue(self, node, ConstValue::Int(ConstInt {
7635 +
        magnitude: value as u64,
7636 +
        bits: 32,
7637 +
        signed: false,
7638 +
        negative: false,
7639 +
    }));
7640 +
    return setNodeType(self, node, Type::U32);
7641 +
}
7642 +
7643 +
/// Validate call arguments against a function type: check argument count,
7644 +
/// type-check each argument, and verify that throwing functions use `try`.
7645 +
fn checkCallArgs(self: *mut Resolver, node: *ast::Node, call: ast::Call, info: *FnType, ctx: CallCtx)
7646 +
    throws (ResolveError)
7647 +
{
7648 +
    if ctx == CallCtx::Normal and info.throwList.len > 0 {
7649 +
        throw emitError(self, node, ErrorKind::MissingTry);
7650 +
    }
7651 +
    if call.args.len <> info.paramTypes.len as u32 {
7652 +
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
7653 +
            expected: info.paramTypes.len as u32,
7654 +
            actual: call.args.len,
7655 +
        }));
7656 +
    }
7657 +
    for argNode, i in call.args {
7658 +
        let expectedTy = *info.paramTypes[i];
7659 +
7660 +
        try checkAssignable(self, argNode, expectedTy);
7661 +
    }
7662 +
}
7663 +
7664 +
/// Unify one symbolic parameter type with exact call-site evidence.
7665 +
fn inferGenericArgument(
7666 +
    self: *mut Resolver,
7667 +
    pattern: Type,
7668 +
    actual: Type,
7669 +
    params: *[*GenericParamType],
7670 +
    inferred: *mut [?*Type],
7671 +
) -> bool {
7672 +
    if let case Type::Parameter(param) = pattern {
7673 +
        let mut evidence = actual;
7674 +
        match actual {
7675 +
            case Type::Unknown, Type::Nil, Type::Undefined => return true,
7676 +
            case Type::Int => set evidence = Type::I64,
7677 +
            else => {},
7678 +
        }
7679 +
        for candidate, i in params {
7680 +
            if candidate == param {
7681 +
                if let prior = inferred[i] {
7682 +
                    return typesEqual(*prior, evidence);
7683 +
                }
7684 +
                set inferred[i] = allocType(self, evidence);
7685 +
                return true;
7686 +
            }
7687 +
        }
7688 +
        return typesEqual(pattern, evidence);
7689 +
    }
7690 +
    if typesEqual(pattern, actual) {
7691 +
        return true;
7692 +
    }
7693 +
    if not containsGenericParameter(pattern) {
7694 +
        return true;
7695 +
    }
7696 +
    match pattern {
7697 +
        case Type::Pointer(pointer) => {
7698 +
            let case Type::Pointer(actualPointer) = actual else return false;
7699 +
            return pointer.class == actualPointer.class
7700 +
                and pointer.mutable == actualPointer.mutable
7701 +
                and inferGenericArgument(
7702 +
                    self,
7703 +
                    *pointer.target,
7704 +
                    *actualPointer.target,
7705 +
                    params,
7706 +
                    inferred,
7707 +
                );
7708 +
        }
7709 +
        case Type::Slice(slice) => {
7710 +
            let case Type::Slice(actualSlice) = actual else return false;
7711 +
            return slice.class == actualSlice.class
7712 +
                and slice.mutable == actualSlice.mutable
7713 +
                and inferGenericArgument(
7714 +
                    self,
7715 +
                    *slice.item,
7716 +
                    *actualSlice.item,
7717 +
                    params,
7718 +
                    inferred,
7719 +
                );
7720 +
        }
7721 +
        case Type::Optional(inner) => {
7722 +
            let case Type::Optional(actualInner) = actual else return false;
7723 +
            return inferGenericArgument(
7724 +
                self, *inner, *actualInner, params, inferred
7725 +
            );
7726 +
        }
7727 +
        case Type::Array(array) => {
7728 +
            let case Type::Array(actualArray) = actual else return false;
7729 +
            return array.length == actualArray.length and inferGenericArgument(
7730 +
                self, *array.item, *actualArray.item, params, inferred
7731 +
            );
7732 +
        }
7733 +
        case Type::GenericDataApply(application) => {
7734 +
            let case Type::Nominal(nominal) = actual else return false;
7735 +
            let concrete = genericDataSpecializationForNominal(self, nominal)
7736 +
                else return false;
7737 +
            if concrete.template <> application.template
7738 +
                or concrete.args.len <> application.args.len
7739 +
            {
7740 +
                return false;
7741 +
            }
7742 +
            for arg, i in application.args {
7743 +
                if not inferGenericArgument(
7744 +
                    self, *arg, *concrete.args[i], params, inferred
7745 +
                ) {
7746 +
                    return false;
7747 +
                }
7748 +
            }
7749 +
            return true;
7750 +
        }
7751 +
        else => return false,
7752 +
    }
7753 +
}
7754 +
7755 +
/// Infer and resolve a direct call to a generic function template.
7756 +
fn resolveInferredGenericCall(
7757 +
    self: *mut Resolver,
7758 +
    callee: *ast::Node,
7759 +
    call: ast::Call,
7760 +
    expected: Type,
7761 +
) -> ?*FnType throws (ResolveError) {
7762 +
    let templateSym = findGenericCandidateSymbol(self, callee) else return nil;
7763 +
    let template = genericTemplateFor(self, templateSym) else return nil;
7764 +
    let signature = template.signature else return nil;
7765 +
    if call.args.len <> signature.paramTypes.len {
7766 +
        return nil;
7767 +
    }
7768 +
    let mut inferred: [?*Type; MAX_FN_PARAMS] = undefined;
7769 +
    for i in 0..inferred.len {
7770 +
        set inferred[i] = nil;
7771 +
    }
7772 +
    for argNode, i in call.args {
7773 +
        let actual = try infer(self, argNode);
7774 +
        if not inferGenericArgument(
7775 +
            self,
7776 +
            *signature.paramTypes[i],
7777 +
            actual,
7778 +
            template.params,
7779 +
            &mut inferred[..],
7780 +
        ) {
7781 +
            throw emitError(self, argNode, ErrorKind::GenericInferenceConflict);
7782 +
        }
7783 +
    }
7784 +
    if expected <> Type::Unknown and expected <> Type::Void and not inferGenericArgument(
7785 +
        self,
7786 +
        *signature.returnType,
7787 +
        expected,
7788 +
        template.params,
7789 +
        &mut inferred[..],
7790 +
    ) {
7791 +
        throw emitError(self, callee, ErrorKind::GenericInferenceConflict);
7792 +
    }
7793 +
    let a = alloc::arenaAllocator(&mut self.arena);
7794 +
    let mut args: *mut [*Type] = &mut [];
7795 +
    for _, i in template.params {
7796 +
        let arg = inferred[i] else {
7797 +
            throw emitError(
7798 +
                self, callee, ErrorKind::GenericInferenceIncomplete
7799 +
            );
7800 +
        };
7801 +
        args.append(arg, a);
7802 +
    }
7803 +
    for arg, i in args {
7804 +
        if not containsGenericParameter(*arg) {
7805 +
            for bound in template.params[i].bounds {
7806 +
                if findInstance(self, bound, *arg) == nil {
7807 +
                    throw emitError(
7808 +
                        self,
7809 +
                        callee,
7810 +
                        ErrorKind::GenericBoundUnsatisfied(bound.name),
7811 +
                    );
7812 +
                }
7813 +
            }
7814 +
        }
7815 +
    }
7816 +
    let sub = Substitution { params: template.params, args: &args[..] };
7817 +
    let applied = try substituteType(self, Type::Fn(signature), &sub, callee);
7818 +
    let case Type::Fn(appliedFn) = applied
7819 +
        else throw emitError(self, callee, ErrorKind::Internal);
7820 +
    let caller = currentGenericTemplateSymbol(self);
7821 +
    if caller == nil {
7822 +
        if let existing = findGenericFnSpecialization(
7823 +
            self, templateSym, &args[..]
7824 +
        ) {
7825 +
            setNodeSymbol(self, callee, templateSym);
7826 +
            setNodeType(self, callee, Type::Fn(existing.fnType));
7827 +
            set self.nodeData.entries[callee.id].extra =
7828 +
                NodeExtra::GenericFnCall(existing);
7829 +
            return existing.fnType;
7830 +
        }
7831 +
    }
7832 +
    recordGenericFnDependency(
7833 +
        self, callee, caller, templateSym, &args[..], appliedFn
7834 +
    );
7835 +
    return appliedFn;
5375 7836
}
5376 7837
5377 -
/// Validate call arguments against a function type: check argument count,
5378 -
/// type-check each argument, and verify that throwing functions use `try`.
5379 -
fn checkCallArgs(self: *mut Resolver, node: *ast::Node, call: ast::Call, info: *FnType, ctx: CallCtx)
5380 -
    throws (ResolveError)
5381 -
{
5382 -
    if ctx == CallCtx::Normal and info.throwList.len > 0 {
5383 -
        throw emitError(self, node, ErrorKind::MissingTry);
7838 +
/// Resolve `Trait::method(receiver, ...)` for a rigid bounded parameter.
7839 +
fn resolveQualifiedGenericBoundCall(
7840 +
    self: *mut Resolver,
7841 +
    node: *ast::Node,
7842 +
    call: ast::Call,
7843 +
    ctx: CallCtx,
7844 +
) -> ?Type throws (ResolveError) {
7845 +
    let case ast::NodeValue::ScopeAccess(access) = call.callee.value
7846 +
        else return nil;
7847 +
    if currentGenericTemplateSymbol(self) == nil or call.args.len == 0 {
7848 +
        return nil;
5384 7849
    }
5385 -
    if call.args.len <> info.paramTypes.len as u32 {
5386 -
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
5387 -
            expected: info.paramTypes.len as u32,
5388 -
            actual: call.args.len,
5389 -
        }));
7850 +
    let traitSym = try resolveNamePath(self, access.parent);
7851 +
    let case SymbolData::Trait(traitInfo) = traitSym.data else return nil;
7852 +
    let receiverTy = try infer(self, call.args[0]);
7853 +
    let case Type::Pointer(receiver) = receiverTy else return nil;
7854 +
    let case Type::Parameter(param) = *receiver.target else return nil;
7855 +
    let mut hasBound = false;
7856 +
    for bound in param.bounds {
7857 +
        if bound == traitInfo {
7858 +
            set hasBound = true;
7859 +
            break;
7860 +
        }
5390 7861
    }
5391 -
    for argNode, i in call.args {
5392 -
        let expectedTy = *info.paramTypes[i];
5393 -
5394 -
        try checkAssignable(self, argNode, expectedTy);
7862 +
    if not hasBound {
7863 +
        return nil;
7864 +
    }
7865 +
    if isUnsafePointerType(receiverTy) {
7866 +
        try requireUnsafe(self, call.args[0]);
5395 7867
    }
7868 +
    let methodName = try nodeName(self, access.child);
7869 +
    let method = findTraitMethod(traitInfo, methodName)
7870 +
        else throw emitError(
7871 +
            self, access.child, ErrorKind::RecordFieldUnknown(methodName)
7872 +
        );
7873 +
    if method.mutable and not receiver.mutable {
7874 +
        throw emitError(self, call.args[0], ErrorKind::ImmutableBinding);
7875 +
    }
7876 +
    let selfParam: [*GenericParamType; 1] = [method.owner.selfType];
7877 +
    let selfArg: [*Type; 1] = [allocType(self, Type::Parameter(param))];
7878 +
    let sub = Substitution {
7879 +
        params: &selfParam[..],
7880 +
        args: &selfArg[..],
7881 +
    };
7882 +
    let substituted = try substituteType(
7883 +
        self, Type::Fn(method.fnType), &sub, node
7884 +
    );
7885 +
    let case Type::Fn(methodFn) = substituted
7886 +
        else throw emitError(self, node, ErrorKind::Internal);
7887 +
    let a = alloc::arenaAllocator(&mut self.arena);
7888 +
    let mut params: *mut [*Type] = &mut [];
7889 +
    params.append(allocType(self, receiverTy), a);
7890 +
    for methodParam in methodFn.paramTypes {
7891 +
        params.append(methodParam, a);
7892 +
    }
7893 +
    let fullFn = allocFnType(self, FnType {
7894 +
        paramTypes: &params[..],
7895 +
        returnType: methodFn.returnType,
7896 +
        throwList: methodFn.throwList,
7897 +
        isUnsafe: methodFn.isUnsafe,
7898 +
        localCount: 0,
7899 +
    });
7900 +
    try checkUnsafeCall(self, call.callee, fullFn);
7901 +
    try checkCallArgs(self, node, call, fullFn, ctx);
7902 +
    setNodeSymbol(self, access.parent, traitSym);
7903 +
    setNodeType(self, call.callee, Type::Fn(fullFn));
7904 +
    setGenericBoundMethodCall(
7905 +
        self, node, param, traitInfo, method.index, true
7906 +
    );
7907 +
    return setNodeType(self, node, *methodFn.returnType);
5396 7908
}
5397 7909
5398 7910
/// Analyze a function call expression.
5399 -
fn resolveCall(self: *mut Resolver, node: *ast::Node, call: ast::Call, ctx: CallCtx) -> Type
5400 -
    throws (ResolveError)
7911 +
fn resolveCall(
7912 +
    self: *mut Resolver,
7913 +
    node: *ast::Node,
7914 +
    call: ast::Call,
7915 +
    ctx: CallCtx,
7916 +
    expected: Type,
7917 +
) -> Type throws (ResolveError)
5401 7918
{
5402 7919
    // Intercept method calls on slices before inferring the callee.
5403 7920
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
5404 7921
        let parentTy = try infer(self, access.parent);
5405 7922
        if isUnsafePointerType(parentTy) {
5406 7923
            try requireUnsafe(self, access.parent);
5407 7924
        }
7925 +
5408 7926
        let subjectTy = autoDeref(parentTy);
5409 7927
5410 -
        if let case Type::Slice { item, mutable, .. } = subjectTy {
7928 +
        if let case Type::Slice(slice) = subjectTy {
5411 7929
            let methodName = try nodeName(self, access.child);
5412 7930
            if methodName == "append" {
5413 7931
                return try resolveSliceAppend(
5414 -
                    self, node, access.parent, parentTy, call.args, item, mutable
7932 +
                    self, node, access.parent, parentTy, call.args, slice.item, slice.mutable
5415 7933
                );
5416 7934
            }
5417 7935
            if methodName == "delete" {
5418 7936
                return try resolveSliceDelete(
5419 -
                    self, node, access.parent, call.args, item, mutable
7937 +
                    self, node, access.parent, call.args, slice.item, slice.mutable
5420 7938
                );
5421 7939
            }
5422 7940
        }
5423 7941
    }
7942 +
    if let bounded = try resolveQualifiedGenericBoundCall(
7943 +
        self, node, call, ctx
7944 +
    ) {
7945 +
        return bounded;
7946 +
    }
7947 +
    if let inferred = try resolveInferredGenericCall(
7948 +
        self, call.callee, call, expected
7949 +
    ) {
7950 +
        try checkUnsafeCall(self, call.callee, inferred);
7951 +
        try checkCallArgs(self, node, call, inferred, ctx);
7952 +
        return setNodeType(self, node, *inferred.returnType);
7953 +
    }
5424 7954
    let calleeTy = try infer(self, call.callee);
5425 7955
    if let case Type::Fn(info) = calleeTy {
5426 7956
        try checkUnsafeCall(self, call.callee, info);
5427 7957
    }
5428 7958
5429 7959
    // Check if callee is a union variant and dispatch to constructor handler.
5430 7960
    // TODO: Move this out. We should decide on this earlier, based on the callee.
5431 7961
    if let calleeSym = symbolFor(self, call.callee) {
5432 -
        if let case SymbolData::Variant { decl, .. } = calleeSym.data {
5433 -
            // TODO: Don't pass the callee type, pass the union type by getting it from
5434 -
            // the symbol.
5435 -
            let declSym = symbolFor(self, decl) else panic;
5436 -
            let case SymbolData::Type(ty) = declSym.data else panic;
5437 7962
5438 -
            return try resolveUnionConstructorCall(self, node, call, ty);
7963 +
        if let case SymbolData::Variant { .. } = calleeSym.data {
7964 +
            let case Type::Nominal(unionType) = calleeTy
7965 +
                else throw emitError(self, call.callee, ErrorKind::Internal);
7966 +
            return try resolveUnionConstructorCall(self, node, call, unionType);
5439 7967
        }
5440 7968
        // Check if callee is an unlabeled record type for constructor call syntax.
5441 7969
        if let case SymbolData::Type(ty) = calleeSym.data {
5442 7970
            // Ensure the record body is resolved before checking if labeled.
5443 7971
            try ensureNominalResolved(self, ty, call.callee);
5455 7983
        if let t = typeFor(self, access.parent) {
5456 7984
            set parentTy = t;
5457 7985
        }
5458 7986
        let subjectTy = autoDeref(parentTy);
5459 7987
5460 -
        if let case Type::TraitObject { traitInfo, mutable: objMutable, .. } = subjectTy {
7988 +
        if let case Type::Parameter(param) = subjectTy; param.bounds.len > 0 {
5461 7989
            let methodName = try nodeName(self, access.child);
5462 -
            let method = findTraitMethod(traitInfo, methodName)
5463 -
                else throw emitError(self, access.child, ErrorKind::RecordFieldUnknown(methodName));
7990 +
            let selected = try findGenericBoundMethod(
7991 +
                self, access.child, param, methodName
7992 +
            );
7993 +
            let case Type::Fn(info) = calleeTy
7994 +
                else throw emitError(self, call.callee, ErrorKind::Internal);
7995 +
            if selected.method.mutable {
7996 +
                let mut isMutPtr = false;
7997 +
                if let case Type::Pointer(pointer) = parentTy {
7998 +
                    set isMutPtr = pointer.mutable;
7999 +
                }
8000 +
                if not isMutPtr and not (try canBorrowMutFrom(self, access.parent)) {
8001 +
                    throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
8002 +
                }
8003 +
            }
8004 +
            try checkUnsafeCall(self, call.callee, info);
8005 +
            try checkCallArgs(self, node, call, info, ctx);
8006 +
            setGenericBoundMethodCall(
8007 +
                self,
8008 +
                node,
8009 +
                param,
8010 +
                selected.traitInfo,
8011 +
                selected.method.index,
8012 +
                false,
8013 +
            );
8014 +
            return setNodeType(self, node, *info.returnType);
8015 +
        }
5464 8016
8017 +
        if let case Type::TraitObject(traitObject) = subjectTy {
8018 +
            let methodName = try nodeName(self, access.child);
8019 +
            let method = findTraitMethod(traitObject.traitInfo, methodName)
8020 +
                else throw emitError(self, access.child, ErrorKind::RecordFieldUnknown(methodName));
5465 8021
            // Reject mutable-receiver methods called on immutable trait objects.
5466 -
            if method.mutable and not objMutable {
8022 +
            if method.mutable and not traitObject.mutable {
5467 8023
                throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
5468 8024
            }
5469 8025
            try checkCallArgs(self, node, call, method.fnType, ctx);
5470 -
            setTraitMethodCall(self, node, traitInfo, method.index);
5471 8026
8027 +
            setTraitMethodCall(self, node, traitObject.traitInfo, method.index);
5472 8028
            return setNodeType(self, node, *method.fnType.returnType);
5473 8029
        }
5474 8030
5475 8031
        // Check for a standalone method call on a concrete type.
5476 8032
        if let case Type::Nominal(_) = subjectTy {
5479 8035
                // Reject mutable-receiver methods on immutable bindings.
5480 8036
                // If the parent is already a mutable pointer, the receiver is fine.
5481 8037
                // Otherwise, check that the parent can yield a mutable borrow.
5482 8038
                if method.mutable {
5483 8039
                    let mut isMutPtr = false;
5484 -
                    if let case Type::Pointer { mutable, .. } = parentTy {
5485 -
                        set isMutPtr = mutable;
8040 +
                    if let case Type::Pointer(pointer) = parentTy {
8041 +
                        set isMutPtr = pointer.mutable;
5486 8042
                    }
5487 8043
                    if not isMutPtr and not (try canBorrowMutFrom(self, access.parent)) {
5488 8044
                        throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
5489 8045
                    }
5490 8046
                }
5532 8088
    // First argument must be assignable to the element type.
5533 8089
    try checkAssignable(self, args[0], *elemType);
5534 8090
    // Second argument: the allocator. We accept any type -- the lowerer
5535 8091
    // reads `.func` and `.ctx` at fixed offsets.
5536 8092
    try visit(self, args[1], Type::Unknown);
8093 +
    recordGenericTypeUse(self, node, *elemType);
5537 8094
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType };
5538 8095
5539 8096
    // Return the parent's type so the caller can rebind:
5540 8097
    return setNodeType(self, node, parentType);
5541 8098
}
5557 8114
            expected: 1,
5558 8115
            actual: args.len as u32,
5559 8116
        }));
5560 8117
    }
5561 8118
    try checkAssignable(self, args[0], Type::U32);
8119 +
    recordGenericTypeUse(self, node, *elemType);
5562 8120
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType };
5563 8121
5564 8122
    return setNodeType(self, node, Type::Void);
5565 8123
}
5566 8124
5580 8138
            try checkSliceRangeIndices(self, range);
5581 8139
5582 8140
            let mut item: *Type = undefined;
5583 8141
            let mut capacity: ?u32 = nil;
5584 8142
5585 -
            if let case Type::Slice { item: sliceItem, mutable: sliceMutable, .. } = subjectTy {
5586 -
                if not sliceMutable {
8143 +
            if let case Type::Slice(slice) = subjectTy {
8144 +
                if not slice.mutable {
5587 8145
                    throw emitError(self, container, ErrorKind::ImmutableBinding);
5588 8146
                }
5589 -
                set item = sliceItem;
8147 +
                set item = slice.item;
5590 8148
            } else {
5591 8149
                match subjectTy {
5592 8150
                    case Type::Array(a) => {
5593 8151
                        try validateArraySliceBounds(self, range, a.length, node);
5594 8152
                        set item = a.item;
5597 8155
                    else => throw emitError(self, container, ErrorKind::ExpectedIndexable),
5598 8156
                }
5599 8157
            }
5600 8158
            // RHS is either a fill value or a source slice.
5601 8159
            let rhsTy = try infer(self, assign.right);
5602 -
            if let case Type::Slice { item: sourceItem, .. } = rhsTy {
5603 -
                if *sourceItem <> *item {
8160 +
            if let case Type::Slice(source) = rhsTy {
8161 +
                if *source.item <> *item {
5604 8162
                    throw emitTypeMismatch(
5605 8163
                        self,
5606 8164
                        assign.right,
5607 -
                        TypeMismatch { expected: *item, actual: *sourceItem },
8165 +
                        TypeMismatch { expected: *item, actual: *source.item },
5608 8166
                    );
5609 8167
                }
5610 8168
            } else {
5611 8169
                try checkAssignable(self, assign.right, *item);
5612 8170
            }
5704 8262
    if isUnsafePointerType(containerTy) {
5705 8263
        try requireUnsafe(self, container);
5706 8264
    }
5707 8265
    try checkIndex(self, indexNode);
5708 8266
    let subjectTy = autoDeref(containerTy);
5709 -
    if let case Type::Slice { item, .. } = subjectTy {
5710 -
        return setNodeType(self, node, *item);
8267 +
    if let case Type::Slice(slice) = subjectTy {
8268 +
        return setNodeType(self, node, *slice.item);
5711 8269
    }
5712 8270
5713 8271
    match subjectTy {
5714 8272
        case Type::Array(arrayInfo) => {
5715 8273
            return setNodeType(self, node, *arrayInfo.item);
5716 8274
        }
8275 +
        case Type::GenericArray { item, .. } => {
8276 +
            return setNodeType(self, node, *item);
8277 +
        }
5717 8278
        else => {
5718 8279
            throw emitError(self, container, ErrorKind::ExpectedIndexable);
5719 8280
        }
5720 8281
    }
5721 8282
}
5788 8349
    // Check if this is a scope access that might be a union variant.
5789 8350
    if let case ast::NodeValue::ScopeAccess(access) = typeIdent.value {
5790 8351
        let sym = try resolveAccess(self, typeIdent, access, self.scope);
5791 8352
5792 8353
        // Check if resolved symbol is a union variant.
5793 -
        if let case SymbolData::Variant { type, decl, ordinal, index } = sym.data {
5794 -
            // Get the union type from the variant's declaration.
5795 -
            let declSym = symbolFor(self, decl)
8354 +
        if let case SymbolData::Variant { type, ordinal, index, .. } = sym.data {
8355 +
            let resolved = typeFor(self, typeIdent)
5796 8356
                else throw emitError(self, node, ErrorKind::Internal);
5797 -
            let case SymbolData::Type(unionNominalType) = declSym.data
8357 +
            let case Type::Nominal(unionNominalType) = resolved
5798 8358
                else throw emitError(self, node, ErrorKind::Internal);
5799 8359
5800 8360
            // Get the variant's payload type.
5801 8361
            let case Type::Nominal(payloadInfo) = type
5802 8362
                else throw emitError(self, node, ErrorKind::ExpectedRecord);
5977 8537
    throws (ResolveError)
5978 8538
{
5979 8539
    let mut itemHint = hint;
5980 8540
    if let case Type::Array(ary) = hint {
5981 8541
        set itemHint = *ary.item;
8542 +
    } else if let case Type::GenericArray { item, .. } = hint {
8543 +
        set itemHint = *item;
5982 8544
    } else if let case Type::Optional(inner) = hint {
5983 8545
        if let case Type::Array(ary) = *inner {
5984 8546
            set itemHint = *ary.item;
5985 8547
        }
5986 8548
    }
5987 8549
    let valueTy = try visit(self, lit.item, itemHint);
5988 -
    let count = try checkSizeInt(self, lit.count);
5989 -
    let arrayTy = Type::Array(ArrayType {
5990 -
        item: allocType(self, valueTy),
5991 -
        length: count,
5992 -
    });
8550 +
    let _ = try checkNumeric(self, lit.count);
8551 +
    let mut arrayTy: Type = undefined;
8552 +
    if let value = constValueEntry(self, lit.count) {
8553 +
        if not validateConstIntRange(value, Type::U32) {
8554 +
            throw emitError(self, lit.count, ErrorKind::NumericLiteralOverflow);
8555 +
        }
8556 +
        let case ConstValue::Int(int) = value
8557 +
            else throw emitError(self, lit.count, ErrorKind::ConstExprRequired);
8558 +
        set arrayTy = Type::Array(ArrayType {
8559 +
            item: allocType(self, valueTy),
8560 +
            length: int.magnitude as u32,
8561 +
        });
8562 +
    } else if isConstExpr(self, lit.count) and
8563 +
              containsGenericConstExpr(self, lit.count)
8564 +
    {
8565 +
        set arrayTy = Type::GenericArray {
8566 +
            item: allocType(self, valueTy),
8567 +
            length: lit.count,
8568 +
        };
8569 +
    } else {
8570 +
        throw emitError(self, lit.count, ErrorKind::ConstExprRequired);
8571 +
    }
5993 8572
    return setNodeType(self, node, arrayTy);
5994 8573
}
5995 8574
5996 8575
/// Resolve union variant access.
5997 8576
fn resolveUnionVariantAccess(
6028 8607
    let sym = try resolveAccess(self, node, access, self.scope);
6029 8608
    let mut ty: Type = undefined;
6030 8609
6031 8610
    match sym.data {
6032 8611
        case SymbolData::Value { type, .. } => {
8612 +
            if isGenericDeclaration(sym.node) {
8613 +
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
8614 +
            }
6033 8615
            setNodeSymbol(self, node, sym);
6034 8616
            set ty = type;
6035 8617
        }
6036 8618
        case SymbolData::Constant { type, value } => {
6037 8619
            // Propagate the constant value.
6040 8622
            }
6041 8623
            setNodeSymbol(self, node, sym);
6042 8624
            set ty = type;
6043 8625
        }
6044 8626
        case SymbolData::Type(t) => {
8627 +
            if isGenericDeclaration(sym.node) {
8628 +
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
8629 +
            }
6045 8630
            setNodeSymbol(self, node, sym);
6046 8631
            set ty = Type::Nominal(t);
6047 8632
        }
8633 +
        case SymbolData::TypeParameter(param) => {
8634 +
            set *param.used = true;
8635 +
            setNodeSymbol(self, node, sym);
8636 +
            set ty = Type::Parameter(param);
8637 +
        }
8638 +
        case SymbolData::ConstParameter(param) => {
8639 +
            set *param.used = true;
8640 +
            setNodeSymbol(self, node, sym);
8641 +
            let constType = param.constType
8642 +
                else throw emitError(self, node, ErrorKind::Internal);
8643 +
            set ty = *constType;
8644 +
        }
6048 8645
        case SymbolData::Variant { index, .. } => {
6049 8646
            let ty = typeFor(self, node)
6050 8647
                else throw emitError(self, node, ErrorKind::Internal);
6051 8648
            // For unions without payload, store the variant index as a constant.
6052 8649
            if isVoidUnion(ty) {
6067 8664
        }
6068 8665
    }
6069 8666
    return setNodeType(self, node, ty);
6070 8667
}
6071 8668
8669 +
/// Find one bound method, rejecting ambiguous unqualified selections.
8670 +
fn findGenericBoundMethod(
8671 +
    self: *mut Resolver,
8672 +
    node: *ast::Node,
8673 +
    param: *GenericParamType,
8674 +
    name: *[u8],
8675 +
) -> GenericBoundMethod throws (ResolveError) {
8676 +
    let mut found: ?GenericBoundMethod = nil;
8677 +
    for bound in param.bounds {
8678 +
        if let method = findTraitMethod(bound, name) {
8679 +
            if found <> nil {
8680 +
                throw emitError(self, node, ErrorKind::GenericBoundAmbiguous(name));
8681 +
            }
8682 +
            set found = GenericBoundMethod { traitInfo: bound, method };
8683 +
        }
8684 +
    }
8685 +
    let result = found else throw emitError(
8686 +
        self, node, ErrorKind::RecordFieldUnknown(name)
8687 +
    );
8688 +
    return result;
8689 +
}
8690 +
6072 8691
/// Analyze a field access expression.
6073 8692
fn resolveFieldAccess(self: *mut Resolver, node: *ast::Node, access: ast::Access) -> Type
6074 8693
    throws (ResolveError)
6075 8694
{
6076 8695
    let parentTy = try infer(self, access.parent);
6077 8696
    if isUnsafePointerType(parentTy) {
6078 8697
        try requireUnsafe(self, access.parent);
6079 8698
    }
6080 8699
    let subjectTy = autoDeref(parentTy);
6081 -
6082 -
    if let case Type::Slice { class, item, mutable } = subjectTy {
8700 +
    if let case Type::Slice(slice) = subjectTy {
6083 8701
        let fieldNode = access.child;
6084 8702
        let fieldName = try nodeName(self, fieldNode);
6085 8703
        if mem::eq(fieldName, PTR_FIELD) {
6086 8704
            setRecordFieldIndex(self, fieldNode, 0);
6087 8705
            return setNodeType(
6088 8706
                self,
6089 8707
                node,
6090 -
                Type::Pointer { class, target: item, mutable },
8708 +
                Type::Pointer(PointerType {
8709 +
                    class: slice.class,
8710 +
                    target: slice.item,
8711 +
                    mutable: slice.mutable,
8712 +
                }),
6091 8713
            );
6092 8714
        }
6093 8715
        if mem::eq(fieldName, LEN_FIELD) {
6094 8716
            setRecordFieldIndex(self, fieldNode, 1);
6095 8717
            return setNodeType(self, node, Type::U32);
6098 8720
            setRecordFieldIndex(self, fieldNode, 2);
6099 8721
            return setNodeType(self, node, Type::U32);
6100 8722
        }
6101 8723
        throw emitError(self, node, ErrorKind::SliceFieldUnknown(fieldName));
6102 8724
    }
6103 -
    if let case Type::TraitObject { traitInfo, .. } = subjectTy {
8725 +
    if let case Type::TraitObject(traitObject) = subjectTy {
6104 8726
        let fieldName = try nodeName(self, access.child);
6105 -
        let method = findTraitMethod(traitInfo, fieldName)
8727 +
        let method = findTraitMethod(traitObject.traitInfo, fieldName)
6106 8728
            else throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
6107 8729
        return setNodeType(self, node, Type::Fn(method.fnType));
6108 8730
    }
6109 8731
6110 8732
    match subjectTy {
8733 +
        case Type::Parameter(param) if param.bounds.len > 0 => {
8734 +
            let fieldName = try nodeName(self, access.child);
8735 +
            let selected = try findGenericBoundMethod(
8736 +
                self, access.child, param, fieldName
8737 +
            );
8738 +
            let selfParam: [*GenericParamType; 1] = [selected.method.owner.selfType];
8739 +
            let selfArg: [*Type; 1] = [allocType(self, Type::Parameter(param))];
8740 +
            let sub = Substitution {
8741 +
                params: &selfParam[..],
8742 +
                args: &selfArg[..],
8743 +
            };
8744 +
            let methodType = try substituteType(
8745 +
                self, Type::Fn(selected.method.fnType), &sub, node
8746 +
            );
8747 +
            return setNodeType(self, node, methodType);
8748 +
        }
8749 +
        case Type::GenericDataApply(application) => {
8750 +
            let template = genericTemplateFor(self, application.template)
8751 +
                else throw emitError(self, node, ErrorKind::Internal);
8752 +
            let case ast::NodeValue::RecordDecl(decl) = application.template.node.value
8753 +
                else throw emitError(self, access.parent, ErrorKind::ExpectedRecord);
8754 +
            let fieldName = try nodeName(self, access.child);
8755 +
            for fieldNode, index in decl.fields {
8756 +
                let case ast::NodeValue::RecordField { field: maybeField, .. } =
8757 +
                    fieldNode.value
8758 +
                    else throw emitError(self, node, ErrorKind::Internal);
8759 +
                let fieldNodeName = maybeField
8760 +
                    else throw emitError(self, fieldNode, ErrorKind::Internal);
8761 +
                let candidate = try nodeName(self, fieldNodeName);
8762 +
                if mem::eq(candidate, fieldName) {
8763 +
                    let sub = Substitution {
8764 +
                        params: template.params,
8765 +
                        args: application.args,
8766 +
                    };
8767 +
                    let fieldType = try substituteType(
8768 +
                        self, *template.members[index], &sub, node
8769 +
                    );
8770 +
                    setRecordFieldIndex(self, access.child, index);
8771 +
                    return setNodeType(self, node, fieldType);
8772 +
                }
8773 +
            }
8774 +
            throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
8775 +
        }
6111 8776
        case Type::Nominal(NominalType::Record(recordType)) => {
6112 8777
            let fieldNode = access.child;
6113 8778
            let fieldName = try nodeName(self, fieldNode);
6114 8779
            if let fieldIndex = findRecordField(&recordType, fieldName) {
6115 8780
                let fieldTy = recordType.fields[fieldIndex].fieldType;
6133 8798
                return setNodeType(self, node, Type::U32);
6134 8799
            }
6135 8800
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
6136 8801
        }
6137 8802
8803 +
        case Type::GenericArray { .. } => {
8804 +
            let fieldName = try nodeName(self, access.child);
8805 +
            if mem::eq(fieldName, LEN_FIELD) {
8806 +
                return setNodeType(self, node, Type::U32);
8807 +
            }
8808 +
8809 +
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
8810 +
        }
6138 8811
        else => {
6139 8812
            // Check for standalone methods on any nominal type (e.g. unions).
6140 8813
            if let case Type::Nominal(_) = subjectTy {
6141 8814
                let fieldName = try nodeName(self, access.child);
6142 8815
                if let method = findMethod(self, subjectTy, fieldName) {
6162 8835
            if mutable {
6163 8836
                return true;
6164 8837
            }
6165 8838
            // Check if the type is a mutable pointer or slice.
6166 8839
            let ty = typeFor(self, node) else return false;
6167 -
            if let case Type::Pointer { mutable, .. } = ty {
6168 -
                return mutable;
8840 +
            if let case Type::Pointer(pointer) = ty {
8841 +
                return pointer.mutable;
6169 8842
            }
6170 -
            if let case Type::Slice { mutable, .. } = ty {
6171 -
                return mutable;
8843 +
            if let case Type::Slice(slice) = ty {
8844 +
                return slice.mutable;
6172 8845
            }
6173 8846
            return false;
6174 8847
        }
6175 8848
        case ast::NodeValue::FieldAccess(access) => {
6176 8849
            let _ = try infer(self, access.parent);
6191 8864
        case ast::NodeValue::Subscript { container, .. } => {
6192 8865
            let containerTy = try infer(self, container);
6193 8866
            // Subscript auto-derefs pointers, so check the actual indexed type.
6194 8867
            let subjectTy = autoDeref(containerTy);
6195 8868
6196 -
            if let case Type::Slice { mutable, .. } = subjectTy {
6197 -
                return mutable;
8869 +
            if let case Type::Slice(slice) = subjectTy {
8870 +
                return slice.mutable;
6198 8871
            }
6199 8872
            if let case Type::Array(_) = subjectTy {
6200 8873
                return try canBorrowMutFrom(self, container);
6201 8874
            }
6202 8875
            return false;
6208 8881
        }
6209 8882
        case ast::NodeValue::Call(_) => {
6210 8883
            // A call returning `*mut T` (or `&mut [T]`) yields a
6211 8884
            // mutable place. Non-pointer returns cannot be mutably borrowed.
6212 8885
            let ty = try infer(self, node);
6213 -
            if let case Type::Pointer { mutable, .. } = ty {
6214 -
                return mutable;
8886 +
            if let case Type::Pointer(pointer) = ty {
8887 +
                return pointer.mutable;
6215 8888
            }
6216 -
            if let case Type::Slice { mutable, .. } = ty {
6217 -
                return mutable;
8889 +
            if let case Type::Slice(slice) = ty {
8890 +
                return slice.mutable;
6218 8891
            }
6219 8892
            return false;
6220 8893
        }
6221 8894
        case ast::NodeValue::Deref(inner) => {
6222 8895
            let innerTy = try infer(self, inner);
6223 8896
6224 -
            if let case Type::Pointer { mutable, .. } = innerTy {
6225 -
                return mutable;
8897 +
            if let case Type::Pointer(pointer) = innerTy {
8898 +
                return pointer.mutable;
6226 8899
            }
6227 -
            if let case Type::Slice { mutable, .. } = innerTy {
6228 -
                return mutable;
8900 +
            if let case Type::Slice(slice) = innerTy {
8901 +
                return slice.mutable;
6229 8902
            }
6230 8903
            // Record deref: mutability depends on the inner binding.
6231 8904
            if let case Type::Nominal(NominalType::Record(recInfo)) = innerTy {
6232 8905
                if not recInfo.labeled and recInfo.fields.len == 1 {
6233 8906
                    return try canBorrowMutFrom(self, inner);
6262 8935
            try checkSliceRangeIndices(self, range);
6263 8936
6264 8937
            let mut item: *Type = undefined;
6265 8938
            let mut capacity: ?u32 = nil;
6266 8939
6267 -
            if let case Type::Slice { item: sliceItem, mutable: sliceMutable, .. } = subjectTy {
6268 -
                if addr.mutable and not sliceMutable {
8940 +
            if let case Type::Slice(slice) = subjectTy {
8941 +
                if addr.mutable and not slice.mutable {
6269 8942
                    throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
6270 8943
                }
6271 -
                set item = sliceItem;
8944 +
                set item = slice.item;
6272 8945
            } else {
6273 8946
                match subjectTy {
6274 8947
                    case Type::Array(arrayInfo) => {
6275 8948
                        try validateArraySliceBounds(self, range, arrayInfo.length, node);
6276 8949
                        set item = arrayInfo.item;
6279 8952
                    else => {
6280 8953
                        throw emitError(self, container, ErrorKind::ExpectedIndexable);
6281 8954
                    }
6282 8955
                }
6283 8956
            }
6284 -
            let sliceTy = Type::Slice { class, item, mutable: addr.mutable };
8957 +
            let sliceTy = Type::Slice(SliceType {
8958 +
                class,
8959 +
                item,
8960 +
                mutable: addr.mutable,
8961 +
            });
6285 8962
            let alloc = allocType(self, sliceTy);
6286 8963
            setSliceRangeInfo(self, node, SliceRangeInfo {
6287 8964
                itemType: item,
6288 8965
                mutable: addr.mutable,
6289 8966
                capacity,
6292 8969
            return setNodeType(self, node, *alloc);
6293 8970
        }
6294 8971
    }
6295 8972
    // Derive a hint for the target type from the slice hint.
6296 8973
    let mut targetHint: Type = Type::Unknown;
6297 -
    if let case Type::Slice { item, .. } = hint {
6298 -
        set targetHint = Type::Array(ArrayType { item, length: 0 });
8974 +
    if let case Type::Slice(slice) = hint {
8975 +
        set targetHint = Type::Array(ArrayType { item: slice.item, length: 0 });
6299 8976
    }
6300 8977
    let targetTy = try visit(self, addr.target, targetHint);
6301 8978
6302 8979
    // Mark local variable symbols as address-taken so the lowerer
6303 8980
    // allocates a stack slot eagerly.
6315 8992
    if let case Type::Array(arrayInfo) = targetTy {
6316 8993
        match addr.target.value {
6317 8994
            case ast::NodeValue::ArrayLit(_),
6318 8995
                 ast::NodeValue::ArrayRepeatLit(_) =>
6319 8996
            {
6320 -
                let sliceTy = Type::Slice { class, item: arrayInfo.item, mutable: addr.mutable };
8997 +
                let sliceTy = Type::Slice(SliceType {
8998 +
                    class,
8999 +
                    item: arrayInfo.item,
9000 +
                    mutable: addr.mutable,
9001 +
                });
6321 9002
                return setNodeType(self, node, *allocType(self, sliceTy));
6322 9003
            }
6323 9004
            else => {}
6324 9005
        }
6325 9006
    }
6326 -
    let pointerTy = Type::Pointer {
6327 -
        class, target: allocType(self, targetTy), mutable: addr.mutable,
6328 -
    };
9007 +
    let pointerTy = Type::Pointer(PointerType {
9008 +
        class,
9009 +
        target: allocType(self, targetTy),
9010 +
        mutable: addr.mutable,
9011 +
    });
6329 9012
    return setNodeType(self, node, pointerTy);
6330 9013
}
6331 9014
6332 9015
/// Analyze a dereference expression.
6333 9016
fn resolveDeref(self: *mut Resolver, node: *ast::Node, targetNode: *ast::Node, hint: Type) -> Type
6334 9017
    throws (ResolveError)
6335 9018
{
6336 9019
    let operandTy = try visit(self, targetNode, hint);
6337 -
    if let case Type::Pointer { class, target, .. } = operandTy {
6338 -
        if class == types::PointerClass::Unsafe {
9020 +
    if let case Type::Pointer(pointer) = operandTy {
9021 +
        if pointer.class == types::PointerClass::Unsafe {
6339 9022
            try requireUnsafe(self, targetNode);
6340 9023
        }
6341 9024
        // Disallow dereferencing opaque pointers.
6342 -
        if *target == Type::Opaque {
9025 +
        if *pointer.target == Type::Opaque {
6343 9026
            throw emitError(self, targetNode, ErrorKind::OpaqueTypeDeref);
6344 9027
        }
6345 -
        return setNodeType(self, node, *target);
9028 +
        return setNodeType(self, node, *pointer.target);
6346 9029
    }
6347 9030
    // Auto-deref for single-field unlabeled records.
6348 9031
    if let case Type::Nominal(NominalType::Record(recInfo)) = operandTy {
6349 9032
        if not recInfo.labeled and recInfo.fields.len == 1 {
6350 9033
            let fieldTy = recInfo.fields[0].fieldType;
6355 9038
    throw emitError(self, targetNode, ErrorKind::ExpectedPointer);
6356 9039
}
6357 9040
6358 9041
/// Check if a type is a pointer to opaque.
6359 9042
fn isOpaquePointer(ty: Type) -> bool {
6360 -
    if let case Type::Pointer { target, .. } = ty {
6361 -
        return *target == Type::Opaque;
9043 +
    if let case Type::Pointer(pointer) = ty {
9044 +
        return *pointer.target == Type::Opaque;
6362 9045
    }
6363 9046
    return false;
6364 9047
}
6365 9048
6366 9049
/// Check if a type is an opaque slice.
6367 9050
fn isOpaqueSlice(ty: Type) -> bool {
6368 -
    if let case Type::Slice { item, .. } = ty {
6369 -
        return *item == Type::Opaque;
9051 +
    if let case Type::Slice(slice) = ty {
9052 +
        return *slice.item == Type::Opaque;
6370 9053
    }
6371 9054
    return false;
6372 9055
}
6373 9056
6374 9057
/// Check if an `as` cast between two types is valid.
6385 9068
    // TODO: Check that variant index fits in target type.
6386 9069
    if isVoidUnion(source) and isNumericType(target) {
6387 9070
        return true;
6388 9071
    }
6389 9072
    // Allow address to numeric.
6390 -
    if let case Type::Slice { .. } = source {
9073 +
    if let case Type::Slice(_) = source {
6391 9074
        // Disallow slice to numeric; slices are fat pointers.
6392 9075
    } else if isAddressType(source) and isNumericType(target) {
6393 9076
        return true;
6394 9077
    }
6395 9078
    // Allow pointer casts if one side is `*opaque` or target types are castable.
6396 -
    if let case Type::Pointer {
6397 -
        class: sourceClass, target: sourceTarget, mutable: sourceMutable,
6398 -
    } = source {
6399 -
        if let case Type::Pointer {
6400 -
            class: targetClass, target: targetTarget, mutable: targetMutable,
6401 -
        } = target {
6402 -
            if sourceClass <> targetClass {
9079 +
    if let case Type::Pointer(sourcePointer) = source {
9080 +
        if let case Type::Pointer(targetPointer) = target {
9081 +
            if sourcePointer.class <> targetPointer.class {
6403 9082
                return false;
6404 9083
            }
6405 -
            if targetMutable and not sourceMutable {
9084 +
            if targetPointer.mutable and not sourcePointer.mutable {
6406 9085
                return false;
6407 9086
            }
6408 9087
            if isOpaquePointer(source) or isOpaquePointer(target) {
6409 9088
                return true;
6410 9089
            }
6411 -
            return isValidCast(*sourceTarget, *targetTarget);
9090 +
            return isValidCast(*sourcePointer.target, *targetPointer.target);
6412 9091
        }
6413 9092
    }
6414 9093
    // Allow slice casts if one side is `*[opaque]`, target is `*[u8]`,
6415 9094
    // or element types are castable.
6416 -
    if let case Type::Slice {
6417 -
        class: sourceClass, item: sourceItem, mutable: sourceMutable,
6418 -
    } = source {
6419 -
        if let case Type::Slice {
6420 -
            class: targetClass, item: targetItem, mutable: targetMutable,
6421 -
        } = target {
6422 -
            if sourceClass <> targetClass {
9095 +
    if let case Type::Slice(sourceSlice) = source {
9096 +
        if let case Type::Slice(targetSlice) = target {
9097 +
            if sourceSlice.class <> targetSlice.class {
6423 9098
                return false;
6424 9099
            }
6425 -
            if targetMutable and not sourceMutable {
9100 +
            if targetSlice.mutable and not sourceSlice.mutable {
6426 9101
                return false;
6427 9102
            }
6428 9103
            if isOpaqueSlice(source) or isOpaqueSlice(target) {
6429 9104
                return true;
6430 9105
            }
6431 -
            if *targetItem == Type::U8 {
9106 +
            if *targetSlice.item == Type::U8 {
6432 9107
                return true;
6433 9108
            }
6434 -
            return isValidCast(*sourceItem, *targetItem);
9109 +
            return isValidCast(*sourceSlice.item, *targetSlice.item);
6435 9110
        }
6436 9111
    }
6437 9112
    return false;
6438 9113
}
6439 9114
6449 9124
6450 9125
    assert sourceTy <> Type::Unknown;
6451 9126
    assert targetTy <> Type::Unknown;
6452 9127
6453 9128
    let mut valid = isValidCast(sourceTy, targetTy);
6454 -
    if let case Type::Pointer {
6455 -
        class: sourceClass, target: sourceTarget, mutable: sourceMutable,
6456 -
    } = sourceTy {
6457 -
        if let case Type::Pointer {
6458 -
            class: targetClass, target: targetTarget, mutable: targetMutable,
6459 -
        } = targetTy {
6460 -
            if sourceClass == types::PointerClass::Ref and
6461 -
               targetClass == types::PointerClass::Unsafe and
6462 -
               (not targetMutable or sourceMutable) and
6463 -
               isValidCast(*sourceTarget, *targetTarget)
9129 +
    if let case Type::Pointer(sourcePointer) = sourceTy {
9130 +
        if let case Type::Pointer(targetPointer) = targetTy {
9131 +
            if sourcePointer.class == types::PointerClass::Ref and
9132 +
               targetPointer.class == types::PointerClass::Unsafe and
9133 +
               (not targetPointer.mutable or sourcePointer.mutable) and
9134 +
               isValidCast(*sourcePointer.target, *targetPointer.target)
6464 9135
            {
6465 9136
                set valid = true;
6466 9137
            }
6467 9138
        }
6468 9139
    }
6469 -
    if let case Type::Slice {
6470 -
        class: sourceClass, item: sourceItem, mutable: sourceMutable,
6471 -
    } = sourceTy {
6472 -
        if let case Type::Slice {
6473 -
            class: targetClass, item: targetItem, mutable: targetMutable,
6474 -
        } = targetTy {
6475 -
            if sourceClass == types::PointerClass::Ref and
6476 -
               targetClass == types::PointerClass::Unsafe and
6477 -
               (not targetMutable or sourceMutable) and
6478 -
               isValidCast(*sourceItem, *targetItem)
9140 +
    if let case Type::Slice(sourceSlice) = sourceTy {
9141 +
        if let case Type::Slice(targetSlice) = targetTy {
9142 +
            if sourceSlice.class == types::PointerClass::Ref and
9143 +
               targetSlice.class == types::PointerClass::Unsafe and
9144 +
               (not targetSlice.mutable or sourceSlice.mutable) and
9145 +
               isValidCast(*sourceSlice.item, *targetSlice.item)
6479 9146
            {
6480 9147
                set valid = true;
6481 9148
            }
6482 9149
        }
6483 9150
    }
6539 9206
    throws (ResolveError)
6540 9207
{
6541 9208
    let call = tryExpr.expr;
6542 9209
    let case ast::NodeValue::Call(callExpr) = call.value
6543 9210
        else throw emitError(self, call, ErrorKind::TryNonThrowing);
6544 -
    let resultTy = try resolveCall(self, call, callExpr, CallCtx::Try);
9211 +
    let resultTy = try resolveCall(
9212 +
        self, call, callExpr, CallCtx::Try, hint
9213 +
    );
6545 9214
6546 9215
    // TODO: It's annoying that we need to re-fetch the function type after
6547 9216
    // analyzing the call.
6548 9217
    let calleeTy = typeFor(self, callExpr.callee)
6549 9218
        else return setNodeType(self, node, resultTy);
6838 9507
            return ConstValue::Bool(l > r if signed else left.magnitude > right.magnitude),
6839 9508
        case ast::BinaryOp::Lte =>
6840 9509
            return ConstValue::Bool(l <= r if signed else left.magnitude <= right.magnitude),
6841 9510
        case ast::BinaryOp::Gte =>
6842 9511
            return ConstValue::Bool(l >= r if signed else left.magnitude >= right.magnitude),
6843 -
        case ast::BinaryOp::Add => return ConstValue::Int(constIntFromSigned(l + r, bits, signed)),
6844 -
        case ast::BinaryOp::Sub => return ConstValue::Int(constIntFromSigned(l - r, bits, signed)),
6845 -
        case ast::BinaryOp::Mul => return ConstValue::Int(constIntFromSigned(l * r, bits, signed)),
9512 +
        case ast::BinaryOp::Add => {
9513 +
            if not signed {
9514 +
                return ConstValue::Int(
9515 +
                    constIntFromBits(left.magnitude + right.magnitude, bits, false)
9516 +
                );
9517 +
            }
9518 +
            return ConstValue::Int(constIntFromSigned(l + r, bits, true));
9519 +
        },
9520 +
        case ast::BinaryOp::Sub => {
9521 +
            if not signed {
9522 +
                return ConstValue::Int(
9523 +
                    constIntFromBits(left.magnitude - right.magnitude, bits, false)
9524 +
                );
9525 +
            }
9526 +
            return ConstValue::Int(constIntFromSigned(l - r, bits, true));
9527 +
        },
9528 +
        case ast::BinaryOp::Mul => {
9529 +
            if not signed {
9530 +
                return ConstValue::Int(
9531 +
                    constIntFromBits(left.magnitude * right.magnitude, bits, false)
9532 +
                );
9533 +
            }
9534 +
            return ConstValue::Int(constIntFromSigned(l * r, bits, true));
9535 +
        },
6846 9536
        case ast::BinaryOp::Div => {
6847 9537
            if signed {
6848 9538
                if r == 0 {
6849 9539
                    return nil;
6850 9540
                }
9541 +
                if l == parser::I64_MIN and r == -1 {
9542 +
                    return ConstValue::Int(
9543 +
                        constIntFromBits(parser::I64_MIN as u64, bits, true)
9544 +
                    );
9545 +
                }
6851 9546
                return ConstValue::Int(constIntFromSigned(l / r, bits, true));
6852 9547
            }
6853 9548
            if right.magnitude == 0 {
6854 9549
                return nil;
6855 9550
            }
6858 9553
        case ast::BinaryOp::Mod => {
6859 9554
            if signed {
6860 9555
                if r == 0 {
6861 9556
                    return nil;
6862 9557
                }
9558 +
                if l == parser::I64_MIN and r == -1 {
9559 +
                    return ConstValue::Int(
9560 +
                        constIntFromBits(0, bits, true)
9561 +
                    );
9562 +
                }
6863 9563
                return ConstValue::Int(constIntFromSigned(l % r, bits, true));
6864 9564
            }
6865 9565
            if right.magnitude == 0 {
6866 9566
                return nil;
6867 9567
            }
6868 9568
            return constInt(left.magnitude % right.magnitude, bits, false, false);
6869 9569
        },
6870 -
        case ast::BinaryOp::BitAnd => return ConstValue::Int(constIntFromSigned(l & r, bits, signed)),
6871 -
        case ast::BinaryOp::BitOr  => return ConstValue::Int(constIntFromSigned(l | r, bits, signed)),
6872 -
        case ast::BinaryOp::BitXor => return ConstValue::Int(constIntFromSigned(l ^ r, bits, signed)),
9570 +
        case ast::BinaryOp::BitAnd => return ConstValue::Int(
9571 +
            constIntFromBits(constIntToBits(left) & constIntToBits(right), bits, signed)
9572 +
        ),
9573 +
        case ast::BinaryOp::BitOr => return ConstValue::Int(
9574 +
            constIntFromBits(constIntToBits(left) | constIntToBits(right), bits, signed)
9575 +
        ),
9576 +
        case ast::BinaryOp::BitXor => return ConstValue::Int(
9577 +
            constIntFromBits(constIntToBits(left) ^ constIntToBits(right), bits, signed)
9578 +
        ),
6873 9579
        else => return nil,
6874 9580
    }
6875 9581
}
6876 9582
6877 9583
/// Try to constant-fold a binary operation on two resolved operands.
6960 9666
                let leftTy = try infer(self, binop.left);
6961 9667
                let rightTy = try visit(self, binop.right, leftTy);
6962 9668
6963 9669
                // Allow arithmetic on owning pointers and unsafe pointers, but
6964 9670
                // never on references.
6965 -
                if let case Type::Pointer { class: leftClass, target: leftTarget, .. } = leftTy {
6966 -
                    if *leftTarget == Type::Opaque {
9671 +
                if let case Type::Pointer(leftPointer) = leftTy {
9672 +
                    if *leftPointer.target == Type::Opaque {
6967 9673
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
6968 9674
                    }
6969 -
                    if leftClass <> types::PointerClass::Ref
9675 +
                    if leftPointer.class <> types::PointerClass::Ref
6970 9676
                        and isNumericType(rightTy)
6971 9677
                    {
6972 -
                        if leftClass == types::PointerClass::Unsafe {
9678 +
                        if leftPointer.class == types::PointerClass::Unsafe {
6973 9679
                            try requireUnsafe(self, node);
6974 9680
                        }
6975 9681
                        return setNodeType(self, node, leftTy);
6976 9682
                    }
6977 9683
                }
6978 -
                if let case Type::Pointer { class: rightClass, target: rightTarget, .. } = rightTy {
6979 -
                    if *rightTarget == Type::Opaque {
9684 +
                if let case Type::Pointer(rightPointer) = rightTy {
9685 +
                    if *rightPointer.target == Type::Opaque {
6980 9686
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
6981 9687
                    }
6982 9688
                    if binop.op == ast::BinaryOp::Add
6983 -
                        and rightClass <> types::PointerClass::Ref
9689 +
                        and rightPointer.class <> types::PointerClass::Ref
6984 9690
                        and isNumericType(leftTy)
6985 9691
                    {
6986 -
                        if rightClass == types::PointerClass::Unsafe {
9692 +
                        if rightPointer.class == types::PointerClass::Unsafe {
6987 9693
                            try requireUnsafe(self, node);
6988 9694
                        }
6989 9695
                        return setNodeType(self, node, rightTy);
6990 9696
                    }
6991 9697
                }
7065 9771
        },
7066 9772
    };
7067 9773
    return setNodeType(self, node, resultTy);
7068 9774
}
7069 9775
7070 -
/// Resolve a type signature node and set its type.
7071 -
fn inferTypeSig(self: *mut Resolver, node: *ast::Node, sig: ast::TypeSig) -> Type
7072 -
    throws (ResolveError)
7073 -
{
7074 -
    let resolved = try resolveTypeSig(self, node, sig);
7075 -
7076 -
    return setNodeType(self, node, resolved);
7077 -
}
7078 -
7079 -
/// Convert a type signature node into a type value.
7080 -
fn resolveTypeSig(self: *mut Resolver, node: *ast::Node, sig: ast::TypeSig) -> Type
7081 -
    throws (ResolveError)
7082 -
{
9776 +
/// Resolve type syntax in an ordinary or symbolic generic context.
9777 +
fn resolveTypeSyntax(
9778 +
    self: *mut Resolver,
9779 +
    node: *ast::Node,
9780 +
    context: TypeSyntaxContext,
9781 +
) -> Type throws (ResolveError) {
9782 +
    let case ast::NodeValue::TypeSig(sig) = node.value
9783 +
        else panic "resolveTypeSyntax: expected type signature";
9784 +
    let mut ty: Type = undefined;
7083 9785
    match sig {
7084 -
        case ast::TypeSig::Void => {
7085 -
            return Type::Void;
7086 -
        }
9786 +
        case ast::TypeSig::Void => set ty = Type::Void,
7087 9787
        case ast::TypeSig::Opaque => {
7088 -
            return Type::Opaque;
7089 -
        }
7090 -
        case ast::TypeSig::Bool => {
7091 -
            return Type::Bool;
9788 +
            if let case TypeSyntaxContext::Symbolic = context {
9789 +
                throw emitError(self, node, ErrorKind::OpaqueTypeNotAllowed);
9790 +
            }
9791 +
            set ty = Type::Opaque;
7092 9792
        }
9793 +
        case ast::TypeSig::Bool => set ty = Type::Bool,
7093 9794
        case ast::TypeSig::Integer { width, sign } => {
7094 -
            let u = sign == ast::Signedness::Unsigned;
9795 +
            let unsigned = sign == ast::Signedness::Unsigned;
7095 9796
            match width {
7096 -
                case 1 => return Type::U8 if u else Type::I8,
7097 -
                case 2 => return Type::U16 if u else Type::I16,
7098 -
                case 4 => return Type::U32 if u else Type::I32,
7099 -
                case 8 => return Type::U64 if u else Type::I64,
7100 -
                else => {
7101 -
                    panic "resolveTypeSig: invalid integer width";
7102 -
                }
9797 +
                case 1 => set ty = Type::U8 if unsigned else Type::I8,
9798 +
                case 2 => set ty = Type::U16 if unsigned else Type::I16,
9799 +
                case 4 => set ty = Type::U32 if unsigned else Type::I32,
9800 +
                case 8 => set ty = Type::U64 if unsigned else Type::I64,
9801 +
                else => panic "resolveTypeSyntax: invalid integer width",
7103 9802
            }
7104 9803
        }
7105 9804
        case ast::TypeSig::Array { itemType, length } => {
7106 -
            let item = try infer(self, itemType);
7107 -
            let length = try checkSizeInt(self, length);
7108 -
7109 -
            return Type::Array(ArrayType { item: allocType(self, item), length });
9805 +
            let item = try resolveTypeSyntax(self, itemType, context);
9806 +
            match context {
9807 +
                case TypeSyntaxContext::Concrete => {
9808 +
                    let concreteLength = try checkSizeInt(self, length);
9809 +
                    set ty = Type::Array(ArrayType {
9810 +
                        item: allocType(self, item),
9811 +
                        length: concreteLength,
9812 +
                    });
9813 +
                }
9814 +
                case TypeSyntaxContext::Symbolic => {
9815 +
                    let _ = try checkNumeric(self, length);
9816 +
                    if let value = constValueEntry(self, length) {
9817 +
                        if not validateConstIntRange(value, Type::U32) {
9818 +
                            throw emitError(
9819 +
                                self, length, ErrorKind::NumericLiteralOverflow
9820 +
                            );
9821 +
                        }
9822 +
                        let case ConstValue::Int(int) = value else {
9823 +
                            throw emitError(
9824 +
                                self, length, ErrorKind::ConstExprRequired
9825 +
                            );
9826 +
                        };
9827 +
                        set ty = Type::Array(ArrayType {
9828 +
                            item: allocType(self, item),
9829 +
                            length: int.magnitude as u32,
9830 +
                        });
9831 +
                    } else if isConstExpr(self, length) and
9832 +
                              containsGenericConstExpr(self, length)
9833 +
                    {
9834 +
                        set ty = Type::GenericArray {
9835 +
                            item: allocType(self, item),
9836 +
                            length,
9837 +
                        };
9838 +
                    } else {
9839 +
                        throw emitError(
9840 +
                            self, length, ErrorKind::ConstExprRequired
9841 +
                        );
9842 +
                    }
9843 +
                }
9844 +
            }
7110 9845
        }
7111 9846
        case ast::TypeSig::Slice { class, itemType, mutable } => {
7112 -
            let item = try infer(self, itemType);
7113 -
            return Type::Slice {
9847 +
            let item = try resolveTypeSyntax(self, itemType, context);
9848 +
            set ty = Type::Slice(SliceType {
7114 9849
                class,
7115 9850
                item: allocType(self, item),
7116 9851
                mutable,
7117 -
            };
9852 +
            });
7118 9853
        }
7119 9854
        case ast::TypeSig::Pointer { class, valueType, mutable } => {
7120 -
            let target = try infer(self, valueType);
7121 -
            return Type::Pointer {
9855 +
            let target = try resolveTypeSyntax(self, valueType, context);
9856 +
            set ty = Type::Pointer(PointerType {
7122 9857
                class,
7123 9858
                target: allocType(self, target),
7124 9859
                mutable,
7125 -
            };
9860 +
            });
7126 9861
        }
7127 9862
        case ast::TypeSig::Optional { valueType } => {
7128 -
            let payload = try infer(self, valueType);
7129 -
            return Type::Optional(allocType(self, payload));
9863 +
            let payload = try resolveTypeSyntax(self, valueType, context);
9864 +
            set ty = Type::Optional(allocType(self, payload));
7130 9865
        }
7131 9866
        case ast::TypeSig::Nominal(name) => {
7132 -
            let ty = try resolveTypeName(self, name);
7133 -
            return Type::Nominal(ty);
9867 +
            if let case TypeSyntaxContext::Symbolic = context {
9868 +
                if let case ast::NodeValue::GenericApply(app) = name.value {
9869 +
                    let templateSym = try resolveGenericDataTarget(self, app.target);
9870 +
                    try ensureGenericDataTemplate(self, templateSym);
9871 +
                    let template = genericTemplateFor(self, templateSym)
9872 +
                        else throw emitError(self, name, ErrorKind::Internal);
9873 +
                    if app.args.len <> template.params.len {
9874 +
                        throw emitError(
9875 +
                            self,
9876 +
                            name,
9877 +
                            ErrorKind::GenericArgumentCount(CountMismatch {
9878 +
                                expected: template.params.len,
9879 +
                                actual: app.args.len,
9880 +
                            }),
9881 +
                        );
9882 +
                    }
9883 +
                    let a = alloc::arenaAllocator(&mut self.arena);
9884 +
                    let mut args: *mut [*Type] = &mut [];
9885 +
                    for argNode, i in app.args {
9886 +
                        let arg = try resolveGenericArgument(
9887 +
                            self, argNode, template.params[i]
9888 +
                        );
9889 +
                        args.append(allocType(self, arg), a);
9890 +
                    }
9891 +
                    let symbolic = try! alloc::alloc(
9892 +
                        &mut self.arena,
9893 +
                        @sizeOf(GenericDataApplyType),
9894 +
                        @alignOf(GenericDataApplyType),
9895 +
                    ) as *mut GenericDataApplyType;
9896 +
                    set *symbolic = GenericDataApplyType {
9897 +
                        template: templateSym,
9898 +
                        args: &args[..],
9899 +
                        site: name,
9900 +
                    };
9901 +
                    return setNodeType(
9902 +
                        self, node, Type::GenericDataApply(symbolic)
9903 +
                    );
9904 +
                }
9905 +
            }
9906 +
            if let case ast::NodeValue::Ident(paramName) = name.value {
9907 +
                if mem::eq(paramName, "Self") {
9908 +
                    let selfType = self.currentTraitSelf else {
9909 +
                        throw emitError(
9910 +
                            self, name, ErrorKind::UnresolvedSymbol(paramName)
9911 +
                        );
9912 +
                    };
9913 +
                    set *selfType.used = true;
9914 +
                    set ty = Type::Parameter(selfType);
9915 +
                } else {
9916 +
                    let sym = findTypeSymbol(self.scope, paramName) else {
9917 +
                        throw emitError(
9918 +
                            self, name, ErrorKind::UnresolvedSymbol(paramName)
9919 +
                        );
9920 +
                    };
9921 +
                    match sym.data {
9922 +
                        case SymbolData::Type(nominal) => {
9923 +
                            if isGenericDeclaration(sym.node) {
9924 +
                                throw emitError(
9925 +
                                    self, name, ErrorKind::GenericArgumentsRequired
9926 +
                                );
9927 +
                            }
9928 +
                            setNodeSymbol(self, name, sym);
9929 +
                            set ty = Type::Nominal(nominal);
9930 +
                        }
9931 +
                        case SymbolData::TypeParameter(param) => {
9932 +
                            set *param.used = true;
9933 +
                            setNodeSymbol(self, name, sym);
9934 +
                            set ty = Type::Parameter(param);
9935 +
                        }
9936 +
                        else => throw emitError(
9937 +
                            self, name, ErrorKind::Internal
9938 +
                        ),
9939 +
                    }
9940 +
                }
9941 +
            } else {
9942 +
                let nominal = try resolveTypeName(self, name);
9943 +
                set ty = Type::Nominal(nominal);
9944 +
            }
7134 9945
        }
7135 9946
        case ast::TypeSig::Record { fields, labeled } => {
7136 -
            let recordType = try resolveRecordFields(self, node, fields, labeled);
7137 -
            let nominalTy = allocNominalType(self, NominalType::Record(recordType));
7138 -
            return Type::Nominal(nominalTy);
9947 +
            match context {
9948 +
                case TypeSyntaxContext::Concrete => {
9949 +
                    let recordType = try buildRecordType(
9950 +
                        self,
9951 +
                        node,
9952 +
                        fields,
9953 +
                        labeled,
9954 +
                        false,
9955 +
                        AggregateMemberSource::Ordinary,
9956 +
                    );
9957 +
                    set ty = Type::Nominal(allocNominalType(
9958 +
                        self, NominalType::Record(recordType)
9959 +
                    ));
9960 +
                }
9961 +
                case TypeSyntaxContext::Symbolic => {
9962 +
                    let a = alloc::arenaAllocator(&mut self.arena);
9963 +
                    let mut result: *mut [RecordField] = &mut [];
9964 +
                    for field in fields {
9965 +
                        let case ast::NodeValue::RecordField {
9966 +
                            field: fieldNameNode,
9967 +
                            type: typeNode,
9968 +
                            value,
9969 +
                        } = field.value else {
9970 +
                            panic "resolveTypeSyntax: invalid record field";
9971 +
                        };
9972 +
                        let fieldType = try resolveTypeSyntax(
9973 +
                            self, typeNode, context
9974 +
                        );
9975 +
                        try ensureStorableType(self, typeNode, fieldType);
9976 +
                        if let initializer = value {
9977 +
                            let _ = try checkAssignable(
9978 +
                                self, initializer, fieldType
9979 +
                            );
9980 +
                        }
9981 +
                        let mut fieldName: ?*[u8] = nil;
9982 +
                        if let nameNode = fieldNameNode {
9983 +
                            set fieldName = try nodeName(self, nameNode);
9984 +
                        }
9985 +
                        result.append(RecordField {
9986 +
                            name: fieldName,
9987 +
                            fieldType,
9988 +
                            offset: -1,
9989 +
                        }, a);
9990 +
                    }
9991 +
                    let genericRecord = try! alloc::alloc(
9992 +
                        &mut self.arena,
9993 +
                        @sizeOf(GenericRecordType),
9994 +
                        @alignOf(GenericRecordType),
9995 +
                    ) as *mut GenericRecordType;
9996 +
                    set *genericRecord = GenericRecordType {
9997 +
                        fields: &result[..],
9998 +
                        labeled,
9999 +
                    };
10000 +
                    set ty = Type::GenericRecord(genericRecord);
10001 +
                }
10002 +
            }
7139 10003
        }
7140 -
        case ast::TypeSig::Fn(t) => {
7141 -
            let a = alloc::arenaAllocator(&mut self.arena);
7142 -
            let mut paramTypes: *mut [*Type] = &mut [];
7143 -
            let mut throwList: *mut [*Type] = &mut [];
7144 -
7145 -
            if t.params.len > MAX_FN_PARAMS {
7146 -
                throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
7147 -
                    expected: MAX_FN_PARAMS,
7148 -
                    actual: t.params.len,
7149 -
                }));
10004 +
        case ast::TypeSig::Fn(signature) => {
10005 +
            if signature.params.len > MAX_FN_PARAMS {
10006 +
                throw emitError(self, node, ErrorKind::FnParamOverflow(
10007 +
                    CountMismatch {
10008 +
                        expected: MAX_FN_PARAMS,
10009 +
                        actual: signature.params.len,
10010 +
                    }
10011 +
                ));
7150 10012
            }
7151 -
            if t.throwList.len > MAX_FN_THROWS {
7152 -
                throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch {
7153 -
                    expected: MAX_FN_THROWS,
7154 -
                    actual: t.throwList.len,
7155 -
                }));
10013 +
            if signature.throwList.len > MAX_FN_THROWS {
10014 +
                throw emitError(self, node, ErrorKind::FnThrowOverflow(
10015 +
                    CountMismatch {
10016 +
                        expected: MAX_FN_THROWS,
10017 +
                        actual: signature.throwList.len,
10018 +
                    }
10019 +
                ));
7156 10020
            }
7157 -
7158 -
            for paramNode in t.params {
7159 -
                let paramTy = try resolveValueType(self, paramNode);
7160 -
                paramTypes.append(allocType(self, paramTy), a);
10021 +
            let a = alloc::arenaAllocator(&mut self.arena);
10022 +
            let mut params: *mut [*Type] = &mut [];
10023 +
            let mut throwTypes: *mut [*Type] = &mut [];
10024 +
            for param in signature.params {
10025 +
                let paramType = try resolveContextualValueType(
10026 +
                    self, param, context
10027 +
                );
10028 +
                params.append(allocType(self, paramType), a);
7161 10029
            }
7162 -
            for tyNode in t.throwList {
7163 -
                let throwTy = try resolveValueType(self, tyNode);
7164 -
                try ensureStorableType(self, tyNode, throwTy);
7165 -
                throwList.append(allocType(self, throwTy), a);
10030 +
            for throwNode in signature.throwList {
10031 +
                let throwType = try resolveContextualValueType(
10032 +
                    self, throwNode, context
10033 +
                );
10034 +
                try ensureStorableType(self, throwNode, throwType);
10035 +
                throwTypes.append(allocType(self, throwType), a);
7166 10036
            }
7167 -
            let mut retType = allocType(self, Type::Void);
7168 -
            if let ret = t.returnType {
7169 -
                let resolvedRet = try resolveValueType(self, ret);
7170 -
                try ensureStorableType(self, ret, resolvedRet);
7171 -
                set retType = allocType(self, resolvedRet);
10037 +
            let mut returnType = allocType(self, Type::Void);
10038 +
            if let returnNode = signature.returnType {
10039 +
                let resolved = try resolveContextualValueType(
10040 +
                    self, returnNode, context
10041 +
                );
10042 +
                try ensureStorableType(self, returnNode, resolved);
10043 +
                set returnType = allocType(self, resolved);
7172 10044
            }
7173 -
            let fnType = FnType {
7174 -
                paramTypes: &paramTypes[..],
7175 -
                returnType: retType,
7176 -
                throwList: &throwList[..],
10045 +
            set ty = Type::Fn(allocFnType(self, FnType {
10046 +
                paramTypes: &params[..],
10047 +
                returnType,
10048 +
                throwList: &throwTypes[..],
7177 10049
                isUnsafe: false,
7178 10050
                localCount: 0,
7179 -
            };
7180 -
            return Type::Fn(allocFnType(self, fnType));
10051 +
            }));
7181 10052
        }
7182 -
        // Resolve an opaque trait object signature.
7183 10053
        case ast::TypeSig::TraitObject { class, traitName, mutable } => {
7184 10054
            let sym = try resolveNamePath(self, traitName);
7185 10055
            let case SymbolData::Trait(traitInfo) = sym.data
7186 10056
                else throw emitError(self, traitName, ErrorKind::Internal);
10057 +
            if traitInfo.state == TraitState::Queued {
10058 +
                let case ast::NodeValue::TraitDecl {
10059 +
                    supertraits, methods, ..
10060 +
                } = sym.node.value else {
10061 +
                    throw emitError(self, traitName, ErrorKind::Internal);
10062 +
                };
10063 +
                try resolveTraitBody(self, sym.node, supertraits, methods);
10064 +
            }
10065 +
            if not traitInfo.objectSafe {
10066 +
                throw emitError(self, traitName, ErrorKind::TraitNotObjectSafe);
10067 +
            }
7187 10068
            setNodeSymbol(self, traitName, sym);
7188 -
7189 -
            return Type::TraitObject { class, traitInfo, mutable };
10069 +
            set ty = Type::TraitObject(TraitObjectType {
10070 +
                class,
10071 +
                traitInfo,
10072 +
                mutable,
10073 +
            });
7190 10074
        }
7191 10075
    }
10076 +
    return setNodeType(self, node, ty);
7192 10077
}
7193 10078
7194 10079
/// Check if a type can be used for inferrence.
7195 10080
fn isTypeInferrable(type: Type) -> bool {
7196 -
    if let case Type::Pointer { target, .. } = type {
7197 -
        return isTypeInferrable(*target);
10081 +
    if let case Type::Pointer(pointer) = type {
10082 +
        return isTypeInferrable(*pointer.target);
7198 10083
    }
7199 10084
    match type {
7200 10085
        case Type::Unknown, Type::Nil, Type::Undefined, Type::Int => return false,
7201 10086
        case Type::Array(ary) => return isTypeInferrable(*ary.item),
7202 10087
        case Type::Optional(opt) => return isTypeInferrable(*opt),
7240 10125
        return Diagnostics { errors: self.errors };
7241 10126
    };
7242 10127
    exitScope(self);
7243 10128
    setNodeType(self, root, Type::Void);
7244 10129
10130 +
    try closeGenericFnSpecializations(self) catch {
10131 +
        return Diagnostics { errors: self.errors };
10132 +
    };
10133 +
    try materializeGenericFnTypeUses(self) catch {
10134 +
        return Diagnostics { errors: self.errors };
10135 +
    };
10136 +
    try validateGenericDataRoots(self) catch {
10137 +
        return Diagnostics { errors: self.errors };
10138 +
    };
7245 10139
    return Diagnostics { errors: self.errors };
7246 10140
}
7247 10141
7248 10142
/// Analyze the module graph. This pass processes `mod` statements, creating symbols
7249 10143
/// and scopes for them, and also binds type names in each module so that cross-module
7286 10180
/// Resolve all type bodies in a module.
7287 10181
fn resolveTypeBodies(self: *mut Resolver, block: *ast::Block) throws (ResolveError) {
7288 10182
    for node in block.statements {
7289 10183
        match node.value {
7290 10184
            case ast::NodeValue::RecordDecl(decl) => {
7291 -
                try resolveRecordBody(self, node, decl) catch {
7292 -
                    // Continue resolving other types even if one fails.
7293 -
                };
10185 +
                if decl.params.len > 0 {
10186 +
                    try resolveGenericDataTemplate(
10187 +
                        self, node, decl.params, decl.fields, decl.derives
10188 +
                    ) catch {};
10189 +
                } else {
10190 +
                    try resolveRecordBody(self, node, decl) catch {
10191 +
                        // Continue resolving other types even if one fails.
10192 +
                    };
10193 +
                }
7294 10194
            }
7295 10195
            case ast::NodeValue::UnionDecl(decl) => {
7296 -
                try resolveUnionBody(self, node, decl) catch {
7297 -
                    // Continue resolving other types even if one fails.
7298 -
                };
10196 +
                if decl.params.len > 0 {
10197 +
                    try resolveGenericDataTemplate(
10198 +
                        self, node, decl.params, decl.variants, decl.derives
10199 +
                    ) catch {};
10200 +
                } else {
10201 +
                    try resolveUnionBody(self, node, decl) catch {
10202 +
                        // Continue resolving other types even if one fails.
10203 +
                    };
10204 +
                }
7299 10205
            }
7300 10206
            case ast::NodeValue::TraitDecl { supertraits, methods, .. } => {
7301 10207
                try resolveTraitBody(self, node, supertraits, methods) catch {
7302 10208
                    // Continue resolving other types even if one fails.
7303 10209
                };
7498 10404
        case ast::NodeValue::AddressOf(addr) => return linearRootSymbol(self, addr.target),
7499 10405
        case ast::NodeValue::FieldAccess(access) =>
7500 10406
            return linearRootSymbol(self, access.parent),
7501 10407
        case ast::NodeValue::Subscript { container, .. } =>
7502 10408
            return linearRootSymbol(self, container),
10409 +
        case ast::NodeValue::GenericApply(_) => return nil,
7503 10410
        case ast::NodeValue::Deref(target) => return linearRootSymbol(self, target),
7504 10411
        else => return nil,
7505 10412
    }
7506 10413
}
7507 10414
7747 10654
                let method = &traitInfo.methods[methodIndex];
7748 10655
                set receiverClass = method.receiverClass;
7749 10656
                set receiverMutable = method.mutable;
7750 10657
                set haveReceiver = true;
7751 10658
            }
10659 +
            case NodeExtra::GenericBoundMethodCall {
10660 +
                traitInfo, methodIndex, explicitReceiver, ..
10661 +
            } => {
10662 +
                if not explicitReceiver {
10663 +
                    let method = &traitInfo.methods[methodIndex];
10664 +
                    set receiverClass = method.receiverClass;
10665 +
                    set receiverMutable = method.mutable;
10666 +
                    set haveReceiver = true;
10667 +
                }
10668 +
            }
7752 10669
            case NodeExtra::MethodCall { method } => {
7753 10670
                set receiverClass = method.receiverClass;
7754 10671
                set receiverMutable = method.mutable;
7755 10672
                set haveReceiver = true;
7756 10673
            }
7776 10693
7777 10694
    for arg, i in call.args {
7778 10695
        let expected = *info.paramTypes[i];
7779 10696
        let root = linearRootSymbol(checker.resolver, arg);
7780 10697
        let mut argExclusive = isLinear(expected);
7781 -
        if let case Type::Pointer { class: types::PointerClass::Ref, mutable, .. } = expected {
10698 +
        if let case Type::Pointer(PointerType { class: types::PointerClass::Ref, mutable, .. }) = expected {
7782 10699
            set argExclusive = mutable;
7783 -
        } else if let case Type::Slice { class: types::PointerClass::Ref, mutable, .. } = expected {
10700 +
        } else if let case Type::Slice(SliceType {
10701 +
            class: types::PointerClass::Ref, mutable, ..
10702 +
        }) = expected {
7784 10703
            set argExclusive = mutable;
7785 -
        } else if let case Type::TraitObject {
10704 +
        } else if let case Type::TraitObject(TraitObjectType {
7786 10705
            class: types::PointerClass::Ref, mutable, ..
7787 -
        } = expected {
10706 +
        }) = expected {
7788 10707
            set argExclusive = mutable;
7789 10708
        }
7790 10709
        if not isUnsafePointerType(expected) {
7791 10710
            if let rootSym = root {
7792 10711
                for j in 0..rootsLen {
7920 10839
                    );
7921 10840
                }
7922 10841
                set env.available |= (1 as u64) << (index as u64);
7923 10842
            }
7924 10843
        }
10844 +
7925 10845
        case ast::NodeValue::Call(call) => try checkLinearCall(checker, env, node, call),
7926 10846
        case ast::NodeValue::AddressOf(addr) => {
7927 10847
            try checkLinearNode(checker, env, addr.target, LinearUse::Borrow);
7928 10848
        }
7929 10849
        case ast::NodeValue::Deref(target) => {
7950 10870
                }
7951 10871
            }
7952 10872
            try checkLinearNode(checker, env, container, LinearUse::Observe);
7953 10873
            try checkLinearNode(checker, env, index, LinearUse::Consume);
7954 10874
        }
10875 +
        case ast::NodeValue::GenericApply(_) => {
10876 +
            let extra = checker.resolver.nodeData.entries[node.id].extra;
10877 +
            if let case NodeExtra::GenericFnCall(_) = extra {
10878 +
                return;
10879 +
            }
10880 +
            if let case NodeExtra::GenericFnDependency(_) = extra {
10881 +
                return;
10882 +
            }
10883 +
            throw emitError(checker.resolver, node, ErrorKind::Internal);
10884 +
        }
7955 10885
        case ast::NodeValue::RecordLit(lit) => {
7956 10886
            for fieldNode in lit.fields {
7957 10887
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
7958 10888
                    else panic "checkLinearNode: expected field";
7959 10889
                try checkLinearNode(checker, env, field.value, LinearUse::Consume);
8312 11242
        let pkg = &packages[i];
8313 11243
        let diags = try resolvePackage(self, pkg.rootEntry, pkg.rootAst);
8314 11244
        if not success(&diags) {
8315 11245
            return diags;
8316 11246
        }
11247 +
        try closeGenericFnSpecializations(self) catch {
11248 +
            return Diagnostics { errors: self.errors };
11249 +
        };
11250 +
        try materializeGenericFnTypeUses(self) catch {
11251 +
            return Diagnostics { errors: self.errors };
11252 +
        };
8317 11253
    }
11254 +
    // Data roots are validated after every package and reachable generic body
11255 +
    // has had a chance to root its concrete specialization dependencies.
11256 +
    try validateGenericDataRoots(self) catch {
11257 +
        return Diagnostics { errors: self.errors };
11258 +
    };
8318 11259
    return Diagnostics { errors: self.errors };
8319 11260
}
8320 11261
8321 11262
/// Resolve a package.
8322 11263
fn resolvePackage(self: *mut Resolver, rootEntry: *module::ModuleEntry, node: *ast::Node) -> Diagnostics throws (ResolveError) {
8325 11266
        else panic "resolvePackage: module scope not found";
8326 11267
8327 11268
    // Set up the module scope for this package.
8328 11269
    set self.scope = scope;
8329 11270
    set self.currentMod = rootId;
11271 +
    set self.genericRoots = 0;
11272 +
    set self.genericSpecializationCount = 0;
8330 11273
8331 11274
    let case ast::NodeValue::Block(block) = node.value
8332 11275
        else panic "resolvePackage: expected block for module root";
8333 11276
8334 11277
    // Module graph analysis phase: bind all module name symbols and scopes.
lib/std/lang/resolver/printer.rad +135 -9
102 102
            io::print("i32");
103 103
        }
104 104
        case super::Type::I64 => {
105 105
            io::print("i64");
106 106
        }
107 -
        case super::Type::Pointer { class, target, mutable } => {
108 -
            printPtrPrefix(class, mutable);
109 -
            printTypeBody(*target, brief);
107 +
        case super::Type::Pointer(pointer) => {
108 +
            printPtrPrefix(pointer.class, pointer.mutable);
109 +
            printTypeBody(*pointer.target, brief);
110 110
        }
111 -
        case super::Type::Slice { class, item, mutable } => {
112 -
            printPtrPrefix(class, mutable);
111 +
        case super::Type::Slice(slice) => {
112 +
            printPtrPrefix(slice.class, slice.mutable);
113 113
            io::print("[");
114 -
            printTypeBody(*item, brief);
114 +
            printTypeBody(*slice.item, brief);
115 115
            io::print("]");
116 116
        }
117 117
        case super::Type::Array(array) => {
118 118
            io::print("[");
119 119
            printTypeBody(*array.item, brief);
120 120
            io::print("; ");
121 121
            io::printU32(array.length);
122 122
            io::print("]");
123 123
        }
124 +
        case super::Type::GenericArray { item, .. } => {
125 +
            io::print("[");
126 +
            printTypeBody(*item, brief);
127 +
            io::print("; <const>]");
128 +
        }
124 129
        case super::Type::Optional(inner) => {
125 130
            io::print("?");
126 131
            printTypeBody(*inner, brief);
127 132
        }
128 133
        case super::Type::Fn(fnType) => {
154 159
                printNominalTypeName(info);
155 160
            } else {
156 161
                printNominalType(info);
157 162
            }
158 163
        }
159 -
        case super::Type::TraitObject { class, traitInfo, mutable } => {
160 -
            printPtrPrefix(class, mutable);
164 +
        case super::Type::Parameter(param) => {
165 +
            io::print(param.name);
166 +
        }
167 +
        case super::Type::ConstParameter(param) => {
168 +
            io::print(param.name);
169 +
        }
170 +
        case super::Type::ConstArgument { .. } => {
171 +
            io::print("<const>");
172 +
        }
173 +
        case super::Type::GenericConstExpr { .. } => {
174 +
            io::print("<const-expr>");
175 +
        }
176 +
        case super::Type::GenericRecord(rec) => {
177 +
            io::print("{ ");
178 +
            for field, i in rec.fields {
179 +
                if i > 0 {
180 +
                    io::print(", ");
181 +
                }
182 +
                if let name = field.name {
183 +
                    io::print(name);
184 +
                    io::print(": ");
185 +
                }
186 +
                printTypeBody(field.fieldType, brief);
187 +
            }
188 +
            io::print(" }");
189 +
        }
190 +
        case super::Type::GenericDataApply(app) => {
191 +
            io::print(app.template.name);
192 +
            io::print("[");
193 +
            for arg, i in app.args {
194 +
                if i > 0 {
195 +
                    io::print(", ");
196 +
                }
197 +
                printTypeBody(*arg, brief);
198 +
            }
199 +
            io::print("]");
200 +
        }
201 +
        case super::Type::TraitObject(object) => {
202 +
            printPtrPrefix(object.class, object.mutable);
161 203
            io::print("opaque ");
162 -
            io::print(traitInfo.name);
204 +
            io::print(object.traitInfo.name);
163 205
        }
164 206
        case super::Type::Range { start, end } => {
165 207
            if let s = start {
166 208
                printTypeBody(*s, brief);
167 209
            }
476 518
            io::print("duplicate instance declaration for the same trait and type");
477 519
        }
478 520
        case super::ErrorKind::MissingTraitMethod(name) => {
479 521
            printQuoted("missing trait method '", name);
480 522
        }
523 +
        case super::ErrorKind::InheritedTraitMethod(name) => {
524 +
            printQuoted("cannot override inherited trait method '", name);
525 +
        }
481 526
        case super::ErrorKind::UnexpectedTraitName => {
482 527
            io::print("trait name cannot be used as a value");
483 528
        }
484 529
        case super::ErrorKind::TraitReceiverMismatch => {
485 530
            io::print("trait method receiver must be a pointer to the declaring trait");
486 531
        }
532 +
        case super::ErrorKind::TraitNotObjectSafe => {
533 +
            io::print("trait methods using `Self` cannot be used through an opaque object");
534 +
        }
535 +
        case super::ErrorKind::TraitInheritanceCycle => {
536 +
            io::print("supertrait declarations cannot form a cycle");
537 +
        }
538 +
        case super::ErrorKind::InvalidInstanceTarget => {
539 +
            io::print("instance target must be a supported concrete type");
540 +
        }
487 541
        case super::ErrorKind::TraitMethodSafetyMismatch => {
488 542
            io::print("trait method implementation has mismatched unsafe requirement");
489 543
        }
490 544
        case super::ErrorKind::FnParamOverflow(m) =>
491 545
            printMismatch("too many function parameters", "maximum", m),
506 560
            io::print("`let-else` fallback must terminate control flow");
507 561
        }
508 562
        case super::ErrorKind::LinearBranchMismatch(name) => {
509 563
            printQuoted("linear value has inconsistent branch state: '", name);
510 564
        }
565 +
        case super::ErrorKind::GenericBoundAmbiguous(name) => {
566 +
            printQuoted("generic bounds expose ambiguous method '", name);
567 +
        }
511 568
        case super::ErrorKind::LinearPartialMove => {
512 569
            io::print("cannot move a field out of a linear value");
513 570
        }
514 571
        case super::ErrorKind::LinearDiscard => {
515 572
            io::print("linear value cannot be discarded");
533 590
            io::print("unsafe pointer operation requires an unsafe declaration");
534 591
        }
535 592
        case super::ErrorKind::UnsafeCall => {
536 593
            io::print("calling an unsafe function requires an unsafe declaration");
537 594
        }
595 +
        case super::ErrorKind::GenericUnsupported => {
596 +
            io::print("invalid generic declaration or application");
597 +
        }
598 +
        case super::ErrorKind::GenericBoundNotTrait => {
599 +
            io::print("generic parameter bound must name a trait");
600 +
        }
601 +
        case super::ErrorKind::GenericConstUnsupported => {
602 +
            io::print("constant generic parameter type must be an integer");
603 +
        }
604 +
        case super::ErrorKind::GenericFnAttribute => {
605 +
            io::print("attribute is not supported on a generic function");
606 +
        }
607 +
        case super::ErrorKind::GenericFnNested => {
608 +
            io::print("generic functions must be declared at module scope");
609 +
        }
610 +
        case super::ErrorKind::GenericFnUnusedParameter(name) => {
611 +
            io::print("generic parameter `");
612 +
            io::print(name);
613 +
            io::print("` does not affect the function");
614 +
        }
615 +
        case super::ErrorKind::GenericFunctionExpected => {
616 +
            io::print("expected a generic function");
617 +
        }
618 +
        case super::ErrorKind::GenericBoundUnsatisfied(name) => {
619 +
            io::print("generic type argument does not satisfy bound `");
620 +
            io::print(name);
621 +
            io::print("`");
622 +
        }
623 +
        case super::ErrorKind::GenericFunctionInstantiationRequired => {
624 +
            io::print("generic function application requires an explicit instantiation");
625 +
        }
626 +
        case super::ErrorKind::GenericSpecializationChain => {
627 +
            io::print("generic specialization dependency depth exceeded");
628 +
        }
629 +
        case super::ErrorKind::GenericInferenceIncomplete => {
630 +
            io::print("cannot infer every generic type argument");
631 +
        }
632 +
        case super::ErrorKind::GenericInferenceConflict => {
633 +
            io::print("generic type argument inference found conflicting types");
634 +
        }
635 +
        case super::ErrorKind::GenericLayoutRequired => {
636 +
            io::print("generic type parameter does not have a concrete layout");
637 +
        }
638 +
        case super::ErrorKind::GenericRecursiveLayout => {
639 +
            io::print("generic specialization has infinitely recursive layout");
640 +
        }
641 +
        case super::ErrorKind::GenericArgumentsRequired => {
642 +
            io::print("generic declaration requires type arguments");
643 +
        }
644 +
        case super::ErrorKind::GenericInstantiationRequired => {
645 +
            io::print("generic data application requires an explicit instantiation");
646 +
        }
647 +
        case super::ErrorKind::GenericArgumentCount(mismatch) =>
648 +
            printMismatch("generic argument count", "expected", mismatch),
649 +
        case super::ErrorKind::GenericDataExpected => {
650 +
            io::print("expected a generic record or union");
651 +
        }
652 +
        case super::ErrorKind::GenericConcreteArgumentsRequired => {
653 +
            io::print("generic data specialization requires concrete type arguments");
654 +
        }
655 +
        case super::ErrorKind::GenericParameterLimit => {
656 +
            io::print("generic declaration has too many parameters");
657 +
        }
658 +
        case super::ErrorKind::GenericRootLimit => {
659 +
            io::print("package has too many generic instantiation roots");
660 +
        }
661 +
        case super::ErrorKind::GenericSpecializationLimit => {
662 +
            io::print("package has too many generic specializations");
663 +
        }
538 664
        case super::ErrorKind::Internal => {
539 665
            io::print("internal compiler error");
540 666
        }
541 667
        case super::ErrorKind::RecordFieldOutOfOrder { .. } => {
542 668
            io::print("record field out of order");
lib/std/lang/resolver/tests.rad +919 -10
237 237
        if let case super::ErrorKind::RecordFieldUnknown(actualName) = *actual {
238 238
            return mem::eq(actualName, expectedName);
239 239
        }
240 240
        return false;
241 241
    }
242 +
    if let case super::ErrorKind::GenericBoundAmbiguous(expectedName) = expected {
243 +
        if let case super::ErrorKind::GenericBoundAmbiguous(actualName) = *actual {
244 +
            return mem::eq(actualName, expectedName);
245 +
        }
246 +
        return false;
247 +
    }
242 248
    if let case super::ErrorKind::ArrayFieldUnknown(expectedName) = expected {
243 249
        if let case super::ErrorKind::ArrayFieldUnknown(actualName) = *actual {
244 250
            return mem::eq(actualName, expectedName);
245 251
        }
246 252
        return false;
273 279
        if let case super::ErrorKind::MissingTraitMethod(actualName) = *actual {
274 280
            return mem::eq(actualName, expectedName);
275 281
        }
276 282
        return false;
277 283
    }
284 +
    if let case super::ErrorKind::InheritedTraitMethod(expectedName) = expected {
285 +
        if let case super::ErrorKind::InheritedTraitMethod(actualName) = *actual {
286 +
            return mem::eq(actualName, expectedName);
287 +
        }
288 +
        return false;
289 +
    }
278 290
    if let case super::ErrorKind::MissingSupertraitInstance(expectedName) = expected {
279 291
        if let case super::ErrorKind::MissingSupertraitInstance(actualName) = *actual {
280 292
            return mem::eq(actualName, expectedName);
281 293
        }
282 294
        return false;
447 459
448 460
/// Require a slice type and return its element type.
449 461
fn expectSliceType(ty: super::Type, mutable: bool) -> super::Type
450 462
    throws (testing::TestError)
451 463
{
452 -
    let case super::Type::Slice { item, mutable: sliceMut, .. } = ty
464 +
    let case super::Type::Slice(super::SliceType {
465 +
        class: types::PointerClass::Owned, item, mutable: sliceMut
466 +
    }) = ty
453 467
        else throw testing::TestError::Failed;
454 468
    try testing::expect(sliceMut == mutable);
455 469
456 470
    return *item;
457 471
}
458 472
459 473
/// Require a pointer type and return its target type.
460 474
fn expectPointerType(ty: super::Type, mutable: bool) -> super::Type
461 475
    throws (testing::TestError)
462 476
{
463 -
    let case super::Type::Pointer { target, mutable: ptrMut, .. } = ty
477 +
    let case super::Type::Pointer(super::PointerType {
478 +
        class: types::PointerClass::Owned, target, mutable: ptrMut
479 +
    }) = ty
464 480
        else throw testing::TestError::Failed;
465 481
    try testing::expect(ptrMut == mutable);
466 482
467 483
    return *target;
468 484
}
3293 3309
    // Resolve should succeed: static is public.
3294 3310
    let result = try resolveModuleTree(&mut a, rootId);
3295 3311
    try expectNoErrors(&result);
3296 3312
}
3297 3313
3314 +
/// Qualified callable arrays remain subscripts rather than generic applications.
3315 +
@test fn testResolveQualifiedCallableSubscript() throws (testing::TestError) {
3316 +
    let mut a = testResolver();
3317 +
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3318 +
    let rootId = try registerModule(
3319 +
        &mut MODULE_GRAPH, nil, "root", "export mod values; mod app;", &mut arena
3320 +
    );
3321 +
    let _ = try registerModule(
3322 +
        &mut MODULE_GRAPH,
3323 +
        rootId,
3324 +
        "values",
3325 +
        "fn value() -> i32 { return 23; } export constant ITEMS: [fn() -> i32; 1] = [value];",
3326 +
        &mut arena,
3327 +
    );
3328 +
    let _ = try registerModule(
3329 +
        &mut MODULE_GRAPH,
3330 +
        rootId,
3331 +
        "app",
3332 +
        "use root::values; fn main() -> i32 { return values::ITEMS[0](); }",
3333 +
        &mut arena,
3334 +
    );
3335 +
    let result = try resolveModuleTree(&mut a, rootId);
3336 +
    try expectNoErrors(&result);
3337 +
}
3338 +
3298 3339
@test fn testResolveAccessSuper() throws (testing::TestError) {
3299 3340
    {
3300 3341
        let mut a = testResolver();
3301 3342
        let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3302 3343
3646 3687
    let mut a = testResolver();
3647 3688
    let result = try resolveProgramStr(&mut a, "fn f(a: i32) { let o: *opaque = &a; let ptr: *i32 = o; }");
3648 3689
    let err = try expectError(&result);
3649 3690
    let case super::ErrorKind::TypeMismatch(mismatch) = err.kind
3650 3691
        else throw testing::TestError::Failed;
3651 -
    let case super::Type::Pointer { target: expectedTarget, .. } = mismatch.expected
3692 +
    let case super::Type::Pointer(super::PointerType {
3693 +
        class: types::PointerClass::Owned, target: expectedTarget, ..
3694 +
    }) = mismatch.expected
3652 3695
        else throw testing::TestError::Failed;
3653 -
    let case super::Type::Pointer { target: actualTarget, .. } = mismatch.actual
3696 +
    let case super::Type::Pointer(super::PointerType {
3697 +
        class: types::PointerClass::Owned, target: actualTarget, ..
3698 +
    }) = mismatch.actual
3654 3699
        else throw testing::TestError::Failed;
3655 3700
3656 3701
    try testing::expect(*expectedTarget == super::Type::I32);
3657 3702
    try testing::expect(*actualTarget == super::Type::Opaque);
3658 3703
}
4381 4426
        else throw testing::TestError::Failed;
4382 4427
    let payloadSym = super::findSymbolInScope(scope, "x")
4383 4428
        else throw testing::TestError::Failed;
4384 4429
    let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
4385 4430
        else throw testing::TestError::Failed;
4386 -
    let case super::Type::Pointer { class: types::PointerClass::Ref, target, mutable } = payloadValType
4431 +
    let case super::Type::Pointer(super::PointerType {
4432 +
        class: types::PointerClass::Ref, target, mutable
4433 +
    }) = payloadValType
4387 4434
        else throw testing::TestError::Failed;
4388 -
    try testing::expect(not mutable);
4389 -
    try testing::expect(*target == super::Type::I32);
4435 +
    assert not mutable;
4436 +
    assert *target == super::Type::I32;
4390 4437
}
4391 4438
4392 4439
/// Test `match &mut opt` produces mutable pointer bindings.
4393 4440
@test fn testResolveMatchMutRefUnionBinding() throws (testing::TestError) {
4394 4441
    let mut a = testResolver();
4406 4453
        else throw testing::TestError::Failed;
4407 4454
    let payloadSym = super::findSymbolInScope(scope, "x")
4408 4455
        else throw testing::TestError::Failed;
4409 4456
    let case super::SymbolData::Value { type: payloadValType, .. } = payloadSym.data
4410 4457
        else throw testing::TestError::Failed;
4411 -
    let case super::Type::Pointer { class: types::PointerClass::Ref, target, mutable } = payloadValType
4458 +
    let case super::Type::Pointer(super::PointerType {
4459 +
        class: types::PointerClass::Ref, target, mutable
4460 +
    }) = payloadValType
4412 4461
        else throw testing::TestError::Failed;
4413 -
    try testing::expect(mutable);
4414 -
    try testing::expect(*target == super::Type::I32);
4462 +
    assert mutable;
4463 +
    assert *target == super::Type::I32;
4415 4464
}
4416 4465
4417 4466
/// Non-constant integer widening must use an explicit cast.
4418 4467
@test fn testResolveIntegerWideningRequiresCast() throws (testing::TestError) {
4419 4468
    {
5427 5476
    let mut a = testResolver();
5428 5477
    let program = "record Marker: Linear {} 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(); }";
5429 5478
    let result = try resolveProgramStr(&mut a, program);
5430 5479
    try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
5431 5480
}
5481 +
5482 +
/// Generic declarations retain rigid parameter identities and resolved bounds.
5483 +
@test fn testGenericTemplateMetadata() throws (testing::TestError) {
5484 +
    let mut a = testResolver();
5485 +
    let program = "trait Copy {} record Box⟨T: Copy⟩ { value: T } union Maybe⟨T⟩ { None, Some(T), Code(u32) } fn id⟨T: Copy⟩(value: T) -> T { return value; }";
5486 +
    let result = try resolveProgramStr(&mut a, program);
5487 +
    try expectNoErrors(&result);
5488 +
    let case ast::NodeValue::Block(block) = result.root.value
5489 +
        else throw testing::TestError::Failed;
5490 +
5491 +
    let boxSym = super::symbolFor(&a, block.statements[1])
5492 +
        else throw testing::TestError::Failed;
5493 +
    let boxTemplate = super::genericTemplateFor(&a, boxSym)
5494 +
        else throw testing::TestError::Failed;
5495 +
    assert boxTemplate.params.len == 1;
5496 +
    assert boxTemplate.params[0].bounds.len == 1;
5497 +
    assert boxTemplate.members.len == 1;
5498 +
    let case super::Type::Parameter(boxField) = *boxTemplate.members[0]
5499 +
        else throw testing::TestError::Failed;
5500 +
    assert boxField == boxTemplate.params[0];
5501 +
5502 +
    let maybeSym = super::symbolFor(&a, block.statements[2])
5503 +
        else throw testing::TestError::Failed;
5504 +
    let maybeTemplate = super::genericTemplateFor(&a, maybeSym)
5505 +
        else throw testing::TestError::Failed;
5506 +
    assert maybeTemplate.members.len == 3;
5507 +
    assert *maybeTemplate.members[0] == super::Type::Void;
5508 +
    let case super::Type::GenericRecord(payload) = *maybeTemplate.members[1]
5509 +
        else throw testing::TestError::Failed;
5510 +
    assert payload.fields.len == 1;
5511 +
    let case super::Type::Parameter(someType) = payload.fields[0].fieldType
5512 +
        else throw testing::TestError::Failed;
5513 +
    assert someType == maybeTemplate.params[0];
5514 +
    let concrete = super::allocType(&mut a, super::Type::U8);
5515 +
    let args: [*super::Type; 1] = [concrete];
5516 +
    let sub = super::Substitution { params: maybeTemplate.params, args: &args[..] };
5517 +
    let codeType = try super::substituteType(
5518 +
        &mut a, *maybeTemplate.members[2], &sub, block.statements[2]
5519 +
    ) catch {
5520 +
        throw testing::TestError::Failed;
5521 +
    };
5522 +
    let case super::Type::Nominal(super::NominalType::Record(codeRecord)) = codeType
5523 +
        else throw testing::TestError::Failed;
5524 +
    assert codeRecord.layout.size == 4;
5525 +
5526 +
    let fnSym = super::symbolFor(&a, block.statements[3])
5527 +
        else throw testing::TestError::Failed;
5528 +
    let fnTemplate = super::genericTemplateFor(&a, fnSym)
5529 +
        else throw testing::TestError::Failed;
5530 +
    let signature = fnTemplate.signature else throw testing::TestError::Failed;
5531 +
    let case super::Type::Parameter(argType) = *signature.paramTypes[0]
5532 +
        else throw testing::TestError::Failed;
5533 +
    let case super::Type::Parameter(returnType) = *signature.returnType
5534 +
        else throw testing::TestError::Failed;
5535 +
    assert argType == fnTemplate.params[0];
5536 +
    assert returnType == fnTemplate.params[0];
5537 +
}
5538 +
5539 +
/// Symbolic aggregate members retain rigid types through nested wrappers.
5540 +
@test fn testGenericNestedMemberTypes() throws (testing::TestError) {
5541 +
    let mut a = testResolver();
5542 +
    let result = try resolveProgramStr(
5543 +
        &mut a,
5544 +
        "union Wrapped⟨T⟩ { List([T; 2]), Maybe(?T), Apply(fn(T) -> T) }",
5545 +
    );
5546 +
    try expectNoErrors(&result);
5547 +
    let case ast::NodeValue::Block(block) = result.root.value
5548 +
        else throw testing::TestError::Failed;
5549 +
    let sym = super::symbolFor(&a, block.statements[0])
5550 +
        else throw testing::TestError::Failed;
5551 +
    let template = super::genericTemplateFor(&a, sym)
5552 +
        else throw testing::TestError::Failed;
5553 +
    assert template.members.len == 3;
5554 +
    for member in template.members {
5555 +
        assert super::containsGenericParameter(*member);
5556 +
    }
5557 +
    let concrete = super::allocType(&mut a, super::Type::U16);
5558 +
    let args: [*super::Type; 1] = [concrete];
5559 +
    let sub = super::Substitution { params: template.params, args: &args[..] };
5560 +
    for member in template.members {
5561 +
        let specialized = try super::substituteType(
5562 +
            &mut a, *member, &sub, block.statements[0]
5563 +
        ) catch {
5564 +
            throw testing::TestError::Failed;
5565 +
        };
5566 +
        let case super::Type::Nominal(super::NominalType::Record(_)) = specialized
5567 +
            else throw testing::TestError::Failed;
5568 +
    }
5569 +
}
5570 +
5571 +
/// Generic function signatures preserve rigid types inside compound types.
5572 +
@test fn testGenericNestedFunctionSignatureTypes() throws (testing::TestError) {
5573 +
    let mut a = testResolver();
5574 +
    let result = try resolveProgramStr(
5575 +
        &mut a,
5576 +
        "fn transform⟨T⟩(values: [T; 2], callback: fn(T) -> T) -> ?T { return nil; }",
5577 +
    );
5578 +
    try expectNoErrors(&result);
5579 +
    let case ast::NodeValue::Block(block) = result.root.value
5580 +
        else throw testing::TestError::Failed;
5581 +
    let sym = super::symbolFor(&a, block.statements[0])
5582 +
        else throw testing::TestError::Failed;
5583 +
    let template = super::genericTemplateFor(&a, sym)
5584 +
        else throw testing::TestError::Failed;
5585 +
    let signature = template.signature else throw testing::TestError::Failed;
5586 +
    assert signature.paramTypes.len == 2;
5587 +
    assert super::containsGenericParameter(*signature.paramTypes[0]);
5588 +
    assert super::containsGenericParameter(*signature.paramTypes[1]);
5589 +
    assert super::containsGenericParameter(*signature.returnType);
5590 +
}
5591 +
5592 +
/// Rigid parameters from separate declarations never compare as the same type.
5593 +
@test fn testGenericParameterIdentityIsDeclarationScoped() throws (testing::TestError) {
5594 +
    let mut a = testResolver();
5595 +
    let result = try resolveProgramStr(
5596 +
        &mut a,
5597 +
        "fn first⟨T⟩(value: T) -> T { return value; } fn second⟨T⟩(value: T) -> T { return value; }",
5598 +
    );
5599 +
    try expectNoErrors(&result);
5600 +
    let case ast::NodeValue::Block(block) = result.root.value
5601 +
        else throw testing::TestError::Failed;
5602 +
    let first = super::symbolFor(&a, block.statements[0])
5603 +
        else throw testing::TestError::Failed;
5604 +
    let second = super::symbolFor(&a, block.statements[1])
5605 +
        else throw testing::TestError::Failed;
5606 +
    let firstTemplate = super::genericTemplateFor(&a, first)
5607 +
        else throw testing::TestError::Failed;
5608 +
    let secondTemplate = super::genericTemplateFor(&a, second)
5609 +
        else throw testing::TestError::Failed;
5610 +
    assert firstTemplate.params[0] <> secondTemplate.params[0];
5611 +
    assert not super::typesEqual(
5612 +
        super::Type::Parameter(firstTemplate.params[0]),
5613 +
        super::Type::Parameter(secondTemplate.params[0]),
5614 +
    );
5615 +
}
5616 +
5617 +
/// Substitution recursively rewrites rigid parameters through composed types.
5618 +
@test fn testGenericTypeSubstitution() throws (testing::TestError) {
5619 +
    let mut a = testResolver();
5620 +
    let result = try resolveProgramStr(&mut a, "fn id⟨T⟩(value: T) -> T { return value; }");
5621 +
    try expectNoErrors(&result);
5622 +
    let case ast::NodeValue::Block(block) = result.root.value
5623 +
        else throw testing::TestError::Failed;
5624 +
    let sym = super::symbolFor(&a, block.statements[0])
5625 +
        else throw testing::TestError::Failed;
5626 +
    let template = super::genericTemplateFor(&a, sym)
5627 +
        else throw testing::TestError::Failed;
5628 +
    let rigid = super::Type::Parameter(template.params[0]);
5629 +
    let pointer = super::Type::Pointer(super::PointerType {
5630 +
        class: types::PointerClass::Owned,
5631 +
        target: super::allocType(&mut a, rigid),
5632 +
        mutable: true,
5633 +
    });
5634 +
    let symbolic = super::Type::Optional(super::allocType(&mut a, pointer));
5635 +
    let concrete = super::allocType(&mut a, super::Type::U32);
5636 +
    let args: [*super::Type; 1] = [concrete];
5637 +
    let sub = super::Substitution { params: template.params, args: &args[..] };
5638 +
    let replaced = try super::substituteType(
5639 +
        &mut a, symbolic, &sub, block.statements[0]
5640 +
    ) catch {
5641 +
        throw testing::TestError::Failed;
5642 +
    };
5643 +
    let case super::Type::Optional(inner) = replaced
5644 +
        else throw testing::TestError::Failed;
5645 +
    let case super::Type::Pointer(super::PointerType {
5646 +
        class: types::PointerClass::Owned, target, mutable
5647 +
    }) = *inner
5648 +
        else throw testing::TestError::Failed;
5649 +
    assert mutable;
5650 +
    assert *target == super::Type::U32;
5651 +
}
5652 +
5653 +
/// Duplicate generic parameter names are rejected in their declaration scope.
5654 +
@test fn testDuplicateGenericParameterRejected() throws (testing::TestError) {
5655 +
    let mut a = testResolver();
5656 +
    let result = try resolveProgramStr(&mut a, "fn duplicate⟨T, T⟩(value: T) {}");
5657 +
    let err = try expectError(&result);
5658 +
    let case super::ErrorKind::DuplicateBinding(name) = err.kind
5659 +
        else throw testing::TestError::Failed;
5660 +
    assert mem::eq(name, "T");
5661 +
}
5662 +
5663 +
/// Generic bounds must resolve to trait declarations.
5664 +
@test fn testGenericBoundMustBeTrait() throws (testing::TestError) {
5665 +
    let mut a = testResolver();
5666 +
    let result = try resolveProgramStr(
5667 +
        &mut a,
5668 +
        "record Value {} fn invalid⟨T: Value⟩(value: T) {}",
5669 +
    );
5670 +
    try expectErrorKind(&result, super::ErrorKind::GenericBoundNotTrait);
5671 +
}
5672 +
5673 +
/// Integer constant parameters specialize array layouts.
5674 +
@test fn testGenericConstParameterArrayLayout() throws (testing::TestError) {
5675 +
    let mut a = testResolver();
5676 +
    let result = try resolveProgramStr(
5677 +
        &mut a,
5678 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } instantiate Buffer⟨4⟩;",
5679 +
    );
5680 +
    try expectNoErrors(&result);
5681 +
    let case ast::NodeValue::Block(block) = result.root.value
5682 +
        else throw testing::TestError::Failed;
5683 +
    let case ast::NodeValue::Instantiate(applications) = block.statements[1].value
5684 +
        else throw testing::TestError::Failed;
5685 +
    let resolved = super::typeFor(&a, applications[0])
5686 +
        else throw testing::TestError::Failed;
5687 +
    let case super::Type::Nominal(nominal) = resolved
5688 +
        else throw testing::TestError::Failed;
5689 +
    let case super::NominalType::Record(recordType) = *nominal
5690 +
        else throw testing::TestError::Failed;
5691 +
    let case super::Type::Array(arrayType) = recordType.fields[0].fieldType
5692 +
        else throw testing::TestError::Failed;
5693 +
    assert arrayType.length == 4;
5694 +
    assert recordType.layout.size == 4;
5695 +
}
5696 +
5697 +
/// Equivalent integer expressions share a canonical specialization.
5698 +
@test fn testGenericConstParameterCanonical() throws (testing::TestError) {
5699 +
    let mut a = testResolver();
5700 +
    let result = try resolveProgramStr(
5701 +
        &mut a,
5702 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } instantiate Buffer⟨4⟩; instantiate Buffer⟨2 + 2⟩; instantiate Buffer⟨5⟩;",
5703 +
    );
5704 +
    try expectNoErrors(&result);
5705 +
    let case ast::NodeValue::Block(block) = result.root.value
5706 +
        else throw testing::TestError::Failed;
5707 +
    let case ast::NodeValue::Instantiate(firstApplications) = block.statements[1].value
5708 +
        else throw testing::TestError::Failed;
5709 +
    let case ast::NodeValue::Instantiate(equalApplications) = block.statements[2].value
5710 +
        else throw testing::TestError::Failed;
5711 +
    let case ast::NodeValue::Instantiate(otherApplications) = block.statements[3].value
5712 +
        else throw testing::TestError::Failed;
5713 +
    let firstType = super::typeFor(&a, firstApplications[0])
5714 +
        else throw testing::TestError::Failed;
5715 +
    let equalType = super::typeFor(&a, equalApplications[0])
5716 +
        else throw testing::TestError::Failed;
5717 +
    let otherType = super::typeFor(&a, otherApplications[0])
5718 +
        else throw testing::TestError::Failed;
5719 +
    let case super::Type::Nominal(first) = firstType
5720 +
        else throw testing::TestError::Failed;
5721 +
    let case super::Type::Nominal(equal) = equalType
5722 +
        else throw testing::TestError::Failed;
5723 +
    let case super::Type::Nominal(other) = otherType
5724 +
        else throw testing::TestError::Failed;
5725 +
    assert first == equal;
5726 +
    assert first <> other;
5727 +
}
5728 +
5729 +
/// Constant parameter declarations accept only concrete integer types.
5730 +
@test fn testGenericConstParameterTypeRejected() throws (testing::TestError) {
5731 +
    let mut a = testResolver();
5732 +
    let result = try resolveProgramStr(&mut a, "record Buffer⟨constant N: bool⟩ {}");
5733 +
    try expectErrorKind(&result, super::ErrorKind::GenericConstUnsupported);
5734 +
}
5735 +
5736 +
/// Constant arguments must be side-effect-free compile-time expressions.
5737 +
@test fn testGenericConstArgumentRequired() throws (testing::TestError) {
5738 +
    let mut a = testResolver();
5739 +
    let result = try resolveProgramStr(
5740 +
        &mut a,
5741 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } fn size() -> u32 { return 4; } instantiate Buffer⟨size()⟩;",
5742 +
    );
5743 +
    try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
5744 +
}
5745 +
5746 +
/// Constant arguments are checked against their declared integer width.
5747 +
@test fn testGenericConstArgumentOverflow() throws (testing::TestError) {
5748 +
    let mut a = testResolver();
5749 +
    let result = try resolveProgramStr(
5750 +
        &mut a,
5751 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } instantiate Buffer⟨4294967296⟩;",
5752 +
    );
5753 +
    try expectErrorKind(&result, super::ErrorKind::NumericLiteralOverflow);
5754 +
}
5755 +
5756 +
/// Constant parameters reject type-valued arguments.
5757 +
@test fn testGenericConstArgumentKindRejected() throws (testing::TestError) {
5758 +
    let mut a = testResolver();
5759 +
    let result = try resolveProgramStr(
5760 +
        &mut a,
5761 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } instantiate Buffer⟨u32⟩;",
5762 +
    );
5763 +
    try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
5764 +
}
5765 +
5766 +
/// Type parameters reject expression arguments.
5767 +
@test fn testGenericTypeArgumentKindRejected() throws (testing::TestError) {
5768 +
    let mut a = testResolver();
5769 +
    let result = try resolveProgramStr(
5770 +
        &mut a, "record Box⟨T⟩ { value: T } instantiate Box⟨4⟩;"
5771 +
    );
5772 +
    try expectErrorKind(&result, super::ErrorKind::GenericUnsupported);
5773 +
}
5774 +
5775 +
/// Generic declarations reject parameter lists beyond the implementation limit.
5776 +
@test fn testGenericParameterLimit() throws (testing::TestError) {
5777 +
    let mut a = testResolver();
5778 +
    let result = try resolveProgramStr(
5779 +
        &mut a,
5780 +
        "record TooMany⟨A, B, C, D, E, F, G, H, I⟩ {}",
5781 +
    );
5782 +
    try expectErrorKind(&result, super::ErrorKind::GenericParameterLimit);
5783 +
}
5784 +
5785 +
/// Rigid parameters cannot escape the declaration that introduces them.
5786 +
@test fn testGenericParameterOutsideTemplateUnresolved() throws (testing::TestError) {
5787 +
    let mut a = testResolver();
5788 +
    let result = try resolveProgramStr(&mut a, "fn invalid(value: T) {}");
5789 +
    let err = try expectError(&result);
5790 +
    let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
5791 +
        else throw testing::TestError::Failed;
5792 +
    assert mem::eq(name, "T");
5793 +
}
5794 +
5795 +
/// Layout-dependent builtins reject symbolic generic types.
5796 +
@test fn testGenericParameterLayoutRejected() throws (testing::TestError) {
5797 +
    let mut a = testResolver();
5798 +
    let result = try resolveProgramStr(
5799 +
        &mut a,
5800 +
        "record Sized⟨T⟩ { bytes: u32 = @sizeOf(T) }",
5801 +
    );
5802 +
    try expectErrorKind(&result, super::ErrorKind::GenericLayoutRequired);
5803 +
}
5804 +
5805 +
/// Generic data declarations cannot be used without specialization arguments.
5806 +
@test fn testGenericArgumentsRequired() throws (testing::TestError) {
5807 +
    let mut a = testResolver();
5808 +
    let result = try resolveProgramStr(
5809 +
        &mut a,
5810 +
        "record Box⟨T⟩ { value: T } fn invalid(value: Box) {}",
5811 +
    );
5812 +
    try expectErrorKind(&result, super::ErrorKind::GenericArgumentsRequired);
5813 +
}
5814 +
5815 +
/// Repeated concrete data applications share one canonical nominal type.
5816 +
@test fn testGenericDataSpecializationCanonical() throws (testing::TestError) {
5817 +
    let mut a = testResolver();
5818 +
    let program = "record Pair⟨T, U⟩ { first: T, second: U } union Maybe⟨T⟩ { None, Some(T) } fn roundtrip(value: Pair⟨i32, bool⟩) -> Pair⟨i32, bool⟩ { return value; } instantiate Pair⟨i32, bool⟩; instantiate Pair⟨i32, bool⟩; instantiate Pair⟨bool, i32⟩; instantiate Maybe⟨i32⟩;";
5819 +
    let result = try resolveProgramStr(&mut a, program);
5820 +
    try expectNoErrors(&result);
5821 +
    let case ast::NodeValue::Block(block) = result.root.value
5822 +
        else throw testing::TestError::Failed;
5823 +
    let case ast::NodeValue::Instantiate(firstApplications) = block.statements[3].value
5824 +
        else throw testing::TestError::Failed;
5825 +
    let case ast::NodeValue::Instantiate(secondApplications) = block.statements[4].value
5826 +
        else throw testing::TestError::Failed;
5827 +
    let case ast::NodeValue::Instantiate(reversedApplications) = block.statements[5].value
5828 +
        else throw testing::TestError::Failed;
5829 +
    let firstType = super::typeFor(&a, firstApplications[0])
5830 +
        else throw testing::TestError::Failed;
5831 +
    let secondType = super::typeFor(&a, secondApplications[0])
5832 +
        else throw testing::TestError::Failed;
5833 +
    let reversedType = super::typeFor(&a, reversedApplications[0])
5834 +
        else throw testing::TestError::Failed;
5835 +
    let case super::Type::Nominal(first) = firstType
5836 +
        else throw testing::TestError::Failed;
5837 +
    let case super::Type::Nominal(second) = secondType
5838 +
        else throw testing::TestError::Failed;
5839 +
    let case super::Type::Nominal(reversed) = reversedType
5840 +
        else throw testing::TestError::Failed;
5841 +
    assert first == second;
5842 +
    assert first <> reversed;
5843 +
    let case super::NominalType::Record(recordType) = *first
5844 +
        else throw testing::TestError::Failed;
5845 +
    assert recordType.fields.len == 2;
5846 +
    assert recordType.layout.size == 8;
5847 +
    let pairSym = super::symbolFor(&a, block.statements[0])
5848 +
        else throw testing::TestError::Failed;
5849 +
    let args: [*super::Type; 2] = [
5850 +
        super::allocType(&mut a, super::Type::I32),
5851 +
        super::allocType(&mut a, super::Type::Bool),
5852 +
    ];
5853 +
    let cached = super::findGenericDataSpecialization(&a, pairSym, &args[..])
5854 +
        else throw testing::TestError::Failed;
5855 +
    assert cached.rooted;
5856 +
}
5857 +
5858 +
/// Recursive applications reuse the in-progress canonical specialization.
5859 +
@test fn testGenericDataRecursiveSpecialization() throws (testing::TestError) {
5860 +
    let mut a = testResolver();
5861 +
    let result = try resolveProgramStr(
5862 +
        &mut a,
5863 +
        "record List⟨T⟩ { value: T, next: ?*List⟨T⟩ } instantiate List⟨i32⟩;",
5864 +
    );
5865 +
    try expectNoErrors(&result);
5866 +
    let case ast::NodeValue::Block(block) = result.root.value
5867 +
        else throw testing::TestError::Failed;
5868 +
    let case ast::NodeValue::Instantiate(applications) = block.statements[1].value
5869 +
        else throw testing::TestError::Failed;
5870 +
    let resolved = super::typeFor(&a, applications[0])
5871 +
        else throw testing::TestError::Failed;
5872 +
    let case super::Type::Nominal(listType) = resolved
5873 +
        else throw testing::TestError::Failed;
5874 +
    let case super::NominalType::Record(recordType) = *listType
5875 +
        else throw testing::TestError::Failed;
5876 +
    let case super::Type::Optional(optionalTarget) = recordType.fields[1].fieldType
5877 +
        else throw testing::TestError::Failed;
5878 +
    let case super::Type::Pointer(super::PointerType {
5879 +
        class: types::PointerClass::Owned, target, ..
5880 +
    }) = *optionalTarget
5881 +
        else throw testing::TestError::Failed;
5882 +
    let case super::Type::Nominal(nextType) = *target
5883 +
        else throw testing::TestError::Failed;
5884 +
    assert nextType == listType;
5885 +
}
5886 +
5887 +
/// Generic data applications diagnose arity before specialization.
5888 +
@test fn testGenericDataSpecializationArity() throws (testing::TestError) {
5889 +
    let mut a = testResolver();
5890 +
    let result = try resolveProgramStr(
5891 +
        &mut a,
5892 +
        "record Pair⟨T, U⟩ { first: T, second: U } instantiate Pair⟨i32⟩;",
5893 +
    );
5894 +
    let err = try expectError(&result);
5895 +
    let case super::ErrorKind::GenericArgumentCount(mismatch) = err.kind
5896 +
        else throw testing::TestError::Failed;
5897 +
    assert mismatch.expected == 2;
5898 +
    assert mismatch.actual == 1;
5899 +
}
5900 +
5901 +
/// By-value recursive specializations are rejected instead of recursing.
5902 +
@test fn testGenericDataRecursiveLayoutRejected() throws (testing::TestError) {
5903 +
    let mut a = testResolver();
5904 +
    let result = try resolveProgramStr(
5905 +
        &mut a,
5906 +
        "record Loop⟨T⟩ { next: Loop⟨T⟩ } instantiate Loop⟨i32⟩;",
5907 +
    );
5908 +
    try expectErrorKind(&result, super::ErrorKind::GenericRecursiveLayout);
5909 +
}
5910 +
5911 +
/// Concrete applications outside templates require an explicit root.
5912 +
@test fn testGenericDataInstantiationRequired() throws (testing::TestError) {
5913 +
    let mut a = testResolver();
5914 +
    let result = try resolveProgramStr(
5915 +
        &mut a,
5916 +
        "record Box⟨T⟩ { value: T } fn read(value: Box⟨i32⟩) -> i32 { return value.value; }",
5917 +
    );
5918 +
    try expectErrorKind(&result, super::ErrorKind::GenericInstantiationRequired);
5919 +
}
5920 +
5921 +
/// Substitution cannot introduce a stored reference into a generic record.
5922 +
@test fn testGenericRecordReferenceArgumentRejected() throws (testing::TestError) {
5923 +
    let mut a = testResolver();
5924 +
    let result = try resolveProgramStr(
5925 +
        &mut a,
5926 +
        "record Box⟨T⟩ { value: T } instantiate Box⟨&i32⟩;",
5927 +
    );
5928 +
    try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
5929 +
}
5930 +
5931 +
/// Substitution cannot introduce a stored reference into a generic union.
5932 +
@test fn testGenericUnionReferenceArgumentRejected() throws (testing::TestError) {
5933 +
    let mut a = testResolver();
5934 +
    let result = try resolveProgramStr(
5935 +
        &mut a,
5936 +
        "union Maybe⟨T⟩ { None, Some(T) } instantiate Maybe⟨&i32⟩;",
5937 +
    );
5938 +
    try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
5939 +
}
5940 +
5941 +
/// Roots traverse ordinary nominal containers to reach generic dependencies.
5942 +
@test fn testGenericDataRootThroughOrdinaryNominal() throws (testing::TestError) {
5943 +
    let mut a = testResolver();
5944 +
    let result = try resolveProgramStr(
5945 +
        &mut a,
5946 +
        "record Box⟨T⟩ { value: T } record Holder { value: Box⟨i32⟩ } record Root⟨T⟩ { value: T } instantiate Root⟨Holder⟩;",
5947 +
    );
5948 +
    try expectNoErrors(&result);
5949 +
}
5950 +
5951 +
/// Function instantiation roots create a concrete specialization.
5952 +
@test fn testGenericFunctionSpecializationRoot() throws (testing::TestError) {
5953 +
    let mut a = testResolver();
5954 +
    let result = try resolveProgramStr(
5955 +
        &mut a,
5956 +
        "fn id⟨T⟩(value: T) -> T { return value; } instantiate id⟨i32⟩;",
5957 +
    );
5958 +
    try expectNoErrors(&result);
5959 +
    let node = super::genericFnSpecializations(&a)
5960 +
        else throw testing::TestError::Failed;
5961 +
    assert node.args.len == 1;
5962 +
    assert *node.args[0] == super::Type::I32;
5963 +
}
5964 +
5965 +
/// Grouped instantiation declarations resolve every specialization root.
5966 +
@test fn testGroupedGenericSpecializationRoots() throws (testing::TestError) {
5967 +
    let mut a = testResolver();
5968 +
    let result = try resolveProgramStr(
5969 +
        &mut a,
5970 +
        "record Box⟨T⟩ { value: T } fn id⟨T⟩(value: T) -> T { return value; } instantiate Box⟨i32⟩, id⟨i32⟩, id⟨u64⟩;",
5971 +
    );
5972 +
    try expectNoErrors(&result);
5973 +
    let case ast::NodeValue::Block(block) = result.root.value
5974 +
        else throw testing::TestError::Failed;
5975 +
    let case ast::NodeValue::Instantiate(applications) = block.statements[2].value
5976 +
        else throw testing::TestError::Failed;
5977 +
    assert applications.len == 3;
5978 +
    assert super::typeFor(&a, applications[0]) <> nil;
5979 +
    let functions = super::genericFnSpecializations(&a)
5980 +
        else throw testing::TestError::Failed;
5981 +
    assert functions.next <> nil;
5982 +
}
5983 +
5984 +
/// Generic free-function bodies are checked with their rigid signature.
5985 +
@test fn testGenericFunctionBodyChecked() throws (testing::TestError) {
5986 +
    let mut a = testResolver();
5987 +
    let result = try resolveProgramStr(
5988 +
        &mut a,
5989 +
        "fn id⟨T⟩(value: T) -> T { return value; }",
5990 +
    );
5991 +
    try expectNoErrors(&result);
5992 +
    let case ast::NodeValue::Block(block) = result.root.value
5993 +
        else throw testing::TestError::Failed;
5994 +
    let sym = super::symbolFor(&a, block.statements[0])
5995 +
        else throw testing::TestError::Failed;
5996 +
    let template = super::genericTemplateFor(&a, sym)
5997 +
        else throw testing::TestError::Failed;
5998 +
    assert template.bodyResolved;
5999 +
    assert *template.params[0].used;
6000 +
}
6001 +
6002 +
/// Rigid parameters compose through pointers, optionals, and throws signatures.
6003 +
@test fn testGenericFunctionCompoundSignature() throws (testing::TestError) {
6004 +
    let mut a = testResolver();
6005 +
    let result = try resolveProgramStr(
6006 +
        &mut a,
6007 +
        "union Fault { Bad } fn pass⟨T⟩(value: *?T) -> *?T throws (Fault) { return value; }",
6008 +
    );
6009 +
    try expectNoErrors(&result);
6010 +
}
6011 +
6012 +
/// Concrete-only arithmetic is rejected while checking the template body.
6013 +
@test fn testGenericFunctionConcreteOperationRejected() throws (testing::TestError) {
6014 +
    let mut a = testResolver();
6015 +
    let result = try resolveProgramStr(
6016 +
        &mut a,
6017 +
        "fn add⟨T⟩(left: T, right: T) -> T { return left + right; }",
6018 +
    );
6019 +
    try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
6020 +
}
6021 +
6022 +
/// Type parameters used only by a body annotation still affect the template.
6023 +
@test fn testGenericFunctionBodyOnlyParameter() throws (testing::TestError) {
6024 +
    let mut a = testResolver();
6025 +
    let result = try resolveProgramStr(
6026 +
        &mut a,
6027 +
        "fn local⟨T⟩() { let value: ?T = nil; }",
6028 +
    );
6029 +
    try expectNoErrors(&result);
6030 +
}
6031 +
6032 +
/// Parameters that affect neither signature nor body are rejected.
6033 +
@test fn testGenericFunctionUnusedParameterRejected() throws (testing::TestError) {
6034 +
    let mut a = testResolver();
6035 +
    let result = try resolveProgramStr(
6036 +
        &mut a,
6037 +
        "fn unused⟨T⟩() {}",
6038 +
    );
6039 +
    let err = try expectError(&result);
6040 +
    let case super::ErrorKind::GenericFnUnusedParameter(name) = err.kind
6041 +
        else throw testing::TestError::Failed;
6042 +
    assert mem::eq(name, "T");
6043 +
}
6044 +
6045 +
/// Linkage and entry-point attributes are not valid on templates.
6046 +
@test fn testGenericFunctionAttributeRejected() throws (testing::TestError) {
6047 +
    let mut a = testResolver();
6048 +
    let result = try resolveProgramStr(
6049 +
        &mut a,
6050 +
        "fn external⟨T⟩(value: T) -> T;",
6051 +
    );
6052 +
    try expectErrorKind(&result, super::ErrorKind::GenericFnAttribute);
6053 +
    let mut b = testResolver();
6054 +
    let defaultResult = try resolveProgramStr(
6055 +
        &mut b,
6056 +
        "@default fn entry⟨T⟩(value: T) -> T { return value; }",
6057 +
    );
6058 +
    try expectErrorKind(&defaultResult, super::ErrorKind::GenericFnAttribute);
6059 +
}
6060 +
6061 +
/// Generic functions cannot introduce nested template scopes.
6062 +
@test fn testNestedGenericFunctionRejected() throws (testing::TestError) {
6063 +
    let mut a = testResolver();
6064 +
    let result = try resolveProgramStr(
6065 +
        &mut a,
6066 +
        "fn outer() { fn inner⟨T⟩(value: T) -> T { return value; } }",
6067 +
    );
6068 +
    try expectErrorKind(&result, super::ErrorKind::GenericFnNested);
6069 +
}
6070 +
6071 +
/// Bound method operations resolve through their declared trait.
6072 +
@test fn testGenericBoundMethodResolved() throws (testing::TestError) {
6073 +
    let mut a = testResolver();
6074 +
    let result = try resolveProgramStr(
6075 +
        &mut a,
6076 +
        "trait Copy { fn (&Copy) copy() -> Self; } fn duplicate⟨T: Copy⟩(value: T) -> T { return value.copy(); }",
6077 +
    );
6078 +
    try expectNoErrors(&result);
6079 +
}
6080 +
6081 +
/// Unqualified methods shared by multiple bounds are ambiguous.
6082 +
@test fn testGenericBoundMethodAmbiguous() throws (testing::TestError) {
6083 +
    let mut a = testResolver();
6084 +
    let result = try resolveProgramStr(
6085 +
        &mut a,
6086 +
        "trait A { fn (&A) run(); } trait B { fn (&B) run(); } fn invoke⟨T: A + B⟩(value: T) { value.run(); }",
6087 +
    );
6088 +
    try expectErrorKind(&result, super::ErrorKind::GenericBoundAmbiguous("run"));
6089 +
}
6090 +
6091 +
/// Qualified bound calls disambiguate methods shared by several traits.
6092 +
@test fn testGenericBoundMethodQualified() throws (testing::TestError) {
6093 +
    let mut a = testResolver();
6094 +
    let result = try resolveProgramStr(
6095 +
        &mut a,
6096 +
        "trait A { fn (&A) run() -> u32; } trait B { fn (&B) run() -> u32; } fn invoke⟨T: A + B⟩(value: T) -> u32 { return B::run(&value); }",
6097 +
    );
6098 +
    try expectNoErrors(&result);
6099 +
}
6100 +
6101 +
/// Qualified bound dispatch enforces unsafe receiver operations.
6102 +
@test fn testGenericBoundQualifiedUnsafeReceiverRejected() throws (testing::TestError) {
6103 +
    let mut a = testResolver();
6104 +
    let result = try resolveProgramStr(
6105 +
        &mut a,
6106 +
        "trait Read { fn (*Read) read(); } fn invoke⟨T: Read⟩(value: *unsafe T) { Read::read(value); }",
6107 +
    );
6108 +
    try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
6109 +
}
6110 +
6111 +
/// Qualified bound calls accept module-qualified trait paths.
6112 +
@test fn testGenericBoundQualifiedAcrossModule() throws (testing::TestError) {
6113 +
    let mut a = testResolver();
6114 +
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6115 +
    let rootId = try registerModule(
6116 +
        &mut MODULE_GRAPH, nil, "root", "export mod defs; mod app;", &mut arena
6117 +
    );
6118 +
    let _ = try registerModule(
6119 +
        &mut MODULE_GRAPH,
6120 +
        rootId,
6121 +
        "defs",
6122 +
        "export trait Read { fn (&Read) read() -> u32; }",
6123 +
        &mut arena,
6124 +
    );
6125 +
    let _ = try registerModule(
6126 +
        &mut MODULE_GRAPH,
6127 +
        rootId,
6128 +
        "app",
6129 +
        "use root::defs; fn invoke⟨T: defs::Read⟩(value: T) -> u32 { return defs::Read::read(&value); }",
6130 +
        &mut arena,
6131 +
    );
6132 +
    let result = try resolveModuleTree(&mut a, rootId);
6133 +
    try expectNoErrors(&result);
6134 +
}
6135 +
6136 +
/// Imported generic roots share their defining module's specialization.
6137 +
@test fn testGenericSpecializationAcrossModule() throws (testing::TestError) {
6138 +
    let mut a = testResolver();
6139 +
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6140 +
    let rootId = try registerModule(
6141 +
        &mut MODULE_GRAPH,
6142 +
        nil,
6143 +
        "root",
6144 +
        "export mod base; use base::*; instantiate base::identity⟨u32⟩; instantiate Box⟨u32⟩;",
6145 +
        &mut arena,
6146 +
    );
6147 +
    let baseId = try registerModule(
6148 +
        &mut MODULE_GRAPH,
6149 +
        rootId,
6150 +
        "base",
6151 +
        "export record Box⟨T⟩ { value: T } export fn identity⟨T⟩(value: T) -> T { return value; } instantiate identity⟨u32⟩; instantiate Box⟨u32⟩;",
6152 +
        &mut arena,
6153 +
    );
6154 +
    let result = try resolveModuleTree(&mut a, rootId);
6155 +
    try expectNoErrors(&result);
6156 +
6157 +
    let node = super::genericFnSpecializations(&a)
6158 +
        else throw testing::TestError::Failed;
6159 +
    assert node.next == nil;
6160 +
    assert node.template.moduleId == baseId;
6161 +
}
6162 +
6163 +
/// Qualified bound dispatch accepts computed receiver expressions.
6164 +
@test fn testGenericBoundQualifiedExpressionReceiver() throws (testing::TestError) {
6165 +
    let mut a = testResolver();
6166 +
    let result = try resolveProgramStr(
6167 +
        &mut a,
6168 +
        "trait Read { fn (*Read) read(); } fn borrow⟨T⟩(value: *T) -> *T { return value; } fn invoke⟨T: Read⟩(value: T) { Read::read(borrow(&value)); }",
6169 +
    );
6170 +
    try expectNoErrors(&result);
6171 +
}
6172 +
6173 +
/// Calls select a previously rooted concrete specialization.
6174 +
@test fn testGenericFunctionRootedCall() throws (testing::TestError) {
6175 +
    let mut a = testResolver();
6176 +
    let result = try resolveProgramStr(
6177 +
        &mut a,
6178 +
        "fn id⟨T⟩(value: T) -> T { return value; } instantiate id⟨i32⟩; fn run() -> i32 { return id⟨i32⟩(7); }",
6179 +
    );
6180 +
    try expectNoErrors(&result);
6181 +
}
6182 +
6183 +
/// Calls cannot implicitly create specialization roots.
6184 +
@test fn testGenericFunctionUnrootedCallRejected() throws (testing::TestError) {
6185 +
    let mut a = testResolver();
6186 +
    let result = try resolveProgramStr(
6187 +
        &mut a,
6188 +
        "fn id⟨T⟩(value: T) -> T { return value; } fn run() -> i32 { return id⟨i32⟩(7); }",
6189 +
    );
6190 +
    try expectErrorKind(
6191 +
        &result, super::ErrorKind::GenericFunctionInstantiationRequired
6192 +
    );
6193 +
}
6194 +
6195 +
/// A rooted template pulls symbolic callees into the specialization closure.
6196 +
@test fn testGenericFunctionDependencyClosure() throws (testing::TestError) {
6197 +
    let mut a = testResolver();
6198 +
    let result = try resolveProgramStr(
6199 +
        &mut a,
6200 +
        "fn id⟨T⟩(value: T) -> T { return value; } fn wrap⟨T⟩(value: T) -> T { return id⟨T⟩(value); } instantiate wrap⟨i32⟩;",
6201 +
    );
6202 +
    try expectNoErrors(&result);
6203 +
6204 +
    let mut count: u32 = 0;
6205 +
    let mut cursor = super::genericFnSpecializations(&a);
6206 +
    while let node = cursor {
6207 +
        set count += 1;
6208 +
        set cursor = node.next;
6209 +
    }
6210 +
    assert count == 2;
6211 +
}
6212 +
6213 +
/// Inference cannot create a specialization without an explicit root.
6214 +
@test fn testGenericFunctionInferredUnrootedCallRejected() throws (testing::TestError) {
6215 +
    let mut a = testResolver();
6216 +
    let result = try resolveProgramStr(
6217 +
        &mut a,
6218 +
        "fn id⟨T⟩(value: T) -> T { return value; } fn run(value: i32) -> i32 { return id(value); }",
6219 +
    );
6220 +
    try expectErrorKind(
6221 +
        &result, super::ErrorKind::GenericFunctionInstantiationRequired
6222 +
    );
6223 +
}
6224 +
6225 +
/// Exact argument evidence can select an already rooted specialization.
6226 +
@test fn testGenericFunctionCallInference() throws (testing::TestError) {
6227 +
    let mut a = testResolver();
6228 +
    let result = try resolveProgramStr(
6229 +
        &mut a,
6230 +
        "fn id⟨T⟩(value: T) -> T { return value; } instantiate id⟨i32⟩; instantiate id⟨i64⟩; fn run(value: i32) -> i32 { id(1); return id(value); }",
6231 +
    );
6232 +
    try expectNoErrors(&result);
6233 +
}
6234 +
6235 +
/// Inference requires evidence for every generic parameter.
6236 +
@test fn testGenericFunctionInferenceIncomplete() throws (testing::TestError) {
6237 +
    let mut a = testResolver();
6238 +
    let result = try resolveProgramStr(
6239 +
        &mut a,
6240 +
        "fn absent⟨T⟩() -> ?T { return nil; } fn run() { let value = absent(); }",
6241 +
    );
6242 +
    try expectErrorKind(&result, super::ErrorKind::GenericInferenceIncomplete);
6243 +
}
6244 +
6245 +
/// An already known result type can complete local inference.
6246 +
@test fn testGenericFunctionResultInference() throws (testing::TestError) {
6247 +
    let mut a = testResolver();
6248 +
    let result = try resolveProgramStr(
6249 +
        &mut a,
6250 +
        "fn absent⟨T⟩() -> ?T { return nil; } instantiate absent⟨i32⟩; fn run() { let value: ?i32 = absent(); }",
6251 +
    );
6252 +
    try expectNoErrors(&result);
6253 +
}
6254 +
6255 +
/// Multiple arguments cannot infer different types for one parameter.
6256 +
@test fn testGenericFunctionInferenceConflict() throws (testing::TestError) {
6257 +
    let mut a = testResolver();
6258 +
    let result = try resolveProgramStr(
6259 +
        &mut a,
6260 +
        "fn first⟨T⟩(left: T, right: T) -> T { return left; } fn run(left: i32, right: u32) { let value = first(left, right); }",
6261 +
    );
6262 +
    try expectErrorKind(&result, super::ErrorKind::GenericInferenceConflict);
6263 +
}
6264 +
6265 +
/// Structurally expanding recursion is rejected at the closure bound.
6266 +
@test fn testGenericFunctionExpandingRecursion() throws (testing::TestError) {
6267 +
    let mut a = testResolver();
6268 +
    let result = try resolveProgramStr(
6269 +
        &mut a,
6270 +
        "fn expand⟨T⟩() { let marker: ?T = nil; expand⟨*T⟩(); } instantiate expand⟨i32⟩;",
6271 +
    );
6272 +
    try expectErrorKind(&result, super::ErrorKind::GenericSpecializationChain);
6273 +
}
6274 +
6275 +
/// Trait `Self` is rigid in the declaration and concrete in an instance.
6276 +
@test fn testTraitSelfSubstitution() throws (testing::TestError) {
6277 +
    let mut a = testResolver();
6278 +
    let result = try resolveProgramStr(
6279 +
        &mut a,
6280 +
        "trait Select { fn (&Select) select(other: Self) -> Self; } instance Select for u32 { fn (value: &u32) select(other: u32) -> u32 { return other; } }",
6281 +
    );
6282 +
    try expectNoErrors(&result);
6283 +
}
6284 +
6285 +
/// Specialized nominal types are valid concrete instance targets.
6286 +
@test fn testGenericDataInstanceTarget() throws (testing::TestError) {
6287 +
    let mut a = testResolver();
6288 +
    let result = try resolveProgramStr(
6289 +
        &mut a,
6290 +
        "record Box⟨T⟩ { value: T } instantiate Box⟨u32⟩; trait Read { fn (&Read) read(); } instance Read for Box⟨u32⟩ { fn (value: &Box⟨u32⟩) read() {} }",
6291 +
    );
6292 +
    try expectNoErrors(&result);
6293 +
}
6294 +
6295 +
/// `Self` outside a trait declaration has no implicit binding.
6296 +
@test fn testTraitSelfOutsideTraitRejected() throws (testing::TestError) {
6297 +
    let mut a = testResolver();
6298 +
    let result = try resolveProgramStr(&mut a, "fn invalid(value: Self) {}");
6299 +
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Self"));
6300 +
}
6301 +
6302 +
/// A trait exposing `Self` cannot be erased behind an opaque object.
6303 +
@test fn testTraitSelfObjectSafety() throws (testing::TestError) {
6304 +
    let mut a = testResolver();
6305 +
    let result = try resolveProgramStr(
6306 +
        &mut a,
6307 +
        "trait Clone { fn (&Clone) clone() -> Self; } fn inspect(value: &opaque Clone) {}",
6308 +
    );
6309 +
    try expectErrorKind(&result, super::ErrorKind::TraitNotObjectSafe);
6310 +
}
6311 +
6312 +
/// Resolving a nested trait object preserves the enclosing trait's `Self`.
6313 +
@test fn testTraitSelfNestedTraitResolution() throws (testing::TestError) {
6314 +
    let mut a = testResolver();
6315 +
    let result = try resolveProgramStr(
6316 +
        &mut a,
6317 +
        "trait Convert { fn (&Convert) convert(reader: &opaque Reader, value: Self) -> Self; } trait Reader { fn (&Reader) read() -> u32; } record Value {} instance Convert for Value { fn (value: &Value) convert(reader: &opaque Reader, other: Value) -> Value { return other; } }",
6318 +
    );
6319 +
    try expectNoErrors(&result);
6320 +
}
6321 +
6322 +
/// Cyclic supertraits cannot expose partially constructed method tables.
6323 +
@test fn testTraitInheritanceCycleRejected() throws (testing::TestError) {
6324 +
    let mut a = testResolver();
6325 +
    let result = try resolveProgramStr(
6326 +
        &mut a,
6327 +
        "trait First: Second { fn (&First) first(); } trait Second: First { fn (&Second) second(); }",
6328 +
    );
6329 +
    try expectErrorKind(&result, super::ErrorKind::TraitInheritanceCycle);
6330 +
}
6331 +
6332 +
/// A subtrait instance inherits implementations from its supertrait instance.
6333 +
@test fn testInheritedTraitMethodOverrideRejected() throws (testing::TestError) {
6334 +
    let mut a = testResolver();
6335 +
    let result = try resolveProgramStr(
6336 +
        &mut a,
6337 +
        "trait Base { fn (&Base) value() -> u32; } trait Child: Base {} instance Base for u32 { fn (value: &u32) value() -> u32 { return 1; } } instance Child for u32 { fn (value: &u32) value() -> u32 { return 2; } }",
6338 +
    );
6339 +
    try expectErrorKind(&result, super::ErrorKind::InheritedTraitMethod("value"));
6340 +
}
lib/std/lang/scanner/tests.rad +35 -21
3 3
use std::testing;
4 4
5 5
/// String pool for testing.
6 6
static TEST_STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
7 7
8 +
/// Create a scanner for test source.
8 9
fn testScanner(source: *[u8]) -> super::Scanner {
9 10
    return super::scanner(super::SourceLoc::File("test.r"), source, &mut TEST_STRING_POOL);
10 11
}
11 12
12 13
@test fn testScanTokens() throws (testing::TestError) {
222 223
        try testing::expect(super::next(&mut s).kind == expectedKind);
223 224
    }
224 225
}
225 226
226 227
@test fn testScanKeywords() throws (testing::TestError) {
227 -
    let mut s = testScanner("nil mod not static unsafe");
228 -
    let tok1: super::Token = super::next(&mut s);
229 -
230 -
    try testing::expect(tok1.kind == super::TokenKind::Nil);
231 -
    try testing::expect(tok1.source.len == 3);
232 -
233 -
    let tok2: super::Token = super::next(&mut s);
234 -
    try testing::expect(tok2.kind == super::TokenKind::Mod);
235 -
    try testing::expect(tok2.source.len == 3);
236 -
237 -
    let tok3: super::Token = super::next(&mut s);
238 -
    try testing::expect(tok3.kind == super::TokenKind::Not);
239 -
    try testing::expect(tok3.source.len == 3);
240 -
241 -
    let tok4: super::Token = super::next(&mut s);
242 -
    try testing::expect(tok4.kind == super::TokenKind::Static);
243 -
    try testing::expect(tok4.source.len == 6);
244 -
245 -
    let tok5: super::Token = super::next(&mut s);
246 -
    try testing::expect(tok5.kind == super::TokenKind::Unsafe);
247 -
    try testing::expect(tok5.source.len == 6);
228 +
    let mut s = testScanner("constant instantiate nil mod not static unsafe");
229 +
    let expected: [super::TokenKind; 8] = [
230 +
        super::TokenKind::Constant,
231 +
        super::TokenKind::Instantiate,
232 +
        super::TokenKind::Nil,
233 +
        super::TokenKind::Mod,
234 +
        super::TokenKind::Not,
235 +
        super::TokenKind::Static,
236 +
        super::TokenKind::Unsafe,
237 +
        super::TokenKind::Eof,
238 +
    ];
239 +
    for kind in expected {
240 +
        assert super::next(&mut s).kind == kind;
241 +
    }
248 242
}
249 243
250 244
@test fn testScanVoidAsIdent() throws (testing::TestError) {
251 245
    let mut s = testScanner("void");
252 246
    let tok: super::Token = super::next(&mut s);
321 315
    try testing::expect(super::next(&mut s).kind == super::TokenKind::Ident);
322 316
    try testing::expect(super::next(&mut s).kind == super::TokenKind::Semicolon);
323 317
    try testing::expect(super::next(&mut s).kind == super::TokenKind::RBrace);
324 318
    try testing::expect(super::next(&mut s).kind == super::TokenKind::Eof);
325 319
}
320 +
321 +
@test fn testScanGenericDelimiters() throws (testing::TestError) {
322 +
    let mut s = testScanner("Pair⟨T⟩");
323 +
    assert super::next(&mut s).kind == super::TokenKind::Ident;
324 +
    let open = super::next(&mut s);
325 +
    assert open.kind == super::TokenKind::LAngle;
326 +
    assert mem::eq(open.source, "⟨");
327 +
    assert super::next(&mut s).kind == super::TokenKind::Ident;
328 +
    let close = super::next(&mut s);
329 +
    assert close.kind == super::TokenKind::RAngle;
330 +
    assert mem::eq(close.source, "⟩");
331 +
    assert super::next(&mut s).kind == super::TokenKind::Eof;
332 +
}
333 +
334 +
@test fn testRejectGenericDelimiterLookalikes() throws (testing::TestError) {
335 +
    // U+3008 LEFT ANGLE BRACKET, not U+27E8 MATHEMATICAL LEFT ANGLE BRACKET.
336 +
    let source: [u8; 3] = [0xe3, 0x80, 0x88];
337 +
    let mut s = testScanner(&source[..]);
338 +
    assert super::next(&mut s).kind == super::TokenKind::Invalid;
339 +
}
std.lib.test +1 -0
7 7
lib/std/lang/alloc/tests.rad
8 8
lib/std/lang/parser/tests.rad
9 9
lib/std/lang/module/tests.rad
10 10
lib/std/lang/scanner/tests.rad
11 11
lib/std/lang/resolver/tests.rad
12 +
lib/std/lang/lower/tests.rad
12 13
lib/std/lang/gen/bitset/tests.rad
test/runner.rad +12 -0
46 46
/// Maximum number of data bytes in a `.ras` test binary.
47 47
constant ASM_DATA_CAPACITY: u32 = 1024;
48 48
49 49
// Static storage for large buffers to avoid stack overflow.
50 50
// Tests run serially so sharing these is safe.
51 +
/// Source input buffer.
51 52
static SOURCE_BUF: [u8; SOURCE_BUF_SIZE] = undefined;
53 +
/// Expected snapshot buffer.
52 54
static EXPECTED_BUF: [u8; EXPECTED_BUF_SIZE] = undefined;
55 +
/// Actual output buffer.
53 56
static OUTPUT_BUF: [u8; OUTPUT_BUF_SIZE] = undefined;
57 +
/// AST arena storage.
54 58
static AST_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined;
59 +
/// IL arena storage.
55 60
static IL_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined;
61 +
/// Printer arena storage.
56 62
static PRINT_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined;
63 +
/// Resolver arena storage.
57 64
static RESOLVER_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined;
65 +
/// Resolver node metadata storage.
58 66
static NODE_DATA_STORAGE: [resolver::NodeData; MAX_NODE_DATA] = undefined;
67 +
/// Resolver diagnostic storage.
59 68
static ERROR_STORAGE: [resolver::Error; MAX_ERRORS] = undefined;
69 +
/// Assembler text storage.
60 70
static ASM_TEXT_STORAGE: [u32; ASM_TEXT_CAPACITY] = undefined;
71 +
/// Assembler data storage.
61 72
static ASM_DATA_STORAGE: [u8; ASM_DATA_CAPACITY] = undefined;
62 73
63 74
/// Strip a `//` comment from a line, preserving `//` inside quoted strings.
64 75
/// Returns the content before the comment, trimmed of trailing whitespace.
65 76
fn stripLine(line: *[u8]) -> *[u8] {
179 190
    let codeBytes = @sliceOf(code.ptr as *u8, code.len * rv64::INSTR_SIZE as u32);
180 191
181 192
    return unix::writeFileParts(path, &[headerBytes, codeBytes, roData, rwData]);
182 193
}
183 194
195 +
/// Assemble a source file into an RV64 image.
184 196
fn assembleBinary(sourcePath: *[u8], outputPath: *[u8]) -> bool {
185 197
    let source = unix::readFile(sourcePath, &mut SOURCE_BUF[..]) else {
186 198
        io::printError("error: could not read source: ");
187 199
        io::printError(sourcePath);
188 200
        io::printError("\n");
test/tests/generic.bound.dispatch.rad added +27 -0
1 +
//! Bounded generic calls dispatch directly to concrete instances.
2 +
//! returns: 4
3 +
4 +
trait Less {
5 +
    fn (&Less) less(other: &Self) -> bool;
6 +
}
7 +
8 +
instance Less for u32 {
9 +
    fn (value: &u32) less(other: &u32) -> bool {
10 +
        return *value < *other;
11 +
    }
12 +
}
13 +
14 +
/// Return the lesser value.
15 +
fn minimum⟨T: Less⟩(a: T, b: T) -> T {
16 +
    if a.less(&b) {
17 +
        return a;
18 +
    }
19 +
    return b;
20 +
}
21 +
22 +
instantiate minimum⟨u32⟩;
23 +
24 +
/// Exercise bounded generic dispatch.
25 +
@default fn main() -> i32 {
26 +
    return minimum⟨u32(4, 7) as i32;
27 +
}
test/tests/generic.bound.dispatch.ril added +32 -0
1 +
data $"vtable::u32 test::Less" align 8 {
2 +
    fn $"u32 test::Less::less";
3 +
}
4 +
5 +
fn w8 $"u32 test::Less::less"(w64 %0, w64 %1) {
6 +
  @entry0
7 +
    load w32 %2 %0 0;
8 +
    load w32 %3 %1 0;
9 +
    ult w32 %4 %2 %3;
10 +
    ret %4;
11 +
}
12 +
13 +
fn w32 $main() {
14 +
  @entry0
15 +
    call w32 %0 $"test::minimum⟨u32⟩"(4, 7);
16 +
    ret %0;
17 +
}
18 +
19 +
fn w32 $"test::minimum⟨u32⟩"(w32 %0, w32 %1) {
20 +
  @entry0
21 +
    reserve %2 4 4;
22 +
    store w32 %0 %2 0;
23 +
    reserve %3 4 4;
24 +
    store w32 %1 %3 0;
25 +
    call w8 %4 $"u32 test::Less::less"(%2, %3);
26 +
    br.ne w32 %4 0 @then1 @merge2;
27 +
  @then1
28 +
    ret %0;
29 +
  @merge2
30 +
    load w32 %5 %3 0;
31 +
    ret %5;
32 +
}
test/tests/generic.constant.dependency.rad added +18 -0
1 +
//! returns: 0
2 +
3 +
/// Return a constant generic argument.
4 +
fn inner⟨constant N: u32() -> u32 {
5 +
    return N;
6 +
}
7 +
8 +
/// Forward a constant generic argument.
9 +
fn outer⟨constant N: u32() -> u32 {
10 +
    return inner⟨N⟩();
11 +
}
12 +
13 +
instantiate outer⟨4⟩;
14 +
15 +
/// Exercise constant generic dependencies.
16 +
@default fn main() -> i32 {
17 +
    return outer⟨4() as i32 - 4;
18 +
}
test/tests/generic.constant.dependency.ril added +17 -0
1 +
fn w32 $main() {
2 +
  @entry0
3 +
    call w32 %0 $"test::outer⟨4⟩"();
4 +
    sub w32 %1 %0 4;
5 +
    ret %1;
6 +
}
7 +
8 +
fn w32 $"test::inner⟨4⟩"() {
9 +
  @entry0
10 +
    ret 4;
11 +
}
12 +
13 +
fn w32 $"test::outer⟨4⟩"() {
14 +
  @entry0
15 +
    call w32 %0 $"test::inner⟨4⟩"();
16 +
    ret %0;
17 +
}
test/tests/generic.constant.rad added +32 -0
1 +
//! returns: 0
2 +
3 +
/// Inline storage with a generic capacity.
4 +
record InlineVec⟨T, constant N: u32{
5 +
    /// Element storage.
6 +
    data: [T; N],
7 +
    /// Number of initialized elements.
8 +
    len: u32,
9 +
}
10 +
11 +
/// Nested storage with a derived generic capacity.
12 +
record Nested⟨constant N: u32{
13 +
    /// Storage whose capacity is one greater than `N`.
14 +
    inner: InlineVec⟨u8, N + 1⟩,
15 +
}
16 +
17 +
/// Return an array's capacity and first element.
18 +
fn capacity⟨constant N: u32(items: [u8; N]) -> u32 {
19 +
    return items.len + items[0] as u32;
20 +
}
21 +
22 +
instantiate InlineVec⟨u8, 4⟩;
23 +
instantiate Nested⟨3⟩;
24 +
instantiate capacity⟨4⟩;
25 +
26 +
/// Exercise constant generic records and functions.
27 +
@default fn main() -> i32 {
28 +
    let vector = InlineVec⟨u8, 4{ data: [4, 3, 2, 1], len: 4 };
29 +
    let nested = Nested⟨3{ inner: vector };
30 +
    let result = capacity⟨4(nested.inner.data);
31 +
    return result as i32 - 8;
32 +
}
test/tests/generic.constant.ril added +24 -0
1 +
fn w32 $main() {
2 +
  @entry0
3 +
    reserve %0 8 4;
4 +
    reserve %1 4 1;
5 +
    store w8 4 %1 0;
6 +
    store w8 3 %1 1;
7 +
    store w8 2 %1 2;
8 +
    store w8 1 %1 3;
9 +
    blit %0 %1 4;
10 +
    store w32 4 %0 4;
11 +
    reserve %2 8 4;
12 +
    blit %2 %0 8;
13 +
    call w32 %3 $"test::capacity⟨4⟩"(%2);
14 +
    sub w32 %4 %3 8;
15 +
    ret %4;
16 +
}
17 +
18 +
fn w32 $"test::capacity⟨4⟩"(w64 %0) {
19 +
  @entry0
20 +
    load w8 %1 %0 0;
21 +
    zext w8 %2 %1;
22 +
    add w32 %3 4 %2;
23 +
    ret %3;
24 +
}
test/tests/generic.constant.union.rad added +16 -0
1 +
//! returns: 0
2 +
3 +
/// Union whose discriminant depends on a constant argument.
4 +
union Code⟨constant N: u32{
5 +
    /// Variant whose discriminant is `N`.
6 +
    First = N,
7 +
    /// Variant following `First`.
8 +
    Second,
9 +
}
10 +
11 +
instantiate Code⟨4⟩;
12 +
13 +
/// Exercise a constant generic union.
14 +
@default fn main() -> i32 {
15 +
    return Code⟨4::First as i32 - 4;
16 +
}
test/tests/generic.constant.union.ril added +6 -0
1 +
fn w32 $main() {
2 +
  @entry0
3 +
    zext w8 %0 4;
4 +
    sub w32 %1 %0 4;
5 +
    ret %1;
6 +
}
test/tests/generic.function.call.rad added +59 -0
1 +
//! returns: 67
2 +
3 +
/// Two-word aggregate.
4 +
record Pair {
5 +
    /// First word.
6 +
    first: i32,
7 +
    /// Second word.
8 +
    second: i32,
9 +
}
10 +
11 +
/// Five-word aggregate.
12 +
record Large {
13 +
    /// First word.
14 +
    a: i32,
15 +
    /// Second word.
16 +
    b: i32,
17 +
    /// Third word.
18 +
    c: i32,
19 +
    /// Fourth word.
20 +
    d: i32,
21 +
    /// Fifth word.
22 +
    e: i32,
23 +
}
24 +
25 +
/// Generic value wrapper.
26 +
record Box⟨T⟩ {
27 +
    /// Wrapped value.
28 +
    value: T,
29 +
}
30 +
31 +
/// Return a value unchanged.
32 +
fn identity⟨T⟩(value: T) -> T { return value; }
33 +
34 +
/// Return a pointer unchanged.
35 +
fn pointer⟨T⟩(value: *T) -> *T { return value; }
36 +
37 +
/// Pass a value through a generic call.
38 +
fn passt⟨T⟩(value: T) -> T { return value; }
39 +
40 +
instantiate Box⟨i32⟩,
41 +
            identity⟨i32⟩,
42 +
            pointer⟨i32⟩,
43 +
            passt⟨Pair⟩,
44 +
            passt⟨Large⟩,
45 +
            passt⟨Box⟨i32⟩⟩;
46 +
47 +
/// Exercise generic calls for scalar and aggregate values.
48 +
@default fn main() -> i32 {
49 +
    let number: i32 = 11;
50 +
    let pair = Pair { first: 5, second: 13 };
51 +
    let large = Large { a: 3, b: 5, c: 7, d: 11, e: 19 };
52 +
    let boxed = Box⟨i32{ value: 17 };
53 +
    let identify = identity⟨i32⟩;
54 +
    return identify(7)
55 +
        + passt⟨Pair⟩(pair).second
56 +
        + passt⟨Large⟩(large).e
57 +
        + *pointer⟨i32(&number)
58 +
        + passt⟨Box⟨i32⟩⟩(boxed).value;
59 +
}
test/tests/generic.function.graph.rad added +48 -0
1 +
//! returns: 0
2 +
3 +
/// Return a value unchanged.
4 +
fn identity⟨T⟩(value: T) -> T {
5 +
    return value;
6 +
}
7 +
8 +
/// Forward a value through a generic dependency.
9 +
fn wrap⟨T⟩(value: T) -> T {
10 +
    return identity⟨T⟩(value);
11 +
}
12 +
13 +
/// Recurse within one generic specialization.
14 +
fn countdown⟨T⟩(value: T, count: i32) -> T {
15 +
    if count == 0 {
16 +
        return value;
17 +
    }
18 +
    return countdown⟨T⟩(value, count - 1);
19 +
}
20 +
21 +
/// Enter a mutually recursive generic call graph.
22 +
fn ping⟨T⟩(value: T, count: i32) -> T {
23 +
    if count == 0 {
24 +
        return value;
25 +
    }
26 +
    return pong⟨T⟩(value, count - 1);
27 +
}
28 +
29 +
/// Complete a mutually recursive generic call graph.
30 +
fn pong⟨T⟩(value: T, count: i32) -> T {
31 +
    if count == 0 {
32 +
        return value;
33 +
    }
34 +
    return ping⟨T⟩(value, count - 1);
35 +
}
36 +
37 +
instantiate wrap⟨i32⟩;
38 +
instantiate countdown⟨i32⟩;
39 +
instantiate ping⟨i32⟩;
40 +
41 +
/// Exercise generic call graph specialization.
42 +
@default fn main() -> i32 {
43 +
    let value: i32 = 7;
44 +
    assert wrap(value) == 7;
45 +
    assert countdown(value, 3) == 7;
46 +
    assert ping(value, 4) == 7;
47 +
    return 0;
48 +
}
test/tests/generic.function.graph.ril added +63 -0
1 +
fn w32 $main() {
2 +
  @entry0
3 +
    call w32 %0 $"test::wrap⟨i32⟩"(7);
4 +
    br.eq w32 %0 7 @assert.ok2 @assert.fail1;
5 +
  @assert.fail1
6 +
    unreachable;
7 +
  @assert.ok2
8 +
    call w32 %1 $"test::countdown⟨i32⟩"(7, 3);
9 +
    br.eq w32 %1 7 @assert.ok4 @assert.fail3;
10 +
  @assert.fail3
11 +
    unreachable;
12 +
  @assert.ok4
13 +
    call w32 %2 $"test::ping⟨i32⟩"(7, 4);
14 +
    br.eq w32 %2 7 @assert.ok6 @assert.fail5;
15 +
  @assert.fail5
16 +
    unreachable;
17 +
  @assert.ok6
18 +
    ret 0;
19 +
}
20 +
21 +
fn w32 $"test::identity⟨i32⟩"(w32 %0) {
22 +
  @entry0
23 +
    ret %0;
24 +
}
25 +
26 +
fn w32 $"test::pong⟨i32⟩"(w32 %0, w32 %1) {
27 +
  @entry0
28 +
    br.eq w32 %1 0 @then1 @merge2;
29 +
  @then1
30 +
    ret %0;
31 +
  @merge2
32 +
    sub w32 %2 %1 1;
33 +
    call w32 %3 $"test::ping⟨i32⟩"(%0, %2);
34 +
    ret %3;
35 +
}
36 +
37 +
fn w32 $"test::ping⟨i32⟩"(w32 %0, w32 %1) {
38 +
  @entry0
39 +
    br.eq w32 %1 0 @then1 @merge2;
40 +
  @then1
41 +
    ret %0;
42 +
  @merge2
43 +
    sub w32 %2 %1 1;
44 +
    call w32 %3 $"test::pong⟨i32⟩"(%0, %2);
45 +
    ret %3;
46 +
}
47 +
48 +
fn w32 $"test::countdown⟨i32⟩"(w32 %0, w32 %1) {
49 +
  @entry0
50 +
    br.eq w32 %1 0 @then1 @merge2;
51 +
  @then1
52 +
    ret %0;
53 +
  @merge2
54 +
    sub w32 %2 %1 1;
55 +
    call w32 %3 $"test::countdown⟨i32⟩"(%0, %2);
56 +
    ret %3;
57 +
}
58 +
59 +
fn w32 $"test::wrap⟨i32⟩"(w32 %0) {
60 +
  @entry0
61 +
    call w32 %1 $"test::identity⟨i32⟩"(%0);
62 +
    ret %1;
63 +
}
test/tests/generic.function.rad added +79 -0
1 +
/// Two-word aggregate used by generic tests.
2 +
record Pair {
3 +
    /// First word.
4 +
    first: i32,
5 +
    /// Second word.
6 +
    second: i32,
7 +
}
8 +
9 +
/// Error used by generic throwing functions.
10 +
union Fault {
11 +
    /// Generic operation failed.
12 +
    Bad,
13 +
}
14 +
15 +
/// Generic value wrapper.
16 +
record Box⟨T⟩ {
17 +
    /// Wrapped value.
18 +
    value: T,
19 +
}
20 +
21 +
/// Marker trait used by generic trait-object tests.
22 +
trait Marker {}
23 +
24 +
/// Return a value unchanged.
25 +
fn identity⟨T⟩(value: T) -> T {
26 +
    return value;
27 +
}
28 +
29 +
/// Return a pointer unchanged.
30 +
fn pointer⟨T⟩(value: *T) -> *T {
31 +
    return value;
32 +
}
33 +
34 +
/// Return an optional value unchanged.
35 +
fn optional⟨T⟩(value: ?T) -> ?T {
36 +
    return value;
37 +
}
38 +
39 +
/// Return a value through a throwing generic function.
40 +
fn fallible⟨T⟩(value: T) -> T throws (Fault) {
41 +
    return value;
42 +
}
43 +
44 +
/// Lift a value into an optional.
45 +
fn some⟨T⟩(value: T) -> ?T {
46 +
    return value;
47 +
}
48 +
49 +
/// Return a generic slice.
50 +
fn reslice⟨T⟩(items: *[T]) -> *[T] {
51 +
    return &items[..];
52 +
}
53 +
54 +
/// Return the last item or a fallback.
55 +
fn last⟨T⟩(items: *[T], fallback: T) -> T {
56 +
    let mut result = fallback;
57 +
    for item in items {
58 +
        set result = item;
59 +
    }
60 +
    return result;
61 +
}
62 +
63 +
instantiate Box⟨i32⟩;
64 +
instantiate identity⟨i32⟩;
65 +
instantiate identity⟨u64⟩;
66 +
instantiate pointer⟨i32⟩;
67 +
instantiate identity⟨Box⟨i32⟩⟩;
68 +
instantiate identity⟨*opaque Marker⟩;
69 +
instantiate optional⟨i32⟩;
70 +
instantiate optional⟨Pair⟩;
71 +
72 +
instantiate fallible⟨i32⟩;
73 +
instantiate some⟨i32⟩;
74 +
instantiate some⟨Pair⟩;
75 +
instantiate reslice⟨i32⟩;
76 +
instantiate reslice⟨Pair⟩;
77 +
instantiate last⟨i32⟩;
78 +
instantiate last⟨Pair⟩;
79 +
instantiate fallible⟨Pair⟩;
test/tests/generic.function.ril added +137 -0
1 +
fn w64 $"test::fallible⟨test::Pair⟩"(w64 %0, w64 %1) {
2 +
  @entry0
3 +
    reserve %2 16 8;
4 +
    store w64 0 %2 0;
5 +
    add w64 %3 %2 8;
6 +
    blit %3 %1 8;
7 +
    blit %0 %2 16;
8 +
    ret %0;
9 +
}
10 +
11 +
fn w64 $"test::last⟨test::Pair⟩"(w64 %0, w64 %1) {
12 +
  @entry0
13 +
    reserve %2 8 4;
14 +
    blit %2 %1 8;
15 +
    load w32 %3 %0 8;
16 +
    load w64 %4 %0 0;
17 +
    jmp @loop1(0, %2);
18 +
  @loop1(w32 %5, w64 %8)
19 +
    br.slt w32 %5 %3 @body2 @merge3;
20 +
  @body2
21 +
    mul w64 %6 %5 8;
22 +
    add w64 %7 %4 %6;
23 +
    blit %8 %7 8;
24 +
    add w32 %9 %5 1;
25 +
    jmp @loop1(%9, %8);
26 +
  @merge3
27 +
    load w64 %10 %8 0;
28 +
    ret %10;
29 +
}
30 +
31 +
fn w32 $"test::last⟨i32⟩"(w64 %0, w32 %1) {
32 +
  @entry0
33 +
    load w32 %2 %0 8;
34 +
    load w64 %3 %0 0;
35 +
    jmp @loop1(0, %1);
36 +
  @loop1(w32 %4, w32 %9)
37 +
    br.slt w32 %4 %2 @body2 @merge3;
38 +
  @body2
39 +
    mul w64 %5 %4 4;
40 +
    add w64 %6 %3 %5;
41 +
    sload w32 %7 %6 0;
42 +
    add w32 %8 %4 1;
43 +
    jmp @loop1(%8, %7);
44 +
  @merge3
45 +
    ret %9;
46 +
}
47 +
48 +
fn w64 $"test::reslice⟨test::Pair⟩"(w64 %0, w64 %1) {
49 +
  @entry0
50 +
    load w64 %2 %1 0;
51 +
    load w32 %3 %1 8;
52 +
    reserve %4 16 8;
53 +
    store w64 %2 %4 0;
54 +
    store w32 %3 %4 8;
55 +
    store w32 %3 %4 12;
56 +
    blit %0 %4 16;
57 +
    ret %0;
58 +
}
59 +
60 +
fn w64 $"test::reslice⟨i32⟩"(w64 %0, w64 %1) {
61 +
  @entry0
62 +
    load w64 %2 %1 0;
63 +
    load w32 %3 %1 8;
64 +
    reserve %4 16 8;
65 +
    store w64 %2 %4 0;
66 +
    store w32 %3 %4 8;
67 +
    store w32 %3 %4 12;
68 +
    blit %0 %4 16;
69 +
    ret %0;
70 +
}
71 +
72 +
fn w64 $"test::some⟨test::Pair⟩"(w64 %0, w64 %1) {
73 +
  @entry0
74 +
    reserve %2 12 4;
75 +
    store w8 1 %2 0;
76 +
    add w64 %3 %2 4;
77 +
    blit %3 %1 8;
78 +
    blit %0 %2 12;
79 +
    ret %0;
80 +
}
81 +
82 +
fn w64 $"test::some⟨i32⟩"(w64 %0, w32 %1) {
83 +
  @entry0
84 +
    reserve %2 8 4;
85 +
    store w8 1 %2 0;
86 +
    store w32 %1 %2 4;
87 +
    blit %0 %2 8;
88 +
    ret %0;
89 +
}
90 +
91 +
fn w64 $"test::fallible⟨i32⟩"(w64 %0, w32 %1) {
92 +
  @entry0
93 +
    reserve %2 12 8;
94 +
    store w64 0 %2 0;
95 +
    store w32 %1 %2 8;
96 +
    blit %0 %2 12;
97 +
    ret %0;
98 +
}
99 +
100 +
fn w64 $"test::optional⟨test::Pair⟩"(w64 %0, w64 %1) {
101 +
  @entry0
102 +
    blit %0 %1 12;
103 +
    ret %0;
104 +
}
105 +
106 +
fn w64 $"test::optional⟨i32⟩"(w64 %0, w64 %1) {
107 +
  @entry0
108 +
    blit %0 %1 8;
109 +
    ret %0;
110 +
}
111 +
112 +
fn w64 $"test::identity⟨*opaque test::Marker⟩"(w64 %0, w64 %1) {
113 +
  @entry0
114 +
    blit %0 %1 16;
115 +
    ret %0;
116 +
}
117 +
118 +
fn w64 $"test::identity⟨test::Box⟨i32⟩⟩"(w64 %0) {
119 +
  @entry0
120 +
    load w64 %1 %0 0;
121 +
    ret %1;
122 +
}
123 +
124 +
fn w64 $"test::pointer⟨i32⟩"(w64 %0) {
125 +
  @entry0
126 +
    ret %0;
127 +
}
128 +
129 +
fn w64 $"test::identity⟨u64⟩"(w64 %0) {
130 +
  @entry0
131 +
    ret %0;
132 +
}
133 +
134 +
fn w32 $"test::identity⟨i32⟩"(w32 %0) {
135 +
  @entry0
136 +
    ret %0;
137 +
}
test/tests/generic.module.rad added +12 -0
1 +
//! returns: 0
2 +
3 +
mod base;
4 +
use base::*;
5 +
6 +
instantiate base::identity⟨u32⟩;
7 +
instantiate Box⟨u32⟩;
8 +
9 +
@default fn main() -> i32 {
10 +
    let boxed = Box⟨u32{ value: identity⟨u32(7) };
11 +
    return boxed.value as i32 - 7;
12 +
}
test/tests/generic.module/base.rad added +12 -0
1 +
/// Generic value wrapper exported by the base module.
2 +
export record Box⟨T⟩ {
3 +
    /// Wrapped value.
4 +
    value: T,
5 +
}
6 +
7 +
/// Return an exported generic value unchanged.
8 +
export fn identity⟨T⟩(value: T) -> T {
9 +
    return value;
10 +
}
11 +
12 +
instantiate identity⟨u32⟩;
test/tests/generic.nested.rad added +28 -0
1 +
//! returns: 0
2 +
3 +
/// Generic pair.
4 +
record Pair⟨T, U⟩ {
5 +
    /// First value.
6 +
    first: T,
7 +
    /// Second value.
8 +
    second: U,
9 +
}
10 +
11 +
/// Generic value wrapper.
12 +
record Box⟨T⟩ {
13 +
    /// Wrapped value.
14 +
    value: T,
15 +
}
16 +
17 +
instantiate Box⟨Pair⟨i32, bool⟩⟩;
18 +
19 +
/// Exercise nested generic applications.
20 +
@default fn main() -> i32 {
21 +
    let pair: Pair⟨i32, bool= Pair⟨i32, bool{ first: 42, second: true };
22 +
    let mut boxed: Box⟨Pair⟨i32, bool⟩⟩ = Box⟨Pair⟨i32, bool⟩⟩ { value: pair };
23 +
    set boxed.value.first = 43;
24 +
    if boxed.value.second {
25 +
        return boxed.value.first - 43;
26 +
    }
27 +
    return 1;
28 +
}
test/tests/generic.record.rad added +19 -0
1 +
/// Generic pair.
2 +
record Pair⟨T, U⟩ {
3 +
    /// First value.
4 +
    first: T,
5 +
    /// Second value.
6 +
    second: U,
7 +
}
8 +
9 +
instantiate Pair⟨i32, bool⟩;
10 +
11 +
/// Construct a specialized pair.
12 +
fn makePair(first: i32, second: bool) -> Pair⟨i32, bool{
13 +
    return Pair⟨i32, bool{ first, second };
14 +
}
15 +
16 +
/// Return the first value of a specialized pair.
17 +
fn first(pair: Pair⟨i32, bool) -> i32 {
18 +
    return pair.first;
19 +
}
test/tests/generic.record.ril added +14 -0
1 +
fn w64 $makePair(w32 %0, w8 %1) {
2 +
  @entry0
3 +
    reserve %2 8 4;
4 +
    store w32 %0 %2 0;
5 +
    store w8 %1 %2 4;
6 +
    load w64 %3 %2 0;
7 +
    ret %3;
8 +
}
9 +
10 +
fn w32 $first(w64 %0) {
11 +
  @entry0
12 +
    sload w32 %1 %0 0;
13 +
    ret %1;
14 +
}
test/tests/generic.recursive.rad added +17 -0
1 +
//! returns: 0
2 +
3 +
/// Recursive generic list node.
4 +
record List⟨T⟩ {
5 +
    /// Stored value.
6 +
    value: T,
7 +
    /// Next list node.
8 +
    next: ?*List⟨T⟩,
9 +
}
10 +
11 +
instantiate List⟨i32⟩;
12 +
13 +
/// Exercise recursive generic specialization.
14 +
@default fn main() -> i32 {
15 +
    let value: List⟨i32= List⟨i32{ value: 42, next: nil };
16 +
    return value.value - 42;
17 +
}
test/tests/generic.template.rad added +39 -0
1 +
//! returns: 0
2 +
//! Generic function templates are checked but not emitted.
3 +
4 +
/// Error used by a generic template.
5 +
union Fault {
6 +
    /// Generic operation failed.
7 +
    Bad,
8 +
}
9 +
10 +
/// Generic value wrapper.
11 +
record Box⟨T⟩ {
12 +
    /// Wrapped value.
13 +
    value: T,
14 +
}
15 +
16 +
/// Return a value unchanged.
17 +
fn identity⟨T⟩(value: T) -> T {
18 +
    return value;
19 +
}
20 +
21 +
/// Return a pointer through a throwing generic function.
22 +
fn passPointer⟨T⟩(value: *?T) -> *?T throws (Fault) {
23 +
    return value;
24 +
}
25 +
26 +
/// Type-check a generic local declaration.
27 +
fn bodyType⟨T⟩() {
28 +
    let empty: ?T = nil;
29 +
}
30 +
31 +
/// Return a nested generic application.
32 +
fn nestedType⟨T⟩(value: Box⟨T⟩) -> Box⟨T⟩ {
33 +
    return value;
34 +
}
35 +
36 +
/// Exercise generic template checking.
37 +
@default fn main() -> i32 {
38 +
    return 0;
39 +
}
test/tests/generic.trait.cross.module.rad added +13 -0
1 +
//! Inherited trait methods retain their defining module identity.
2 +
//! returns: 0
3 +
4 +
mod base;
5 +
use base::*;
6 +
7 +
trait Child: Base {}
8 +
9 +
instance Child for Item {}
10 +
11 +
@default fn main() -> i32 {
12 +
    return 0;
13 +
}
test/tests/generic.trait.cross.module/base.rad added +12 -0
1 +
/// Concrete item exported by the base module.
2 +
export record Item {}
3 +
4 +
export trait Base {
5 +
    fn (&Base) value() -> u32;
6 +
}
7 +
8 +
instance Base for Item {
9 +
    fn (value: &Item) value() -> u32 {
10 +
        return 7;
11 +
    }
12 +
}
test/tests/generic.trait.nominal.identity.rad added +25 -0
1 +
//! Qualified nominal types keep distinct instance identities.
2 +
//! returns: 0
3 +
4 +
mod left;
5 +
mod right;
6 +
7 +
trait Inspect {
8 +
    fn (&Inspect) inspect() -> u32;
9 +
}
10 +
11 +
instance Inspect for left::Item {
12 +
    fn (value: &left::Item) inspect() -> u32 {
13 +
        return 1;
14 +
    }
15 +
}
16 +
17 +
instance Inspect for right::Item {
18 +
    fn (value: &right::Item) inspect() -> u32 {
19 +
        return 2;
20 +
    }
21 +
}
22 +
23 +
@default fn main() -> i32 {
24 +
    return 0;
25 +
}
test/tests/generic.trait.nominal.identity/left.rad added +2 -0
1 +
/// Item type from the left module.
2 +
export record Item {}
test/tests/generic.trait.nominal.identity/right.rad added +2 -0
1 +
/// Item type from the right module.
2 +
export record Item {}
test/tests/generic.trait.self.rad added +61 -0
1 +
//! returns: 0
2 +
3 +
trait Choose {
4 +
    fn (&Choose) choose(other: Self) -> Self;
5 +
}
6 +
7 +
instance Choose for u32 {
8 +
    fn (value: &u32) choose(other: u32) -> u32 {
9 +
        return other;
10 +
    }
11 +
}
12 +
13 +
/// Generic wrapper used by trait instances.
14 +
record Box⟨T⟩ {
15 +
    /// Wrapped value.
16 +
    value: T,
17 +
}
18 +
19 +
instantiate Box⟨u32⟩;
20 +
instantiate Box⟨u64⟩;
21 +
22 +
trait Inspect {
23 +
    fn (&Inspect) inspect() -> u32;
24 +
}
25 +
26 +
instance Inspect for Box⟨u32{
27 +
    fn (value: &Box⟨u32) inspect() -> u32 {
28 +
        return value.value;
29 +
    }
30 +
}
31 +
32 +
instance Inspect for Box⟨u64{
33 +
    fn (value: &Box⟨u64) inspect() -> u32 {
34 +
        return value.value as u32;
35 +
    }
36 +
}
37 +
38 +
trait Left {
39 +
    fn (&Left) tag() -> u32;
40 +
}
41 +
42 +
trait Right {
43 +
    fn (&Right) tag() -> u32;
44 +
}
45 +
46 +
instance Left for u32 {
47 +
    fn (value: &u32) tag() -> u32 {
48 +
        return *value;
49 +
    }
50 +
}
51 +
52 +
instance Right for u32 {
53 +
    fn (value: &u32) tag() -> u32 {
54 +
        return *value + 1;
55 +
    }
56 +
}
57 +
58 +
/// Exercise generic trait identity and `Self`.
59 +
@default fn main() -> i32 {
60 +
    return 0;
61 +
}
test/tests/generic.union.rad added +20 -0
1 +
//! returns: 0
2 +
3 +
/// Generic optional value.
4 +
union Maybe⟨T⟩ {
5 +
    /// No value.
6 +
    None,
7 +
    /// Stored value.
8 +
    Some(T),
9 +
}
10 +
11 +
instantiate Maybe⟨i32⟩;
12 +
13 +
/// Exercise generic union specialization.
14 +
@default fn main() -> i32 {
15 +
    let value: Maybe⟨i32= Maybe⟨i32::Some(42);
16 +
    match value {
17 +
        case Maybe⟨i32::Some(inner) => { return inner - 42; }
18 +
        case Maybe⟨i32::None => { return 1; }
19 +
    }
20 +
}
test/tests/trait.dispatch.ril +5 -5
1 -
data $"vtable::Acc::Ops" align 8 {
2 -
    fn $"Acc::get";
3 -
    fn $"Acc::put";
1 +
data $"vtable::test::Acc test::Ops" align 8 {
2 +
    fn $"test::Acc test::Ops::get";
3 +
    fn $"test::Acc test::Ops::put";
4 4
}
5 5
6 -
fn w32 $"Acc::get"(w64 %0) {
6 +
fn w32 $"test::Acc test::Ops::get"(w64 %0) {
7 7
  @entry0
8 8
    sload w32 %1 %0 0;
9 9
    ret %1;
10 10
}
11 11
12 -
fn w64 $"Acc::put"(w64 %0, w32 %1) {
12 +
fn w64 $"test::Acc test::Ops::put"(w64 %0, w32 %1) {
13 13
  @entry0
14 14
    store w32 %1 %0 0;
15 15
    ret;
16 16
}
17 17
test/tests/trait.object.ril +4 -4
1 -
data $"vtable::Counter::Adder" align 8 {
2 -
    fn $"Counter::add";
1 +
data $"vtable::test::Counter test::Adder" align 8 {
2 +
    fn $"test::Counter test::Adder::add";
3 3
}
4 4
5 -
fn w32 $"Counter::add"(w64 %0, w32 %1) {
5 +
fn w32 $"test::Counter test::Adder::add"(w64 %0, w32 %1) {
6 6
  @entry0
7 7
    sload w32 %2 %0 0;
8 8
    add w32 %3 %2 %1;
9 9
    store w32 %3 %0 0;
10 10
    sload w32 %4 %0 0;
15 15
  @entry0
16 16
    reserve %0 4 4;
17 17
    store w32 0 %0 0;
18 18
    reserve %1 16 8;
19 19
    store w64 %0 %1 0;
20 -
    store w64 $"vtable::Counter::Adder" %1 8;
20 +
    store w64 $"vtable::test::Counter test::Adder" %1 8;
21 21
    load w64 %2 %1 0;
22 22
    load w64 %3 %1 8;
23 23
    load w64 %4 %3 0;
24 24
    call w32 %5 %4(%2, 1);
25 25
    ret %5;
test/tests/trait.supertrait.ril +12 -12
1 -
data $"vtable::Socket::Reader" align 8 {
2 -
    fn $"Socket::read";
1 +
data $"vtable::test::Socket test::Reader" align 8 {
2 +
    fn $"test::Socket test::Reader::read";
3 3
}
4 4
5 -
data $"vtable::Socket::Writer" align 8 {
6 -
    fn $"Socket::write";
5 +
data $"vtable::test::Socket test::Writer" align 8 {
6 +
    fn $"test::Socket test::Writer::write";
7 7
}
8 8
9 -
data $"vtable::Socket::ReadWriter" align 8 {
10 -
    fn $"Socket::read";
11 -
    fn $"Socket::write";
12 -
    fn $"Socket::flush";
9 +
data $"vtable::test::Socket test::ReadWriter" align 8 {
10 +
    fn $"test::Socket test::Reader::read";
11 +
    fn $"test::Socket test::Writer::write";
12 +
    fn $"test::Socket test::ReadWriter::flush";
13 13
}
14 14
15 15
data $main$literal$0 align 1 {
16 16
    str "abc";
17 17
}
18 18
19 -
fn w32 $"Socket::read"(w64 %0, w64 %1) {
19 +
fn w32 $"test::Socket test::Reader::read"(w64 %0, w64 %1) {
20 20
  @entry0
21 21
    jmp @while1(0, %1, %0);
22 22
  @while1(w32 %3, w64 %4, w64 %6)
23 23
    load w32 %5 %4 8;
24 24
    br.ult w32 %3 %5 @and#then4 @and#else5;
56 56
  @guard#trap10
57 57
    ebreak;
58 58
    unreachable;
59 59
}
60 60
61 -
fn w32 $"Socket::write"(w64 %0, w64 %1) {
61 +
fn w32 $"test::Socket test::Writer::write"(w64 %0, w64 %1) {
62 62
  @entry0
63 63
    jmp @while1(0, %1, %0);
64 64
  @while1(w32 %2, w64 %3, w64 %5)
65 65
    load w32 %4 %3 8;
66 66
    br.ult w32 %2 %4 @body2 @merge3;
97 97
  @guard#trap9
98 98
    ebreak;
99 99
    unreachable;
100 100
}
101 101
102 -
fn w32 $"Socket::flush"(w64 %0) {
102 +
fn w32 $"test::Socket test::ReadWriter::flush"(w64 %0) {
103 103
  @entry0
104 104
    sload w32 %1 %0 72;
105 105
    store w32 0 %0 72;
106 106
    ret %1;
107 107
}
121 121
    store w8 108 %3 0;
122 122
    add w64 %4 %0 4;
123 123
    store w8 111 %4 0;
124 124
    reserve %5 16 8;
125 125
    store w64 %0 %5 0;
126 -
    store w64 $"vtable::Socket::ReadWriter" %5 8;
126 +
    store w64 $"vtable::test::Socket test::ReadWriter" %5 8;
127 127
    load w64 %6 %5 0;
128 128
    load w64 %7 %5 8;
129 129
    load w64 %8 %7 8;
130 130
    copy %9 $main$literal$0;
131 131
    reserve %10 16 8;