lang: Implement explicit generics

2034127ddef8f28a7cfb3265a29fc5b58bccd547dd77ceaf815c9a43f98a8301
Alexis Sellier committed ago 1 parent df4b837f
compiler/radiance.rad +5 -5
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 -
/// Main arena size (64 MB) - lives throughout compilation.
42 +
/// Main arena size (80 MB) - lives throughout compilation.
43 43
/// Used for: resolver data, types, symbols, global IL data, and codegen output.
44 -
constant MAIN_ARENA_SIZE: u32 = 67108864;
44 +
constant MAIN_ARENA_SIZE: u32 = 83886080;
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.
49 49
static FN_ARENA: [u8; FN_ARENA_SIZE] = undefined;
755 755
    let attrNode = ast::synthNode(arena, ast::NodeValue::Attribute(ast::Attribute::Default));
756 756
    let attrList = ast::nodeSlice(arena, 1).append(attrNode, a);
757 757
    let fnAttrs = ast::Attributes { list: attrList };
758 758
759 759
    return ast::synthNode(arena, ast::NodeValue::FnDecl(ast::FnDecl {
760 -
        name: fnName, sig: fnSig, body: fnBody, attrs: fnAttrs,
760 +
        name: fnName, params: ast::nodeSlice(arena, 0), sig: fnSig, body: fnBody, attrs: fnAttrs,
761 761
    }));
762 762
}
763 763
764 764
/// Append a declaration to a block node's statement list.
765 765
fn injectIntoBlock(
lib/std/lang/ast.rad +33 -1
468 468
    fields: *mut [*Node],
469 469
    /// When true, remaining fields are discarded (`{ x, .. }`).
470 470
    ignoreRest: bool,
471 471
}
472 472
473 +
/// Generic declaration parameter.
474 +
export union GenericParam {
475 +
    /// Rigid type parameter with optional trait bounds.
476 +
    Type {
477 +
        name: *Node,
478 +
        bounds: *mut [*Node],
479 +
    },
480 +
    /// Compile-time constant parameter.
481 +
    Const {
482 +
        name: *Node,
483 +
        type: *Node,
484 +
    },
485 +
}
486 +
487 +
/// Application of ordered generic arguments to a declaration or path.
488 +
export record GenericApply {
489 +
    target: *Node,
490 +
    args: *mut [*Node],
491 +
}
492 +
473 493
/// Record declaration.
474 494
export record RecordDecl {
475 495
    /// Identifier naming the record.
476 496
    name: *Node,
497 +
    /// Generic parameters in declaration order.
498 +
    params: *mut [*Node],
477 499
    /// Field declaration nodes.
478 500
    fields: *mut [*Node],
479 501
    /// Optional attribute list applied to the record.
480 502
    attrs: ?Attributes,
481 503
    /// Trait derivations attached to the record.
486 508
487 509
/// Union declarations.
488 510
export record UnionDecl {
489 511
    /// Identifier naming the union.
490 512
    name: *Node,
513 +
    /// Generic parameters in declaration order.
514 +
    params: *mut [*Node],
491 515
    /// Variant nodes making up the union.
492 516
    variants: *mut [*Node],
493 517
    /// Optional attribute list applied to the union.
494 518
    attrs: ?Attributes,
495 519
    /// Trait derivations attached to the union.
510 534
511 535
/// Function declaration.
512 536
export record FnDecl {
513 537
    /// Identifier naming the function.
514 538
    name: *Node,
539 +
    /// Generic parameters in declaration order.
540 +
    params: *mut [*Node],
515 541
    /// Function type signature.
516 542
    sig: FnSig,
517 543
    /// Optional function body (`nil` for extern functions).
518 544
    body: ?*Node,
519 545
    /// Optional attribute list applied to the function.
617 643
        /// Array or slice.
618 644
        container: *Node,
619 645
        /// Index expression.
620 646
        index: *Node
621 647
    },
648 +
    /// Generic declaration or function application.
649 +
    GenericApply(GenericApply),
622 650
    /// Binary operator expression.
623 651
    BinOp(BinOp),
624 652
    /// Unary operator expression.
625 653
    UnOp(UnOp),
626 654
    /// Builtin function call (e.g. `@sizeOf(T)`).
723 751
    UnionDeclVariant(UnionDeclVariant),
724 752
    /// Attribute node.
725 753
    Attribute(Attribute),
726 754
    /// Record type declaration.
727 755
    RecordDecl(RecordDecl),
756 +
    /// Generic declaration parameter.
757 +
    GenericParam(GenericParam),
758 +
    /// Explicit generic specialization roots declared as one group.
759 +
    Instantiate(*mut [*Node]),
728 760
    /// Record field declaration.
729 761
    RecordField {
730 762
        /// Identifier bound by the declaration.
731 763
        field: ?*Node,
732 764
        /// Declared type annotation.
853 885
    let params: *mut [*Node] = &mut [];
854 886
    let throwList: *mut [*Node] = &mut [];
855 887
    let fnSig = FnSig { params, returnType: nil, throwList };
856 888
    let fnBody = synthNode(arena, NodeValue::Block(Block { statements: bodyStmts }));
857 889
    let fnDecl = synthNode(arena, NodeValue::FnDecl(FnDecl {
858 -
        name: fnName, sig: fnSig, body: fnBody, attrs: nil,
890 +
        name: fnName, params: &mut [], sig: fnSig, body: fnBody, attrs: nil,
859 891
    }));
860 892
    let mut rootStmts: *mut [*Node] = &mut [];
861 893
    rootStmts.append(fnDecl, a);
862 894
    let modBody = synthNode(arena, NodeValue::Block(Block { statements: rootStmts }));
863 895
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 +598 -144
290 290
    fnArena: *mut alloc::Arena,
291 291
    /// Allocator backed by the arena.
292 292
    allocator: alloc::Allocator,
293 293
    /// Resolver for type information. Used to query types, symbols, and
294 294
    /// compile-time constant values during lowering.
295 -
    resolver: *resolver::Resolver,
295 +
    resolver: *mut resolver::Resolver,
296 296
    /// Module graph for cross-module symbol resolution.
297 297
    moduleGraph: ?*module::ModuleGraph,
298 298
    /// Package name for qualified symbol names.
299 299
    pkgName: *[u8],
300 300
    /// Current module being lowered.
301 301
    currentMod: ?u16,
302 +
    /// Rigid-to-concrete mapping for the function currently being lowered.
303 +
    specialization: ?*resolver::Substitution,
304 +
    /// Concrete generic function whose body is currently being lowered.
305 +
    genericSpecialization: ?*resolver::GenericFnSpecialization,
302 306
    /// Global data items (string literals, constants, static arrays).
303 307
    /// These become the data sections in the final binary.
304 308
    data: *mut [il::Data],
305 309
    /// Destination for lowered functions.
306 310
    output: FnOutput,
741 745
/// 3. Returns the complete IL program with functions and data section.
742 746
///
743 747
/// The resolver must have already processed the AST -- we rely on its type
744 748
/// annotations, symbol table, and constant evaluations.
745 749
export fn lower(
746 -
    res: *resolver::Resolver,
750 +
    res: *mut resolver::Resolver,
747 751
    root: *ast::Node,
748 752
    pkgName: *[u8],
749 753
    arena: *mut alloc::Arena
750 754
) -> il::Program throws (LowerError) {
751 755
    let mut low = Lowerer {
754 758
        allocator: alloc::arenaAllocator(arena),
755 759
        resolver: res,
756 760
        moduleGraph: nil,
757 761
        pkgName,
758 762
        currentMod: nil,
763 +
        specialization: nil,
764 +
        genericSpecialization: nil,
759 765
        data: &mut [],
760 766
        output: FnOutput::Accumulate(&mut []),
761 767
        fnSyms: &mut [],
762 768
        errTags: &mut [],
763 769
        errTagCounter: 1,
772 778
// Multi-Module Lowering API   //
773 779
/////////////////////////////////
774 780
775 781
/// Create a lowerer for multi-module compilation.
776 782
export fn lowerer(
777 -
    res: *resolver::Resolver,
783 +
    res: *mut resolver::Resolver,
778 784
    graph: *module::ModuleGraph,
779 785
    pkgName: *[u8],
780 786
    arena: *mut alloc::Arena,
781 787
    fnArena: *mut alloc::Arena,
782 788
    options: LowerOptions
787 793
        allocator: alloc::arenaAllocator(arena),
788 794
        resolver: res,
789 795
        moduleGraph: graph,
790 796
        pkgName,
791 797
        currentMod: nil,
798 +
        specialization: nil,
799 +
        genericSpecialization: nil,
792 800
        data: &mut [],
793 801
        output: FnOutput::Accumulate(&mut []),
794 802
        fnSyms: &mut [],
795 803
        errTags: &mut [],
796 804
        errTagCounter: 1,
818 826
    let stmtsList = block.statements;
819 827
820 828
    for node in stmtsList {
821 829
        match node.value {
822 830
            case ast::NodeValue::FnDecl(decl) => {
831 +
                // Generic declarations are templates, not emitted functions.
832 +
                if decl.params.len > 0 {
833 +
                    continue;
834 +
                }
823 835
                if let f = try lowerFnDecl(low, node, decl) {
824 836
                    let role = lowerFnRole(isRoot, decl.attrs);
825 837
                    emitFunction(low, f, role);
826 838
                }
827 839
            }
840 852
                }
841 853
            }
842 854
            else => {},
843 855
        }
844 856
    }
857 +
    try lowerGenericFnSpecializations(low);
858 +
}
859 +
860 +
/// Lower explicit generic function roots owned by the current module.
861 +
fn lowerGenericFnSpecializations(low: *mut Lowerer) throws (LowerError) {
862 +
    let mut cursor = resolver::genericFnSpecializations(low.resolver);
863 +
    while let node = cursor {
864 +
        let specialization = &node.specialization;
865 +
        let templateSym = specialization.template;
866 +
        if low.moduleGraph <> nil and templateSym.moduleId <> low.currentMod {
867 +
            set cursor = node.next;
868 +
            continue;
869 +
        }
870 +
        let case ast::NodeValue::FnDecl(decl) = templateSym.node.value else {
871 +
            throw LowerError::ExpectedFunction;
872 +
        };
873 +
        if not shouldLowerFn(&decl, low.options.buildTest) {
874 +
            set cursor = node.next;
875 +
            continue;
876 +
        }
877 +
        let template = resolver::genericTemplateFor(low.resolver, templateSym)
878 +
            else throw LowerError::MissingMetadata;
879 +
        let sub = resolver::Substitution {
880 +
            params: template.params,
881 +
            args: specialization.args,
882 +
        };
883 +
        let symbolicFnType = template.signature
884 +
            else throw LowerError::MissingMetadata;
885 +
        let mut concreteFnType = *specialization.fnType;
886 +
        set concreteFnType.localCount = symbolicFnType.localCount;
887 +
        set low.genericSpecialization = specialization;
888 +
        set low.specialization = &sub;
889 +
        let name = specializationName(low, specialization);
890 +
        let func = try lowerConcreteFn(
891 +
            low,
892 +
            templateSym.node,
893 +
            decl,
894 +
            &concreteFnType,
895 +
            name,
896 +
            false,
897 +
        ) catch e {
898 +
            set low.genericSpecialization = nil;
899 +
            set low.specialization = nil;
900 +
            throw e;
901 +
        };
902 +
        set low.genericSpecialization = nil;
903 +
        set low.specialization = nil;
904 +
        emitFunction(low, func, FnRole::Normal);
905 +
        set cursor = node.next;
906 +
    }
845 907
}
846 908
847 909
/// Finalize lowering and return the unified IL program.
848 910
export fn finalize(low: *Lowerer) -> il::Program {
849 911
    let mut fns: *mut [*il::Fn] = undefined;
892 954
        return name;
893 955
    }
894 956
    return il::formatQualifiedName(self.arena, path, name);
895 957
}
896 958
959 +
/// Incrementally build deterministic internal symbol names.
960 +
record NameBuilder {
961 +
    /// Accumulated name bytes.
962 +
    bytes: *mut [u8],
963 +
    /// Allocator used to grow the name.
964 +
    allocator: alloc::Allocator,
965 +
}
966 +
967 +
/// Append bytes to a symbol name.
968 +
fn namePush(builder: *mut NameBuilder, text: *[u8]) {
969 +
    for byte in text {
970 +
        builder.bytes.append(byte, builder.allocator);
971 +
    }
972 +
}
973 +
974 +
/// Append a decimal `u32` to a symbol name.
975 +
fn namePushU32(builder: *mut NameBuilder, value: u32) {
976 +
    let mut digits: [u8; 10] = undefined;
977 +
    namePush(builder, fmt::formatU32(value, &mut digits[..]));
978 +
}
979 +
980 +
/// Append a decimal `u64` to a symbol name.
981 +
fn namePushU64(builder: *mut NameBuilder, value: u64) {
982 +
    let mut digits: [u8; 20] = undefined;
983 +
    namePush(builder, fmt::formatU64(value, &mut digits[..]));
984 +
}
985 +
986 +
/// Append the stable, source-qualified name of a module-level declaration.
987 +
fn namePushQualified(
988 +
    self: *mut Lowerer,
989 +
    builder: *mut NameBuilder,
990 +
    modId: ?u16,
991 +
    name: *[u8],
992 +
) {
993 +
    let path = getModulePath(self, modId);
994 +
    if path.len == 0 or path[0] <> self.pkgName {
995 +
        namePush(builder, self.pkgName);
996 +
        namePush(builder, "::");
997 +
    }
998 +
    for segment in path {
999 +
        namePush(builder, segment);
1000 +
        namePush(builder, "::");
1001 +
    }
1002 +
    namePush(builder, name);
1003 +
}
1004 +
1005 +
/// Append a trait's qualified name.
1006 +
fn namePushTrait(
1007 +
    self: *mut Lowerer,
1008 +
    builder: *mut NameBuilder,
1009 +
    traitInfo: *resolver::TraitType,
1010 +
) {
1011 +
    namePushQualified(self, builder, traitInfo.moduleId, traitInfo.name);
1012 +
}
1013 +
1014 +
/// Append a canonical resolved type using Radiance source syntax.
1015 +
fn namePushType(
1016 +
    self: *mut Lowerer,
1017 +
    builder: *mut NameBuilder,
1018 +
    ty: resolver::Type,
1019 +
) {
1020 +
    match ty {
1021 +
        case resolver::Type::Void => namePush(builder, "void"),
1022 +
        case resolver::Type::Opaque => namePush(builder, "opaque"),
1023 +
        case resolver::Type::Never => namePush(builder, "!"),
1024 +
        case resolver::Type::Bool => namePush(builder, "bool"),
1025 +
        case resolver::Type::U8 => namePush(builder, "u8"),
1026 +
        case resolver::Type::U16 => namePush(builder, "u16"),
1027 +
        case resolver::Type::U32 => namePush(builder, "u32"),
1028 +
        case resolver::Type::U64 => namePush(builder, "u64"),
1029 +
        case resolver::Type::I8 => namePush(builder, "i8"),
1030 +
        case resolver::Type::I16 => namePush(builder, "i16"),
1031 +
        case resolver::Type::I32 => namePush(builder, "i32"),
1032 +
        case resolver::Type::I64 => namePush(builder, "i64"),
1033 +
        case resolver::Type::Pointer(pointer) => {
1034 +
            match pointer.class {
1035 +
                case types::PointerClass::Owned => namePush(builder, "*"),
1036 +
                case types::PointerClass::Ref => namePush(builder, "&"),
1037 +
                case types::PointerClass::Unsafe => namePush(builder, "*unsafe "),
1038 +
            }
1039 +
            if pointer.mutable { namePush(builder, "mut "); }
1040 +
            namePushType(self, builder, *pointer.target);
1041 +
        }
1042 +
        case resolver::Type::Slice(slice) => {
1043 +
            match slice.class {
1044 +
                case types::PointerClass::Owned => namePush(builder, "*"),
1045 +
                case types::PointerClass::Ref => namePush(builder, "&"),
1046 +
                case types::PointerClass::Unsafe => namePush(builder, "*unsafe "),
1047 +
            }
1048 +
            if slice.mutable { namePush(builder, "mut "); }
1049 +
            namePush(builder, "[");
1050 +
            namePushType(self, builder, *slice.item);
1051 +
            namePush(builder, "]");
1052 +
        }
1053 +
        case resolver::Type::Array(array) => {
1054 +
            namePush(builder, "[");
1055 +
            namePushType(self, builder, *array.item);
1056 +
            namePush(builder, "; ");
1057 +
            namePushU32(builder, array.length);
1058 +
            namePush(builder, "]");
1059 +
        }
1060 +
        case resolver::Type::ConstArgument { value, .. } => {
1061 +
            if value.negative { namePush(builder, "-"); }
1062 +
            namePushU64(builder, value.magnitude);
1063 +
        }
1064 +
        case resolver::Type::Optional(inner) => {
1065 +
            namePush(builder, "?");
1066 +
            namePushType(self, builder, *inner);
1067 +
        }
1068 +
        case resolver::Type::Fn(info) => {
1069 +
            if info.isUnsafe { namePush(builder, "unsafe "); }
1070 +
            namePush(builder, "fn(");
1071 +
            for param, i in info.paramTypes {
1072 +
                if i > 0 { namePush(builder, ", "); }
1073 +
                namePushType(self, builder, *param);
1074 +
            }
1075 +
            namePush(builder, ") -> ");
1076 +
            namePushType(self, builder, *info.returnType);
1077 +
            if info.throwList.len > 0 {
1078 +
                namePush(builder, " throws ");
1079 +
                for thrown, i in info.throwList {
1080 +
                    if i > 0 { namePush(builder, ", "); }
1081 +
                    namePushType(self, builder, *thrown);
1082 +
                }
1083 +
            }
1084 +
        }
1085 +
        case resolver::Type::Nominal(nominal) => {
1086 +
            if let data = resolver::genericDataSpecializationForNominal(
1087 +
                self.resolver, nominal
1088 +
            ) {
1089 +
                namePushQualified(
1090 +
                    self, builder, data.template.moduleId, data.template.name
1091 +
                );
1092 +
                namePush(builder, "⟨");
1093 +
                for arg, i in data.args {
1094 +
                    if i > 0 { namePush(builder, ", "); }
1095 +
                    namePushType(self, builder, *arg);
1096 +
                }
1097 +
                namePush(builder, "⟩");
1098 +
                return;
1099 +
            }
1100 +
            if let sym = resolver::symbolForNominal(self.resolver, nominal) {
1101 +
                namePushQualified(self, builder, sym.moduleId, sym.name);
1102 +
                return;
1103 +
            }
1104 +
            match *nominal {
1105 +
                case resolver::NominalType::Record(recordType) => {
1106 +
                    namePush(builder, "{ ");
1107 +
                    for field, i in recordType.fields {
1108 +
                        if i > 0 { namePush(builder, ", "); }
1109 +
                        if let name = field.name {
1110 +
                            namePush(builder, name);
1111 +
                            namePush(builder, ": ");
1112 +
                        }
1113 +
                        namePushType(self, builder, field.fieldType);
1114 +
                    }
1115 +
                    namePush(builder, " }");
1116 +
                }
1117 +
                case resolver::NominalType::Union(_) =>
1118 +
                    panic "namePushType: anonymous union has no source identity",
1119 +
                case resolver::NominalType::Placeholder(_) =>
1120 +
                    panic "namePushType: unresolved nominal type",
1121 +
            }
1122 +
        }
1123 +
        case resolver::Type::TraitObject(object) => {
1124 +
            match object.class {
1125 +
                case types::PointerClass::Owned => namePush(builder, "*"),
1126 +
                case types::PointerClass::Ref => namePush(builder, "&"),
1127 +
                case types::PointerClass::Unsafe => namePush(builder, "*unsafe "),
1128 +
            }
1129 +
            if object.mutable { namePush(builder, "mut "); }
1130 +
            namePush(builder, "opaque ");
1131 +
            namePushTrait(self, builder, object.traitInfo);
1132 +
        }
1133 +
        else => panic "namePushType: non-concrete type",
1134 +
    }
1135 +
}
1136 +
1137 +
/// Build a readable specialization name from source identity and canonical arguments.
1138 +
fn specializationName(
1139 +
    self: *mut Lowerer,
1140 +
    specialization: *resolver::GenericFnSpecialization,
1141 +
) -> *[u8] {
1142 +
    let template = specialization.template;
1143 +
    let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator };
1144 +
    namePushQualified(self, &mut builder, template.moduleId, template.name);
1145 +
    namePush(&mut builder, "⟨");
1146 +
    for arg, i in specialization.args {
1147 +
        if i > 0 { namePush(&mut builder, ", "); }
1148 +
        namePushType(self, &mut builder, *arg);
1149 +
    }
1150 +
    namePush(&mut builder, "⟩");
1151 +
    return &builder.bytes[..];
1152 +
}
1153 +
897 1154
/// Register a function symbol with its qualified name.
898 1155
/// Called when lowering function declarations, so cross-package calls can find
899 1156
/// the function by name.
900 1157
fn registerFnSym(self: *mut Lowerer, sym: *resolver::Symbol, qualName: *[u8]) {
901 1158
    self.fnSyms.append(FnSymEntry { sym, qualName }, self.allocator);
988 1245
989 1246
    // Register function symbol for cross-package call resolution.
990 1247
    if let sym = data.sym {
991 1248
        registerFnSym(self, sym, qualName);
992 1249
    }
993 -
    let mut fnLow = fnLowerer(self, node, fnType, qualName);
1250 +
    return try lowerConcreteFn(self, node, decl, fnType, qualName, isExtern);
1251 +
}
994 1252
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.
1253 +
/// Lower one already-concrete function signature through the shared body path.
1254 +
fn lowerConcreteFn(
1255 +
    self: *mut Lowerer,
1256 +
    node: *ast::Node,
1257 +
    decl: ast::FnDecl,
1258 +
    fnType: *resolver::FnType,
1259 +
    qualName: *[u8],
1260 +
    isExtern: bool,
1261 +
) -> *il::Fn throws (LowerError) {
1262 +
    let mut fnLow = fnLowerer(self, node, fnType, qualName);
998 1263
    if requiresReturnParam(fnType) and not isExtern {
999 1264
        set fnLow.returnReg = nextReg(&mut fnLow);
1000 1265
    }
1001 1266
    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 -
1267 +
    let func = try! alloc::alloc(
1268 +
        self.fnArena, @sizeOf(il::Fn), @alignOf(il::Fn)
1269 +
    ) as *mut il::Fn;
1004 1270
    set *func = il::Fn {
1005 1271
        name: qualName,
1006 1272
        params: lowParams,
1007 1273
        returnType: undefined,
1008 1274
        isExtern,
1009 1275
        isLeaf: true,
1010 1276
        blocks: &[],
1011 1277
    };
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 1278
    if fnType.throwList.len > 0 {
1017 1279
        set func.returnType = il::Type::W64;
1018 1280
    } else {
1019 1281
        set func.returnType = ilType(self, *fnType.returnType);
1020 1282
    }
1021 1283
    let body = decl.body else {
1022 -
        // Extern functions have no body.
1023 1284
        assert isExtern;
1024 1285
        return func;
1025 1286
    };
1026 1287
    set func.blocks = try lowerFnBody(&mut fnLow, body);
1027 1288
    set func.isLeaf = fnLow.isLeaf;
1028 -
1029 1289
    return func;
1030 1290
}
1031 1291
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]);
1292 +
/// Build a readable method name from its concrete type, trait, and source name.
1293 +
fn instanceMethodName(
1294 +
    self: *mut Lowerer,
1295 +
    concreteType: resolver::Type,
1296 +
    traitInfo: ?*resolver::TraitType,
1297 +
    methodName: *[u8],
1298 +
) -> *[u8] {
1299 +
    let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator };
1300 +
    namePushType(self, &mut builder, concreteType);
1301 +
    if let traitValue = traitInfo {
1302 +
        namePush(&mut builder, " ");
1303 +
        namePushTrait(self, &mut builder, traitValue);
1304 +
    }
1305 +
    namePush(&mut builder, "::");
1306 +
    namePush(&mut builder, methodName);
1307 +
    return &builder.bytes[..];
1308 +
}
1309 +
1310 +
/// Build a readable v-table name from its concrete type and trait.
1311 +
fn vtableName(
1312 +
    self: *mut Lowerer,
1313 +
    concreteType: resolver::Type,
1314 +
    traitInfo: *resolver::TraitType,
1315 +
) -> *[u8] {
1316 +
    let mut builder = NameBuilder { bytes: &mut [], allocator: self.allocator };
1317 +
    namePush(&mut builder, "vtable::");
1318 +
    namePushType(self, &mut builder, concreteType);
1319 +
    namePush(&mut builder, " ");
1320 +
    namePushTrait(self, &mut builder, traitInfo);
1321 +
    return &builder.bytes[..];
1062 1322
}
1063 1323
1064 1324
/// Lower an instance declaration (`instance Trait for Type { ... }`).
1065 1325
///
1066 1326
/// 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
1327 +
/// with a qualified name containing both concrete and declaring-trait
1328 +
/// identities. A read-only v-table data record points to these functions,
1329 +
/// ordered by the trait's method indices. The v-table is later referenced when
1070 1330
/// constructing trait objects for dynamic dispatch.
1071 1331
fn lowerInstanceDecl(
1072 1332
    self: *mut Lowerer,
1073 1333
    node: *ast::Node,
1074 1334
    traitNameNode: *ast::Node,
1075 1335
    targetTypeNode: *ast::Node,
1076 1336
    methods: *mut [*ast::Node]
1077 1337
) throws (LowerError) {
1078 -
    // Look up the trait and type from the resolver.
1338 +
    // Look up the trait and concrete instance from resolver metadata.
1079 1339
    let traitSym = resolver::nodeData(self.resolver, traitNameNode).sym
1080 1340
        else throw LowerError::MissingSymbol(traitNameNode);
1081 1341
    let case resolver::SymbolData::Trait(traitInfo) = traitSym.data
1082 1342
        else throw LowerError::MissingMetadata;
1083 -
    let typeSym = resolver::nodeData(self.resolver, targetTypeNode).sym
1084 -
        else throw LowerError::MissingSymbol(targetTypeNode);
1085 -
1086 -
    let tName = traitSym.name;
1087 -
    let typeName = typeSym.name;
1343 +
    let concreteType = resolver::typeFor(self.resolver, targetTypeNode)
1344 +
        else throw LowerError::MissingType(targetTypeNode);
1345 +
    let instEntry = resolver::findInstance(self.resolver, traitInfo, concreteType)
1346 +
        else throw LowerError::MissingMetadata;
1088 1347
1089 1348
    // Lower each instance method as a regular function.
1090 1349
    // Collect qualified names for the v-table. Empty entries are filled
1091 1350
    // later from inherited supertrait methods.
1092 1351
    let mut methodNames: [*[u8]; ast::MAX_TRAIT_METHODS] = undefined;
1098 1357
        } = methodNode.value else continue;
1099 1358
1100 1359
        let case ast::NodeValue::Ident(mName) = name.value else {
1101 1360
            throw LowerError::ExpectedIdentifier;
1102 1361
        };
1103 -
        let qualName = instanceMethodName(self, nil, typeName, mName);
1362 +
        let method = resolver::findTraitMethod(traitInfo, mName)
1363 +
            else panic "lowerInstanceDecl: method not found in trait";
1364 +
        let qualName = instanceMethodName(
1365 +
            self, instEntry.concreteType, method.owner, mName
1366 +
        );
1104 1367
        let func = try lowerMethod(self, methodNode, qualName, receiverName, sig, body)
1105 1368
            else continue;
1106 1369
        emitFunction(self, func, FnRole::Normal);
1107 1370
1108 -
        let method = resolver::findTraitMethod(traitInfo, mName)
1109 -
            else panic "lowerInstanceDecl: method not found in trait";
1110 -
1111 1371
        set methodNames[method.index] = qualName;
1112 1372
        set methodNameSet[method.index] = true;
1113 1373
    }
1114 1374
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.
1375 +
    // Fill inherited method slots from their declaring supertraits. Their
1376 +
    // declaring-trait identity selects the already lowered implementation.
1118 1377
    for method, i in traitInfo.methods {
1119 1378
        if not methodNameSet[i] {
1120 -
            set methodNames[i] = instanceMethodName(self, nil, typeName, method.name);
1379 +
            let inheritedInst = resolver::findInstance(
1380 +
                self.resolver, method.owner, instEntry.concreteType
1381 +
            ) else throw LowerError::MissingMetadata;
1382 +
            set methodNames[i] = instanceMethodName(
1383 +
                self,
1384 +
                inheritedInst.concreteType,
1385 +
                method.owner,
1386 +
                method.name,
1387 +
            );
1121 1388
        }
1122 1389
    }
1123 1390
1124 1391
    // Create v-table in data section, used for dynamic dispatch.
1125 -
    let vName = vtableName(self, nil, typeName, tName);
1392 +
    let vName = vtableName(self, instEntry.concreteType, traitInfo);
1126 1393
    let values = try! alloc::allocSlice(
1127 1394
        self.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue), traitInfo.methods.len as u32
1128 1395
    ) as *mut [il::DataValue];
1129 1396
1130 1397
    for i in 0..traitInfo.methods.len {
1198 1465
        else throw LowerError::MissingSymbol(node);
1199 1466
    let case ast::NodeValue::Ident(mName) = name.value
1200 1467
        else throw LowerError::ExpectedIdentifier;
1201 1468
    let me = resolver::findMethodBySymbol(self.resolver, sym)
1202 1469
        else throw LowerError::MissingMetadata;
1203 -
    let qualName = instanceMethodName(self, nil, me.concreteTypeName, mName);
1470 +
    let qualName = instanceMethodName(
1471 +
        self, me.concreteType, nil, mName
1472 +
    );
1204 1473
1205 1474
    return try lowerMethod(self, node, qualName, receiverName, sig, body);
1206 1475
}
1207 1476
1208 1477
/// Check if a function should be lowered.
1307 1576
        }
1308 1577
        throw LowerError::MissingConst(node);
1309 1578
    };
1310 1579
1311 1580
    if let case resolver::ConstValue::String(s) = val {
1312 -
        if let case resolver::Type::Slice { .. } = ty {
1581 +
        if let case resolver::Type::Slice(_) = ty {
1313 1582
            let strSym = try getOrCreateStringData(self, s, dataPrefix);
1314 1583
            dataSliceHeader(b, strSym, s.len);
1315 1584
            return;
1316 1585
        }
1317 1586
    }
1379 1648
    addr: ast::AddressOf,
1380 1649
    ty: resolver::Type,
1381 1650
    dataPrefix: *[u8],
1382 1651
    b: *mut DataValueBuilder
1383 1652
) throws (LowerError) {
1384 -
    let case resolver::Type::Slice { mutable, .. } = ty
1653 +
    let case resolver::Type::Slice(slice) = ty
1385 1654
        else throw LowerError::ExpectedSliceOrArray;
1386 1655
    let targetTy = resolver::typeFor(self.resolver, addr.target)
1387 1656
        else throw LowerError::MissingType(addr.target);
1388 1657
    let case resolver::Type::Array(arrInfo) = targetTy
1389 1658
        else throw LowerError::ExpectedArray;
1391 1660
    let mut nested = dataBuilder(self.allocator);
1392 1661
    let layout = resolver::getTypeLayout(targetTy);
1393 1662
    try lowerConstDataInto(self, addr.target, targetTy, layout.size, dataPrefix, &mut nested);
1394 1663
1395 1664
    let backing = dataBuilderFinish(&nested);
1396 -
    let readOnly = not mutable;
1665 +
    let readOnly = not slice.mutable;
1397 1666
    let mut dataName: *[u8] = undefined;
1398 1667
    if readOnly {
1399 1668
        if let found = findConstData(self, backing.values, layout.alignment) {
1400 1669
            set dataName = found;
1401 1670
        } else {
1929 2198
    let reg = il::Reg { n: self.regCounter };
1930 2199
    set self.regCounter += 1;
1931 2200
    return reg;
1932 2201
}
1933 2202
2203 +
/// Apply the current function specialization to resolver-owned type metadata.
2204 +
fn specializeType(
2205 +
    self: *mut FnLowerer,
2206 +
    ty: resolver::Type,
2207 +
    node: *ast::Node,
2208 +
) -> resolver::Type {
2209 +
    if let sub = self.low.specialization; resolver::containsGenericParameter(ty) {
2210 +
        return try resolver::substituteType(
2211 +
            self.low.resolver, ty, sub, node
2212 +
        ) catch {
2213 +
            panic "specializeType: substitution failed after resolution";
2214 +
        };
2215 +
    }
2216 +
    return ty;
2217 +
}
2218 +
1934 2219
/// Look up the resolved type of an AST node, or throw `MissingType`.
1935 2220
fn typeOf(self: *mut FnLowerer, node: *ast::Node) -> resolver::Type throws (LowerError) {
1936 2221
    let ty = resolver::typeFor(self.low.resolver, node)
1937 2222
        else throw LowerError::MissingType(node);
1938 -
    return ty;
2223 +
    return specializeType(self, ty, node);
1939 2224
}
1940 2225
1941 2226
/// Look up the symbol for an AST node, or throw `MissingSymbol`.
1942 2227
fn symOf(self: *mut FnLowerer, node: *ast::Node) -> *mut resolver::Symbol throws (LowerError) {
1943 2228
    let sym = resolver::nodeData(self.low.resolver, node).sym
3190 3475
/// For null-ptr-optimized types, loads the data pointer, or returns it
3191 3476
/// directly for scalar pointers. For aggregates, returns the tag register.
3192 3477
fn optionalNilReg(self: *mut FnLowerer, val: il::Val, typ: resolver::Type) -> il::Reg throws (LowerError) {
3193 3478
    let reg = emitValToReg(self, val);
3194 3479
3195 -
    match typ {
3196 -
        case resolver::Type::Optional(resolver::Type::Slice { .. }) => {
3480 +
    if let case resolver::Type::Optional(inner) = typ {
3481 +
        if let case resolver::Type::Slice(_) = *inner {
3197 3482
            let ptrReg = nextReg(self);
3198 3483
            emitLoadW64At(self, ptrReg, reg, SLICE_PTR_OFFSET);
3199 3484
            return ptrReg;
3200 3485
        }
3201 -
        case resolver::Type::Optional(resolver::Type::Pointer { .. }) => return reg,
3202 -
        case resolver::Type::Optional(_) => return tvalTagReg(self, reg),
3203 -
        else => return reg,
3486 +
        if let case resolver::Type::Pointer(_) = *inner {
3487 +
            return reg;
3488 +
        }
3489 +
        return tvalTagReg(self, reg);
3204 3490
    }
3491 +
    return reg;
3205 3492
}
3206 3493
3207 3494
/// Lower an optional nil check (`opt == nil` or `opt <> nil`).
3208 3495
fn lowerNilCheck(self: *mut FnLowerer, opt: *ast::Node, isEq: bool) -> il::Val throws (LowerError) {
3209 3496
    let optTy = try typeOf(self, opt);
3421 3708
            }
3422 3709
            // Plain nested record destructuring pattern.
3423 3710
            // Auto-deref: if the field is a pointer, load it first.
3424 3711
            let mut derefType = fieldInfo.fieldType;
3425 3712
            let mut nestedBase = emitPtrOffset(self, base, fieldInfo.offset);
3426 -
            if let case resolver::Type::Pointer { target, .. } = fieldInfo.fieldType {
3713 +
            if let case resolver::Type::Pointer(pointer) = fieldInfo.fieldType {
3427 3714
                let ptrReg = nextReg(self);
3428 3715
                emitLoadW64At(self, ptrReg, nestedBase, 0);
3429 3716
                set nestedBase = ptrReg;
3430 -
                set derefType = *target;
3717 +
                set derefType = *pointer.target;
3431 3718
            }
3432 3719
            let recInfo = resolver::getRecord(derefType)
3433 3720
                else throw LowerError::ExpectedRecord;
3434 3721
3435 3722
            try bindNestedRecordFields(self, nestedBase, lit, recInfo, matchBy, failBlock);
3457 3744
3458 3745
    // Auto-deref: when the field is a pointer and the pattern destructures
3459 3746
    // the pointed-to value, load the pointer and use the target type.
3460 3747
    // The loaded pointer becomes the base address for the nested subject.
3461 3748
    let mut derefBase: ?il::Reg = nil;
3462 -
    if let case resolver::Type::Pointer { target, .. } = fieldType {
3749 +
    if let case resolver::Type::Pointer(pointer) = fieldType {
3463 3750
        if resolver::isDestructuringPattern(pattern) {
3464 3751
            let ptrReg = nextReg(self);
3465 3752
            emitLoadW64At(self, ptrReg, fieldPtr, 0);
3466 3753
            set derefBase = ptrReg;
3467 -
            set fieldType = *target;
3754 +
            set fieldType = *pointer.target;
3468 3755
        }
3469 3756
    }
3470 3757
    // Build a MatchSubject for the nested field.
3471 3758
    let ilTy = ilType(self.low, fieldType);
3472 3759
    let kind = matchSubjectKind(fieldType);
4061 4348
/// choosing how to compare or store that value.
4062 4349
fn effectiveType(self: *mut FnLowerer, node: *ast::Node) -> resolver::Type throws (LowerError) {
4063 4350
    let ty = try typeOf(self, node);
4064 4351
    if let coerce = resolver::coercionFor(self.low.resolver, node) {
4065 4352
        if let case resolver::Coercion::OptionalLift(optTy) = coerce {
4066 -
            return optTy;
4353 +
            return specializeType(self, optTy, node);
4067 4354
        }
4068 4355
    }
4069 4356
    return ty;
4070 4357
}
4071 4358
4072 4359
/// Check if a resolver type lowers to an aggregate in memory.
4073 4360
fn isAggregateType(typ: resolver::Type) -> bool {
4074 4361
    match typ {
4075 -
        case resolver::Type::Slice { .. },
4076 -
             resolver::Type::TraitObject { .. } => return true,
4077 -
        case resolver::Type::Optional(resolver::Type::Pointer { .. }) => {
4362 +
        case resolver::Type::Optional(resolver::Type::Pointer(_)) => {
4078 4363
            // Optional pointers are scalar due to NPO.
4079 4364
            return false;
4080 4365
        }
4081 4366
        case resolver::Type::Optional(_) => {
4082 4367
            // All other optionals, including optional slices, are aggregates.
4084 4369
        }
4085 4370
        case resolver::Type::Nominal(_) => {
4086 4371
            // Void unions are small enough to pass by value.
4087 4372
            return not resolver::isVoidUnion(typ);
4088 4373
        }
4089 -
        case resolver::Type::Array(_),
4374 +
        case resolver::Type::Slice(_),
4375 +
             resolver::Type::TraitObject(_),
4376 +
             resolver::Type::Array(_),
4090 4377
             resolver::Type::Nil => return true,
4091 4378
        else => return false,
4092 4379
    }
4093 4380
}
4094 4381
4239 4526
/// For optional pointers (`?*T`), returns an immediate `0` (null pointer).
4240 4527
/// For other optionals, builds a tagged aggregate with tag set to `0` (absent).
4241 4528
fn buildNilOptional(self: *mut FnLowerer, optType: resolver::Type) -> il::Val throws (LowerError) {
4242 4529
    let case resolver::Type::Optional(inner) = optType
4243 4530
        else throw LowerError::ExpectedOptional;
4244 -
    if let case resolver::Type::Pointer { .. } = *inner {
4531 +
    if let case resolver::Type::Pointer(_) = *inner {
4245 4532
        return il::Val::Imm(0);
4246 4533
    }
4247 -
    if let case resolver::Type::Slice { item, mutable, .. } = *inner {
4534 +
    if let case resolver::Type::Slice(slice) = *inner {
4248 4535
        return try buildSliceValue(
4249 -
            self, item, mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0)
4536 +
            self, slice.item, slice.mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0)
4250 4537
        );
4251 4538
    }
4252 4539
    let valOffset = resolver::getOptionalValOffset(*inner) as i32;
4253 4540
    return try buildTagged(self, resolver::getTypeLayout(optType), 0, nil, *inner, 1, valOffset);
4254 4541
}
4274 4561
    mutable: bool,
4275 4562
    ptrVal: il::Val,
4276 4563
    lenVal: il::Val,
4277 4564
    capVal: il::Val
4278 4565
) -> il::Val throws (LowerError) {
4279 -
    let sliceType = resolver::Type::Slice {
4566 +
    let sliceType = resolver::Type::Slice(resolver::SliceType {
4280 4567
        class: types::PointerClass::Unsafe,
4281 4568
        item: elemTy,
4282 4569
        mutable,
4283 -
    };
4570 +
    });
4284 4571
    let dst = try emitReserve(self, sliceType);
4285 -
    let ptrTy = resolver::Type::Pointer {
4572 +
    let ptrTy = resolver::Type::Pointer(resolver::PointerType {
4286 4573
        class: types::PointerClass::Unsafe,
4287 4574
        target: elemTy,
4288 4575
        mutable,
4289 -
    };
4576 +
    });
4290 4577
4291 4578
    try emitStore(self, dst, SLICE_PTR_OFFSET, ptrTy, ptrVal);
4292 4579
    try emitStore(self, dst, SLICE_LEN_OFFSET, resolver::Type::U32, lenVal);
4293 4580
    try emitStore(self, dst, SLICE_CAP_OFFSET, resolver::Type::U32, capVal);
4294 4581
4300 4587
    self: *mut FnLowerer,
4301 4588
    dataVal: il::Val,
4302 4589
    traitInfo: *resolver::TraitType,
4303 4590
    inst: *resolver::InstanceEntry
4304 4591
) -> il::Val throws (LowerError) {
4305 -
    let vName = vtableName(self.low, inst.moduleId, inst.concreteTypeName, traitInfo.name);
4592 +
    let vName = vtableName(
4593 +
        self.low, inst.concreteType, traitInfo
4594 +
    );
4306 4595
4307 4596
    // Reserve space for the trait object on the stack.
4308 4597
    let slot = emitReserveLayout(self, resolver::Layout {
4309 4598
        size: resolver::PTR_SIZE * 2,
4310 4599
        alignment: resolver::PTR_SIZE,
4472 4761
    mutable: bool,
4473 4762
    a: il::Reg,
4474 4763
    b: il::Reg,
4475 4764
    offset: i32
4476 4765
) -> il::Val throws (LowerError) {
4477 -
    let ptrTy = resolver::Type::Pointer {
4766 +
    let ptrTy = resolver::Type::Pointer(resolver::PointerType {
4478 4767
        class: types::PointerClass::Unsafe,
4479 4768
        target: elemTy,
4480 4769
        mutable,
4481 -
    };
4770 +
    });
4482 4771
    let ptrEq = try emitEqAtOffset(self, a, b, offset + SLICE_PTR_OFFSET, ptrTy);
4483 4772
    let lenEq = try emitEqAtOffset(self, a, b, offset + SLICE_LEN_OFFSET, resolver::Type::U32);
4484 4773
4485 4774
    return emitTypedBinOp(self, il::BinOp::And, il::Type::W32, ptrEq, lenEq);
4486 4775
}
4725 5014
    a: il::Reg,
4726 5015
    b: il::Reg,
4727 5016
    offset: i32
4728 5017
) -> il::Val throws (LowerError) {
4729 5018
    match typ {
4730 -
        case resolver::Type::Slice { item, mutable, .. } =>
4731 -
            return try lowerSliceEq(self, item, mutable, a, b, offset),
5019 +
        case resolver::Type::Slice(slice) =>
5020 +
            return try lowerSliceEq(self, slice.item, slice.mutable, a, b, offset),
4732 5021
        case resolver::Type::Optional(inner) => {
4733 -
            if let case resolver::Type::Slice { item, mutable, .. } = *inner {
5022 +
            if let case resolver::Type::Slice(slice) = *inner {
4734 5023
                // Optional slices use null pointer optimization.
4735 -
                return try lowerSliceEq(self, item, mutable, a, b, offset);
5024 +
                return try lowerSliceEq(self, slice.item, slice.mutable, a, b, offset);
4736 5025
            }
4737 5026
            return try lowerOptionalEq(self, *inner, a, b, offset);
4738 5027
        }
4739 5028
        case resolver::Type::Array(arr) =>
4740 5029
            return try lowerArrayEq(self, arr, a, b, offset),
4942 5231
    range: ast::Range,
4943 5232
    info: resolver::SliceRangeInfo
4944 5233
) -> SliceRangeResult throws (LowerError) {
4945 5234
    let baseVal = try lowerExpr(self, container);
4946 5235
    let baseReg = emitValToReg(self, baseVal);
5236 +
    let itemType = specializeType(self, *info.itemType, container);
4947 5237
4948 5238
    // Extract data pointer and container length.
4949 5239
    let mut dataReg = baseReg;
4950 5240
    let mut containerLen: il::Val = undefined;
4951 5241
    if let cap = info.capacity { // Slice from array.
4983 5273
    // Only compute range offset and count if the start value is not
4984 5274
    // statically known to be zero.
4985 5275
    if startVal <> il::Val::Imm(0) {
4986 5276
        // Offset the data pointer by the start value.
4987 5277
        set dataReg = emitElem(
4988 -
            self, resolver::getTypeLayout(*info.itemType).size, dataReg, startVal
5278 +
            self, resolver::getTypeLayout(itemType).size, dataReg, startVal
4989 5279
        );
4990 5280
        // Compute the count as `end - start`.
4991 5281
        let lenReg = nextReg(self);
4992 5282
        emit(self, il::Instr::BinOp {
4993 5283
            op: il::BinOp::Sub,
5010 5300
) -> il::Val throws (LowerError) {
5011 5301
    let info = resolver::sliceRangeInfoFor(self.low.resolver, sliceNode) else {
5012 5302
        throw LowerError::MissingMetadata;
5013 5303
    };
5014 5304
    let r = try resolveSliceRangePtr(self, container, range, info);
5305 +
    let itemType = specializeType(self, *info.itemType, sliceNode);
5015 5306
    return try buildSliceValue(
5016 -
        self, info.itemType, info.mutable, il::Val::Reg(r.dataReg), r.count, r.count
5307 +
        self, &itemType, info.mutable, il::Val::Reg(r.dataReg), r.count, r.count
5017 5308
    );
5018 5309
}
5019 5310
5020 5311
/// Lower an address-of (`&x`) expression.
5021 5312
fn lowerAddressOf(self: *mut FnLowerer, node: *ast::Node, addr: ast::AddressOf) -> il::Val throws (LowerError) {
5090 5381
    self: *mut FnLowerer,
5091 5382
    sliceNode: *ast::Node,
5092 5383
    arrayNode: *ast::Node
5093 5384
) -> il::Val throws (LowerError) {
5094 5385
    let sliceTy = try typeOf(self, sliceNode);
5095 -
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy else {
5386 +
    let case resolver::Type::Slice(slice) = sliceTy else {
5096 5387
        throw LowerError::UnexpectedType(&sliceTy);
5097 5388
    };
5098 5389
    let arrayTy = try typeOf(self, arrayNode);
5099 5390
    let case resolver::Type::Array(arrayInfo) = arrayTy else {
5100 5391
        throw LowerError::ExpectedArray;
5101 5392
    };
5102 5393
    let length = arrayInfo.length;
5103 5394
    if length == 0 {
5104 5395
        return try buildSliceValue(
5105 -
            self, item, mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0)
5396 +
            self, slice.item, slice.mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0)
5106 5397
        );
5107 5398
    }
5108 5399
    if resolver::isConstExpr(self.low.resolver, arrayNode) {
5109 5400
        let mut b = dataBuilder(self.low.allocator);
5110 5401
        match arrayNode.value {
5113 5404
            case ast::NodeValue::ArrayRepeatLit(repeat) =>
5114 5405
                try lowerConstArrayRepeatInto(self.low, repeat, arrayTy, self.fnName, &mut b),
5115 5406
            else => throw LowerError::UnexpectedNodeValue(arrayNode),
5116 5407
        }
5117 5408
        let result = dataBuilderFinish(&b);
5118 -
        let alignment = resolver::getTypeLayout(*item).alignment;
5409 +
        let alignment = resolver::getTypeLayout(*slice.item).alignment;
5119 5410
        return try lowerConstDataAsSlice(
5120 -
            self, result.values, alignment, not mutable,
5121 -
            item, mutable, length
5411 +
            self, result.values, alignment, not slice.mutable,
5412 +
            slice.item, slice.mutable, length
5122 5413
        );
5123 5414
    }
5124 5415
    let data = try lowerExpr(self, arrayNode);
5125 5416
    let count = il::Val::Imm(length as i64);
5126 -
    return try buildSliceValue(self, item, mutable, data, count, count);
5417 +
    return try buildSliceValue(self, slice.item, slice.mutable, data, count, count);
5127 5418
}
5128 5419
5129 5420
/// Lower the common element pointer computation for subscript operations.
5130 5421
/// Handles both arrays and slices by resolving the container type, extracting
5131 5422
/// the data pointer (for slices), and emitting an [`il::Instr::Elem`] to compute
5141 5432
5142 5433
    let mut dataReg = baseReg;
5143 5434
    let mut elemType: resolver::Type = undefined;
5144 5435
5145 5436
    match subjectTy {
5146 -
        case resolver::Type::Slice { item, .. } => {
5147 -
            set elemType = *item;
5437 +
        case resolver::Type::Slice(slice) => {
5438 +
            set elemType = *slice.item;
5148 5439
            let sliceLen = loadSliceLen(self, baseReg);
5149 5440
            // Runtime safety check: index must be strictly less than slice length.
5150 5441
            try emitTrapUnlessCmp(self, il::CmpOp::Ult, il::Type::W32, indexVal, sliceLen);
5151 5442
            set dataReg = loadSlicePtr(self, baseReg);
5152 5443
        }
5427 5718
    container: *ast::Node,
5428 5719
    range: ast::Range,
5429 5720
    info: resolver::SliceRangeInfo
5430 5721
) throws (LowerError) {
5431 5722
    let r = try resolveSliceRangePtr(self, container, range, info);
5432 -
    let elemSize = resolver::getTypeLayout(*info.itemType).size;
5723 +
    let itemType = specializeType(self, *info.itemType, container);
5724 +
    let elemSize = resolver::getTypeLayout(itemType).size;
5433 5725
    let rhsTy = try typeOf(self, rhs);
5434 5726
5435 -
    if let case resolver::Type::Slice { .. } = rhsTy {
5727 +
    if let case resolver::Type::Slice(_) = rhsTy {
5436 5728
        // Copy from source slice.
5437 5729
        let srcReg = emitValToReg(self, try lowerExpr(self, rhs));
5438 5730
        let srcData = loadSlicePtr(self, srcReg);
5439 5731
        let srcLen = loadSliceLen(self, srcReg);
5440 5732
5446 5738
        );
5447 5739
        try emitByteCopyLoop(self, r.dataReg, srcData, bytes, "copy");
5448 5740
    } else {
5449 5741
        // Fill with scalar value.
5450 5742
        let fillVal = try lowerExpr(self, rhs);
5451 -
        try emitFillLoop(self, r.dataReg, fillVal, r.count, *info.itemType, elemSize);
5743 +
        try emitFillLoop(self, r.dataReg, fillVal, r.count, itemType, elemSize);
5452 5744
    }
5453 5745
}
5454 5746
5455 5747
/// Emit a typed fill loop: `for i in 0..count { dst[i * stride] = value; }`.
5456 5748
fn emitFillLoop(
5652 5944
    match info {
5653 5945
        case resolver::ForLoopInfo::Range { valType, range, bindingName, indexName } => {
5654 5946
            let endExpr = range.end else {
5655 5947
                throw LowerError::MissingMetadata;
5656 5948
            };
5949 +
            let concreteValType = specializeType(self, *valType, node);
5657 5950
            let mut startVal = il::Val::Imm(0);
5658 5951
            if let start = range.start {
5659 5952
                set startVal = try lowerExpr(self, start);
5660 5953
            }
5661 5954
            let endVal = try lowerExpr(self, endExpr);
5662 -
            let iterType = ilType(self.low, *valType);
5955 +
            let iterType = ilType(self.low, concreteValType);
5663 5956
            let valVar = newVar(self, bindingName, iterType, false, startVal);
5664 5957
5665 5958
            let mut indexVar: ?Var = nil;
5666 -
            if indexName <> nil { // Optional index always starts at zero.
5667 -
                set indexVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0));
5959 +
            if indexName <> nil {
5960 +
                set indexVar = newVar(
5961 +
                    self, indexName, il::Type::W32, false, il::Val::Imm(0)
5962 +
                );
5668 5963
            }
5669 5964
            let iter = ForIter::Range {
5670 -
                valVar, indexVar, endVal, valType: iterType,
5671 -
                unsigned: isUnsignedType(*valType),
5965 +
                valVar,
5966 +
                indexVar,
5967 +
                endVal,
5968 +
                valType: iterType,
5969 +
                unsigned: isUnsignedType(concreteValType),
5672 5970
            };
5673 -
5674 5971
            try lowerForLoop(self, &iter, f.body);
5675 5972
        }
5676 5973
        case resolver::ForLoopInfo::Collection { elemType, length, bindingName, indexName } => {
5974 +
            let concreteElemType = specializeType(self, *elemType, node);
5677 5975
            let containerVal = try lowerExpr(self, f.iterable);
5678 5976
            let containerReg = emitValToReg(self, containerVal);
5679 5977
5680 5978
            let mut dataReg = containerReg;
5681 5979
            let mut lengthVal: il::Val = undefined;
5682 -
            if let len = length { // Array (length is known).
5980 +
            if let len = length {
5683 5981
                set lengthVal = il::Val::Imm(len as i64);
5684 -
            } else { // Slice (length must be loaded).
5982 +
            } else {
5685 5983
                set lengthVal = loadSliceLen(self, containerReg);
5686 5984
                set dataReg = loadSlicePtr(self, containerReg);
5687 5985
            }
5688 -
            // Declare index value binidng.
5689 -
            let idxVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0));
5690 -
5691 -
            // Declare element value binding.
5986 +
            let idxVar = newVar(
5987 +
                self, indexName, il::Type::W32, false, il::Val::Imm(0)
5988 +
            );
5692 5989
            let mut valVar: ?Var = nil;
5693 5990
            if bindingName <> nil {
5694 5991
                set valVar = newVar(
5695 5992
                    self,
5696 5993
                    bindingName,
5697 -
                    ilType(self.low, *elemType),
5994 +
                    ilType(self.low, concreteElemType),
5698 5995
                    false,
5699 -
                    il::Val::Undef
5996 +
                    il::Val::Undef,
5700 5997
                );
5701 5998
            }
5702 -
            let iter = ForIter::Collection { valVar, idxVar, dataReg, lengthVal, elemType };
5703 -
5999 +
            let iter = ForIter::Collection {
6000 +
                valVar,
6001 +
                idxVar,
6002 +
                dataReg,
6003 +
                lengthVal,
6004 +
                elemType: &concreteElemType,
6005 +
            };
5704 6006
            try lowerForLoop(self, &iter, f.body);
5705 6007
        }
5706 6008
    }
5707 6009
    exitVarScope(self, savedVarsLen);
5708 6010
}
6172 6474
/// String literals are stored as global data and the result is a slice
6173 6475
/// pointing to the data with the appropriate length.
6174 6476
fn lowerStringLit(self: *mut FnLowerer, node: *ast::Node, s: *[u8]) -> il::Val throws (LowerError) {
6175 6477
    // Get the slice type from the node.
6176 6478
    let sliceTy = try typeOf(self, node);
6177 -
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy
6479 +
    let case resolver::Type::Slice(slice) = sliceTy
6178 6480
        else throw LowerError::ExpectedSliceOrArray;
6179 6481
    // Build the string data value.
6180 6482
    let ptr = try! alloc::alloc(
6181 6483
        self.low.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue)
6182 6484
    ) as *mut il::DataValue;
6183 6485
6184 6486
    set *ptr = il::DataValue { item: il::DataItem::Str(s), count: 1 };
6185 6487
6186 6488
    return try lowerConstDataAsSlice(
6187 -
        self, @sliceOf(ptr, 1), 1, true, item, mutable, s.len
6489 +
        self, @sliceOf(ptr, 1), 1, true, slice.item, slice.mutable, s.len
6188 6490
    );
6189 6491
}
6190 6492
6191 6493
/// Lower a builtin call expression.
6192 6494
fn lowerBuiltinCall(self: *mut FnLowerer, node: *ast::Node, kind: ast::Builtin, args: *mut [*ast::Node]) -> il::Val throws (LowerError) {
6205 6507
fn lowerSliceOf(self: *mut FnLowerer, node: *ast::Node, args: *mut [*ast::Node]) -> il::Val throws (LowerError) {
6206 6508
    if args.len <> 2 and args.len <> 3 {
6207 6509
        throw LowerError::InvalidArgCount;
6208 6510
    }
6209 6511
    let sliceTy = try typeOf(self, node);
6210 -
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy
6512 +
    let case resolver::Type::Slice(slice) = sliceTy
6211 6513
        else throw LowerError::ExpectedSliceOrArray;
6212 6514
    let ptrVal = try lowerExpr(self, args[0]);
6213 6515
    let lenVal = try lowerExpr(self, args[1]);
6214 6516
    let mut capVal = lenVal;
6215 6517
    if args.len == 3 {
6216 6518
        set capVal = try lowerExpr(self, args[2]);
6217 6519
    }
6218 6520
    if not isLtEq(lenVal, capVal) {
6219 6521
        try emitTrapIfLt(self, il::Type::W32, capVal, lenVal);
6220 6522
    }
6221 -
    return try buildSliceValue(self, item, mutable, ptrVal, lenVal, capVal);
6523 +
    return try buildSliceValue(self, slice.item, slice.mutable, ptrVal, lenVal, capVal);
6222 6524
}
6223 6525
6224 6526
/// Lower a `try` expression.
6225 6527
fn lowerTry(self: *mut FnLowerer, node: *ast::Node, t: ast::Try) -> il::Val throws (LowerError) {
6226 6528
    let case ast::NodeValue::Call(callExpr) = t.expr.value else {
6240 6542
    let callNodeExtra = resolver::nodeData(self.low.resolver, t.expr).extra;
6241 6543
    if let case resolver::NodeExtra::TraitMethodCall {
6242 6544
        traitInfo, methodIndex
6243 6545
    } = callNodeExtra {
6244 6546
        set resVal = try lowerTraitMethodCall(self, t.expr, callExpr, traitInfo, methodIndex);
6547 +
    } else if let case resolver::NodeExtra::GenericBoundMethodCall {
6548 +
        param, traitInfo, methodIndex, explicitReceiver,
6549 +
    } = callNodeExtra {
6550 +
        set resVal = try lowerGenericBoundMethodCall(
6551 +
            self, t.expr, callExpr, param, traitInfo, methodIndex, explicitReceiver
6552 +
        );
6245 6553
    } else if let case resolver::NodeExtra::MethodCall { method } = callNodeExtra {
6246 6554
        set resVal = try lowerMethodCall(self, t.expr, callExpr, method);
6247 6555
    } else {
6248 6556
        set resVal = try lowerCall(self, t.expr, callExpr);
6249 6557
    }
6642 6950
fn lowerCallOrCtor(self: *mut FnLowerer, node: *ast::Node, call: ast::Call) -> il::Val throws (LowerError) {
6643 6951
    let nodeData = resolver::nodeData(self.low.resolver, node).extra;
6644 6952
6645 6953
    // Check for slice method dispatch.
6646 6954
    if let case resolver::NodeExtra::SliceAppend { elemType } = nodeData {
6647 -
        return try lowerSliceAppend(self, call, elemType);
6955 +
        let concrete = specializeType(self, *elemType, node);
6956 +
        return try lowerSliceAppend(self, call, &concrete);
6648 6957
    }
6649 6958
    if let case resolver::NodeExtra::SliceDelete { elemType } = nodeData {
6650 -
        try lowerSliceDelete(self, call, elemType);
6959 +
        let concrete = specializeType(self, *elemType, node);
6960 +
        try lowerSliceDelete(self, call, &concrete);
6651 6961
        return il::Val::Undef;
6652 6962
    }
6653 6963
    // Check for trait method dispatch.
6654 6964
    if let case resolver::NodeExtra::TraitMethodCall { traitInfo, methodIndex } = nodeData {
6655 6965
        return try lowerTraitMethodCall(self, node, call, traitInfo, methodIndex);
6656 6966
    }
6967 +
    if let case resolver::NodeExtra::GenericBoundMethodCall {
6968 +
        param, traitInfo, methodIndex, explicitReceiver,
6969 +
    } = nodeData {
6970 +
        return try lowerGenericBoundMethodCall(
6971 +
            self, node, call, param, traitInfo, methodIndex, explicitReceiver
6972 +
        );
6973 +
    }
6657 6974
    // Check for standalone method call.
6658 6975
    if let case resolver::NodeExtra::MethodCall { method } = nodeData {
6659 6976
        return try lowerMethodCall(self, node, call, method);
6660 6977
    }
6661 6978
    if let sym = resolver::nodeData(self.low.resolver, call.callee).sym {
6823 7140
/// If the parent is already a pointer type, the value is used directly.
6824 7141
/// If the parent is a value type (eg. a local record), its address is taken.
6825 7142
fn lowerReceiver(self: *mut FnLowerer, parent: *ast::Node, parentTy: resolver::Type) -> il::Val
6826 7143
    throws (LowerError)
6827 7144
{
6828 -
    if let case resolver::Type::Pointer { .. } = parentTy {
7145 +
    if let case resolver::Type::Pointer(_) = parentTy {
6829 7146
        // Already a pointer: lower and use directly.
6830 7147
        return try lowerExpr(self, parent);
6831 7148
    }
6832 7149
    // Value type: take its address by lowering it and returning the slot pointer.
6833 7150
    // Aggregate types are already lowered as pointers to stack slots.
6841 7158
    try emitStore(self, slot, 0, parentTy, val);
6842 7159
6843 7160
    return il::Val::Reg(slot);
6844 7161
}
6845 7162
7163 +
/// Lower a bounded generic method to its concrete instance function.
7164 +
fn lowerGenericBoundMethodCall(
7165 +
    self: *mut FnLowerer,
7166 +
    node: *ast::Node,
7167 +
    call: ast::Call,
7168 +
    param: *resolver::GenericParamType,
7169 +
    traitInfo: *resolver::TraitType,
7170 +
    methodIndex: u32,
7171 +
    explicitReceiver: bool,
7172 +
) -> il::Val throws (LowerError) {
7173 +
    let mut receiverNode: *ast::Node = undefined;
7174 +
    if explicitReceiver {
7175 +
        if call.args.len == 0 {
7176 +
            throw LowerError::MissingMetadata;
7177 +
        }
7178 +
        set receiverNode = call.args[0];
7179 +
    } else {
7180 +
        let case ast::NodeValue::FieldAccess(access) = call.callee.value
7181 +
            else throw LowerError::MissingMetadata;
7182 +
        set receiverNode = access.parent;
7183 +
    }
7184 +
    let concreteType = specializeType(
7185 +
        self, resolver::Type::Parameter(param), node
7186 +
    );
7187 +
    let inst = resolver::findInstance(
7188 +
        self.low.resolver, traitInfo, concreteType
7189 +
    ) else throw LowerError::MissingMetadata;
7190 +
    let method = &traitInfo.methods[methodIndex];
7191 +
    let _ = resolver::findInstance(
7192 +
        self.low.resolver, method.owner, concreteType
7193 +
    ) else throw LowerError::MissingMetadata;
7194 +
    let methodSym = inst.methods[methodIndex];
7195 +
    let case resolver::SymbolData::Value {
7196 +
        type: resolver::Type::Fn(fnInfo), ..
7197 +
    } = methodSym.data else throw LowerError::MissingMetadata;
7198 +
    let mut receiverVal: il::Val = undefined;
7199 +
    if explicitReceiver {
7200 +
        set receiverVal = try lowerCallArg(self, receiverNode, call.args.len > 1);
7201 +
    } else {
7202 +
        let receiverType = try typeOf(self, receiverNode);
7203 +
        set receiverVal = try lowerReceiver(self, receiverNode, receiverType);
7204 +
    }
7205 +
    let qualName = instanceMethodName(
7206 +
        self.low,
7207 +
        concreteType,
7208 +
        method.owner,
7209 +
        method.name,
7210 +
    );
7211 +
    let argOffset: u32 = 1 if requiresReturnParam(fnInfo) else 0;
7212 +
    let receiverCount: u32 = 0 if explicitReceiver else 1;
7213 +
    let args = try allocVals(self, call.args.len + receiverCount + argOffset);
7214 +
    set args[argOffset] = receiverVal;
7215 +
    for arg, i in call.args {
7216 +
        if explicitReceiver and i == 0 {
7217 +
            continue;
7218 +
        }
7219 +
        set args[i + receiverCount + argOffset] = try lowerCallArg(
7220 +
            self, arg, i + 1 < call.args.len
7221 +
        );
7222 +
    }
7223 +
    return try emitCallValue(self, il::Val::FnAddr(qualName), fnInfo, args);
7224 +
}
7225 +
6846 7226
/// Lower a standalone method call via direct dispatch.
6847 7227
///
6848 7228
/// Given `obj.method(args)` where `method` is a standalone method on a concrete type,
6849 7229
/// emits a direct call with the receiver address as the first argument:
6850 7230
///
6861 7241
6862 7242
    // Get the receiver as a pointer.
6863 7243
    let parentTy = try typeOf(self, access.parent);
6864 7244
    let receiverVal = try lowerReceiver(self, access.parent, parentTy);
6865 7245
6866 -
    let qualName = instanceMethodName(self.low, nil, method.concreteTypeName, method.name);
6867 7246
    let case resolver::SymbolData::Value { type: resolver::Type::Fn(fnInfo), .. } = method.symbol.data
6868 7247
        else panic "lowerMethodCall: expected Fn type on method symbol";
7248 +
    let qualName = instanceMethodName(
7249 +
        self.low, method.concreteType, nil, method.name
7250 +
    );
6869 7251
6870 7252
    // Build args: optional return param slot + receiver + user args.
6871 7253
    let argOffset: u32 = 1 if requiresReturnParam(fnInfo) else 0;
6872 7254
    let args = try allocVals(self, call.args.len + 1 + argOffset);
6873 7255
    set args[argOffset] = receiverVal;
6939 7321
6940 7322
/// Resolve callee to an IL value. For direct function calls, use the symbol name.
6941 7323
/// For variables holding function pointers or complex expressions (eg. `array[i]()`),
6942 7324
/// lower the callee expression.
6943 7325
fn lowerCallee(self: *mut FnLowerer, callee: *ast::Node) -> il::Val throws (LowerError) {
7326 +
    if let generic = try lowerGenericFnValue(self, callee) {
7327 +
        return generic;
7328 +
    }
6944 7329
    if let sym = resolver::nodeData(self.low.resolver, callee).sym {
6945 7330
        if let case ast::NodeValue::FnDecl(_) = sym.node.value {
6946 7331
            // First try to look up the symbol in our registered functions.
6947 7332
            // This handles cross-package calls correctly, since packages are
6948 7333
            // lowered in dependency order.
6987 7372
    let coerce = resolver::coercionFor(self.low.resolver, node) else {
6988 7373
        return val;
6989 7374
    };
6990 7375
    match coerce {
6991 7376
        case resolver::Coercion::OptionalLift(optType) => {
7377 +
            let concrete = specializeType(self, optType, node);
6992 7378
            if let case ast::NodeValue::Nil = node.value {
6993 -
                return try buildNilOptional(self, optType);
7379 +
                return try buildNilOptional(self, concrete);
6994 7380
            }
6995 -
            return try wrapInOptional(self, val, optType);
7381 +
            return try wrapInOptional(self, val, concrete);
6996 7382
        }
6997 7383
        case resolver::Coercion::NumericCast { from, to } => {
6998 -
            return lowerNumericCast(self, val, from, to);
7384 +
            return lowerNumericCast(
7385 +
                self,
7386 +
                val,
7387 +
                specializeType(self, from, node),
7388 +
                specializeType(self, to, node),
7389 +
            );
6999 7390
        }
7000 7391
        case resolver::Coercion::ResultWrap => {
7001 7392
            let payloadType = *self.fnType.returnType;
7002 7393
            return try buildResult(self, 0, val, payloadType);
7003 7394
        }
7134 7525
        else =>
7135 7526
            throw LowerError::UnexpectedNodeValue(node),
7136 7527
    }
7137 7528
}
7138 7529
7530 +
/// Lower a rigid constant parameter using the active specialization.
7531 +
fn lowerGenericConstValue(
7532 +
    self: *mut FnLowerer,
7533 +
    node: *ast::Node,
7534 +
) -> ?il::Val {
7535 +
    let sub = self.low.specialization else return nil;
7536 +
    let sym = resolver::symbolFor(self.low.resolver, node) else return nil;
7537 +
    let case resolver::SymbolData::ConstParameter(param) = sym.data else return nil;
7538 +
    let arg = resolver::substitutionArg(sub, param);
7539 +
    let case resolver::Type::ConstArgument { value, .. } = arg else return nil;
7540 +
    return il::Val::Imm(constIntToI64(value));
7541 +
}
7542 +
7543 +
/// Lower resolver-selected generic function metadata to a concrete address.
7544 +
fn lowerGenericFnValue(
7545 +
    self: *mut FnLowerer,
7546 +
    node: *ast::Node,
7547 +
) -> ?il::Val throws (LowerError) {
7548 +
    let data = resolver::nodeData(self.low.resolver, node);
7549 +
    match data.extra {
7550 +
        case resolver::NodeExtra::GenericFnCall(specialization) => {
7551 +
            return il::Val::FnAddr(
7552 +
                specializationName(self.low, specialization)
7553 +
            );
7554 +
        }
7555 +
        case resolver::NodeExtra::GenericFnDependency(dependency) => {
7556 +
            let caller = self.low.genericSpecialization
7557 +
                else throw LowerError::MissingMetadata;
7558 +
            let specialization = resolver::genericFnSpecializationForDependency(
7559 +
                self.low.resolver, dependency, caller
7560 +
            ) else throw LowerError::MissingMetadata;
7561 +
            return il::Val::FnAddr(
7562 +
                specializationName(self.low, specialization)
7563 +
            );
7564 +
        }
7565 +
        else => return nil,
7566 +
    }
7567 +
}
7568 +
7139 7569
/// Lower an expression AST node to an IL value.
7140 7570
/// This is the main expression dispatch, all expression nodes go through here.
7141 7571
fn lowerExpr(self: *mut FnLowerer, node: *ast::Node) -> il::Val throws (LowerError) {
7142 7572
    if self.low.options.debug {
7143 7573
        set self.srcLoc.offset = node.span.offset;
7144 7574
    }
7145 7575
    let mut val: il::Val = undefined;
7146 7576
7147 7577
    match node.value {
7148 7578
        case ast::NodeValue::Ident(_) => {
7149 -
            // First try local variable lookup.
7150 -
            // Otherwise fall back to global symbol lookup.
7151 -
            if let v = lookupLocalVar(self, node) {
7579 +
            if let constVal = lowerGenericConstValue(self, node) {
7580 +
                set val = constVal;
7581 +
            } else if let generic = try lowerGenericFnValue(self, node) {
7582 +
                set val = generic;
7583 +
            // First try local variable lookup, then global symbol lookup.
7584 +
            } else if let v = lookupLocalVar(self, node) {
7152 7585
                set val = try useVar(self, v);
7153 7586
                if self.vars[*v].addressTaken {
7154 7587
                    let typ = try typeOf(self, node);
7155 7588
                    let ptr = emitValToReg(self, val);
7156 7589
                    set val = emitRead(self, ptr, 0, typ);
7158 7591
            } else {
7159 7592
                set val = try lowerGlobalSymbol(self, node);
7160 7593
            }
7161 7594
        }
7162 7595
        case ast::NodeValue::ScopeAccess(_) => {
7163 -
            set val = try lowerScopeAccess(self, node);
7596 +
            if let generic = try lowerGenericFnValue(self, node) {
7597 +
                set val = generic;
7598 +
            } else {
7599 +
                set val = try lowerScopeAccess(self, node);
7600 +
            }
7164 7601
        }
7165 7602
        case ast::NodeValue::Number(lit) => {
7166 7603
            set val = il::Val::Imm(lit.magnitude as i64);
7167 7604
        }
7168 7605
        case ast::NodeValue::Bool(b) => {
7199 7636
            set val = try lowerUnOp(self, node, unop);
7200 7637
        }
7201 7638
        case ast::NodeValue::Subscript { container, index } => {
7202 7639
            set val = try lowerSubscript(self, node, container, index);
7203 7640
        }
7641 +
        case ast::NodeValue::GenericApply(_) => {
7642 +
            let generic = try lowerGenericFnValue(self, node)
7643 +
                else panic "lowerExpr: unresolved generic application";
7644 +
            set val = generic;
7645 +
        }
7204 7646
        case ast::NodeValue::BuiltinCall { kind, args } => {
7205 7647
            set val = try lowerBuiltinCall(self, node, kind, args);
7206 7648
        }
7207 7649
        case ast::NodeValue::Call(call) => {
7208 7650
            set val = try lowerCallOrCtor(self, node, call);
7218 7660
                    //       Perhaps just store the `ConstInt`.
7219 7661
                    case resolver::ConstValue::Int(i) => set val = il::Val::Imm(constIntToI64(i)),
7220 7662
                    else => set val = try lowerFieldAccess(self, access),
7221 7663
                }
7222 7664
            } else {
7223 -
                set val = try lowerFieldAccess(self, access);
7665 +
                let parentTy = try typeOf(self, access.parent);
7666 +
                let mut handled = false;
7667 +
                if let case resolver::Type::Array(array) = parentTy {
7668 +
                    if let case ast::NodeValue::Ident(name) = access.child.value;
7669 +
                       mem::eq(name, "len")
7670 +
                    {
7671 +
                        set val = il::Val::Imm(array.length as i64);
7672 +
                        set handled = true;
7673 +
                    }
7674 +
                }
7675 +
                if not handled {
7676 +
                    set val = try lowerFieldAccess(self, access);
7677 +
                }
7224 7678
            }
7225 7679
        }
7226 7680
        case ast::NodeValue::ArrayLit(elements) => {
7227 7681
            set val = try lowerArrayLit(self, node, elements);
7228 7682
        }
7310 7764
             resolver::Type::U16 => return il::Type::W16,
7311 7765
        case resolver::Type::I32,
7312 7766
             resolver::Type::U32 => return il::Type::W32,
7313 7767
        case resolver::Type::I64,
7314 7768
             resolver::Type::U64,
7315 -
             resolver::Type::Pointer { .. },
7316 -
             resolver::Type::Slice { .. },
7317 -
             resolver::Type::TraitObject { .. },
7769 +
             resolver::Type::Pointer(_),
7770 +
             resolver::Type::Slice(_),
7771 +
             resolver::Type::TraitObject(_),
7318 7772
             resolver::Type::Array(_),
7319 7773
             resolver::Type::Optional(_),
7320 7774
             resolver::Type::Fn(_) => return il::Type::W64,
7321 7775
        case resolver::Type::Nominal(_) => {
7322 7776
            if resolver::isVoidUnion(typ) {
lib/std/lang/parser.rad +152 -13
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(
1964 2084
        }
1965 2085
        case scanner::TokenKind::LBracket => {
1966 2086
            return try parseArrayType(p);
1967 2087
        }
1968 2088
        case scanner::TokenKind::Super, scanner::TokenKind::Ident => {
1969 -
            let path = try parseTypePath(p);
1970 -
2089 +
            let mut name = try parseTypePath(p);
2090 +
            if check(p, scanner::TokenKind::LAngle) {
2091 +
                set name = try parseGenericApply(p, name);
2092 +
            }
1971 2093
            return node(p, ast::NodeValue::TypeSig(
1972 -
                ast::TypeSig::Nominal(path)
2094 +
                ast::TypeSig::Nominal(name)
1973 2095
            ));
1974 2096
        }
1975 2097
        case scanner::TokenKind::U8 => {
1976 2098
            advance(p);
1977 2099
            return nodeTypeInt(p, 1, ast::Signedness::Unsigned);
2238 2360
        case scanner::TokenKind::RBrace => return "expected `}`",
2239 2361
        else => return "expected delimiter",
2240 2362
    }
2241 2363
}
2242 2364
2365 +
/// Parse one or more explicit specialization roots.
2366 +
fn parseInstantiate(p: *mut Parser) -> *ast::Node throws (ParseError) {
2367 +
    try expect(p, scanner::TokenKind::Instantiate, "expected `instantiate`");
2368 +
    let mut applications = ast::nodeSlice(p.arena, 4);
2369 +
    loop {
2370 +
        let target = try parseTypePath(p);
2371 +
        if not check(p, scanner::TokenKind::LAngle) {
2372 +
            throw failParsing(p, "`instantiate` requires a generic application");
2373 +
        }
2374 +
        applications.append(try parseGenericApply(p, target), p.allocator);
2375 +
        if not consume(p, scanner::TokenKind::Comma) {
2376 +
            break;
2377 +
        }
2378 +
    }
2379 +
    return node(p, ast::NodeValue::Instantiate(applications));
2380 +
}
2381 +
2243 2382
/// Parse a trait declaration.
2244 2383
/// Syntax: `trait Name { fn (*Trait) method(...) -> T; ... }`
2245 2384
fn parseTraitDecl(p: *mut Parser, attrs: ?ast::Attributes) -> *ast::Node
2246 2385
    throws (ParseError)
2247 2386
{
2291 2430
    throws (ParseError)
2292 2431
{
2293 2432
    try expect(p, scanner::TokenKind::Instance, "expected `instance`");
2294 2433
    let traitName = try parseTypePath(p);
2295 2434
    try expect(p, scanner::TokenKind::For, "expected `for` after trait name");
2296 -
    let targetType = try parseTypePath(p);
2435 +
    let targetType = try parseType(p);
2297 2436
    try expect(p, scanner::TokenKind::LBrace, "expected `{` after target type");
2298 2437
    let mut methods = ast::nodeSlice(p.arena, ast::MAX_TRAIT_METHODS);
2299 2438
2300 2439
    while not check(p, scanner::TokenKind::RBrace) and
2301 2440
          not check(p, scanner::TokenKind::Eof)
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
2938 2955
    // Throws lists.
2939 2956
    let throwsNode = try! parseStmtStr("fn handle() throws (Error, Other,) {}");
2940 2957
    let case ast::NodeValue::FnDecl(throwsDecl) = throwsNode.value else throw testing::TestError::Failed;
2941 2958
    try testing::expect(throwsDecl.sig.throwList.len == 2);
2942 2959
}
2960 +
2961 +
/// Generic declarations retain ordered type, bound, and constant parameters.
2962 +
@test fn testParseGenericDeclarations() throws (testing::TestError) {
2963 +
    let recordNode = try! parseStmtStr(
2964 +
        "record Pair⟨T: Reader + Writer, U⟩ { first: T, second: U }"
2965 +
    );
2966 +
    let case ast::NodeValue::RecordDecl(recordDecl) = recordNode.value
2967 +
        else throw testing::TestError::Failed;
2968 +
    assert recordDecl.params.len == 2;
2969 +
    let case ast::NodeValue::GenericParam(ast::GenericParam::Type {
2970 +
        name: firstName, bounds
2971 +
    }) = recordDecl.params[0].value else throw testing::TestError::Failed;
2972 +
    try expectIdent(firstName, "T");
2973 +
    assert bounds.len == 2;
2974 +
    try expectIdent(bounds[0], "Reader");
2975 +
    try expectIdent(bounds[1], "Writer");
2976 +
2977 +
    let unionNode = try! parseStmtStr("union Maybe⟨T⟩ { None, Some(T) }");
2978 +
    let case ast::NodeValue::UnionDecl(unionDecl) = unionNode.value
2979 +
        else throw testing::TestError::Failed;
2980 +
    assert unionDecl.params.len == 1;
2981 +
2982 +
    let fnNode = try! parseStmtStr("fn first⟨T⟩(value: T) -> T { return value; }");
2983 +
    let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value
2984 +
        else throw testing::TestError::Failed;
2985 +
    assert fnDecl.params.len == 1;
2986 +
2987 +
    let constNode = try! parseStmtStr(
2988 +
        "record InlineVec⟨T, constant N: u32⟩ { data: [T; 4] }"
2989 +
    );
2990 +
    let case ast::NodeValue::RecordDecl(constDecl) = constNode.value
2991 +
        else throw testing::TestError::Failed;
2992 +
    let case ast::NodeValue::GenericParam(ast::GenericParam::Const {
2993 +
        name: constName, type: constType
2994 +
    }) = constDecl.params[1].value else throw testing::TestError::Failed;
2995 +
    try expectIdent(constName, "N");
2996 +
    try expectIntType(constType, 4, ast::Signedness::Unsigned);
2997 +
}
2998 +
2999 +
/// Generic applications nest in nominal types and preserve qualified targets.
3000 +
@test fn testParseGenericTypeApplications() throws (testing::TestError) {
3001 +
    let node = try! parseTypeStr("Result⟨collections::Vec⟨T⟩, E⟩");
3002 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(outerNode)) = node.value
3003 +
        else throw testing::TestError::Failed;
3004 +
    let case ast::NodeValue::GenericApply(outer) = outerNode.value
3005 +
        else throw testing::TestError::Failed;
3006 +
    try expectIdent(outer.target, "Result");
3007 +
    assert outer.args.len == 2;
3008 +
3009 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(innerNode)) =
3010 +
        outer.args[0].value else throw testing::TestError::Failed;
3011 +
    let case ast::NodeValue::GenericApply(inner) = innerNode.value
3012 +
        else throw testing::TestError::Failed;
3013 +
    let case ast::NodeValue::ScopeAccess(path) = inner.target.value
3014 +
        else throw testing::TestError::Failed;
3015 +
    try expectIdent(path.parent, "collections");
3016 +
    try expectIdent(path.child, "Vec");
3017 +
    assert inner.args.len == 1;
3018 +
    try expectTypeIdent(inner.args[0], "T");
3019 +
    try expectTypeIdent(outer.args[1], "E");
3020 +
3021 +
    let constNode = try! parseTypeStr("InlineVec⟨T, N + 1⟩");
3022 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(constAppNode)) =
3023 +
        constNode.value else throw testing::TestError::Failed;
3024 +
    let case ast::NodeValue::GenericApply(constApp) = constAppNode.value
3025 +
        else throw testing::TestError::Failed;
3026 +
    let case ast::NodeValue::BinOp(constExpr) = constApp.args[1].value
3027 +
        else throw testing::TestError::Failed;
3028 +
    assert constExpr.op == ast::BinaryOp::Add;
3029 +
    try expectIdent(constExpr.left, "N");
3030 +
    try expectNumber(constExpr.right, "1");
3031 +
3032 +
    let rangeNode = try! parseTypeStr("Window⟨0..⟩");
3033 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(rangeAppNode)) =
3034 +
        rangeNode.value else throw testing::TestError::Failed;
3035 +
    let case ast::NodeValue::GenericApply(rangeApp) = rangeAppNode.value
3036 +
        else throw testing::TestError::Failed;
3037 +
    let case ast::NodeValue::Range(range) = rangeApp.args[0].value
3038 +
        else throw testing::TestError::Failed;
3039 +
    assert range.start <> nil;
3040 +
    assert range.end == nil;
3041 +
}
3042 +
3043 +
/// Function applications use generic syntax without changing array subscripts.
3044 +
@test fn testParseGenericFunctionApplications() throws (testing::TestError) {
3045 +
    let explicit = try! parseExprStr("first⟨i32⟩(value)");
3046 +
    let case ast::NodeValue::Call(call) = explicit.value
3047 +
        else throw testing::TestError::Failed;
3048 +
    let case ast::NodeValue::GenericApply(app) = call.callee.value
3049 +
        else throw testing::TestError::Failed;
3050 +
    try expectIdent(app.target, "first");
3051 +
    assert app.args.len == 1;
3052 +
    try expectIntType(app.args[0], 4, ast::Signedness::Signed);
3053 +
3054 +
    let singleSymbolic = try! parseExprStr("first⟨T⟩(value)");
3055 +
    let case ast::NodeValue::Call(singleCall) = singleSymbolic.value
3056 +
        else throw testing::TestError::Failed;
3057 +
    let case ast::NodeValue::GenericApply(singleApp) = singleCall.callee.value
3058 +
        else throw testing::TestError::Failed;
3059 +
    assert singleApp.args.len == 1;
3060 +
    try expectTypeIdent(singleApp.args[0], "T");
3061 +
3062 +
    let recordExpr = try! parseExprStr("Pair⟨T⟩ { first: value }");
3063 +
    let case ast::NodeValue::RecordLit(recordLit) = recordExpr.value
3064 +
        else throw testing::TestError::Failed;
3065 +
    let recordType = recordLit.typeName else throw testing::TestError::Failed;
3066 +
    let case ast::NodeValue::GenericApply(recordApp) = recordType.value
3067 +
        else throw testing::TestError::Failed;
3068 +
    assert recordApp.args.len == 1;
3069 +
3070 +
    let indexedCall = try! parseExprStr("callbacks[*index](value)");
3071 +
    let case ast::NodeValue::Call(indexed) = indexedCall.value
3072 +
        else throw testing::TestError::Failed;
3073 +
    let case ast::NodeValue::Subscript { index, .. } = indexed.callee.value
3074 +
        else throw testing::TestError::Failed;
3075 +
    let case ast::NodeValue::Deref(indexTarget) = index.value
3076 +
        else throw testing::TestError::Failed;
3077 +
    try expectIdent(indexTarget, "index");
3078 +
3079 +
    let symbolic = try! parseExprStr("map⟨T, U⟩(value)");
3080 +
    let case ast::NodeValue::Call(symbolicCall) = symbolic.value
3081 +
        else throw testing::TestError::Failed;
3082 +
    let case ast::NodeValue::GenericApply(symbolicApp) = symbolicCall.callee.value
3083 +
        else throw testing::TestError::Failed;
3084 +
    assert symbolicApp.args.len == 2;
3085 +
3086 +
    let functionValue = try! parseExprStr("first⟨i32⟩");
3087 +
    let case ast::NodeValue::GenericApply(valueApp) = functionValue.value
3088 +
        else throw testing::TestError::Failed;
3089 +
    try expectIntType(valueApp.args[0], 4, ast::Signedness::Signed);
3090 +
3091 +
    let subscript = try! parseExprStr("values[index]");
3092 +
    let case ast::NodeValue::Subscript { .. } = subscript.value
3093 +
        else throw testing::TestError::Failed;
3094 +
}
3095 +
3096 +
/// Instantiation roots retain every applied path in a grouped declaration.
3097 +
@test fn testParseInstantiateDeclaration() throws (testing::TestError) {
3098 +
    let node = try! parseStmtStr(
3099 +
        "instantiate collections::Pair⟨i32, bool⟩, Maybe⟨i32⟩;"
3100 +
    );
3101 +
    let case ast::NodeValue::Instantiate(applications) = node.value
3102 +
        else throw testing::TestError::Failed;
3103 +
    assert applications.len == 2;
3104 +
    let case ast::NodeValue::GenericApply(app) = applications[0].value
3105 +
        else throw testing::TestError::Failed;
3106 +
    let case ast::NodeValue::ScopeAccess(path) = app.target.value
3107 +
        else throw testing::TestError::Failed;
3108 +
    try expectIdent(path.parent, "collections");
3109 +
    try expectIdent(path.child, "Pair");
3110 +
    assert app.args.len == 2;
3111 +
    let case ast::NodeValue::GenericApply(second) = applications[1].value
3112 +
        else throw testing::TestError::Failed;
3113 +
    try expectIdent(second.target, "Maybe");
3114 +
    assert second.args.len == 1;
3115 +
}
3116 +
3117 +
/// Generic syntax reports focused malformed-list diagnostics.
3118 +
@test fn testParseGenericDiagnostics() throws (testing::TestError) {
3119 +
    try expectStmtParseError(
3120 +
        "record Empty⟨⟩ {}", "generic parameter list cannot be empty"
3121 +
    );
3122 +
    try expectStmtParseError(
3123 +
        "record Bad⟨constant constant N: u32⟩ {}", "duplicate `constant` in generic parameter"
3124 +
    );
3125 +
    try expectStmtParseError(
3126 +
        "instantiate Pair⟨i32,⟩;", "expected generic argument after `,`"
3127 +
    );
3128 +
    try expectStmtParseError(
3129 +
        "instantiate Pair;", "`instantiate` requires a generic application"
3130 +
    );
3131 +
}
lib/std/lang/resolver.rad +3257 -418
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;
58 +
59 +
/// Resolution state for a trait signature table.
60 +
export union TraitState {
61 +
    Queued,
62 +
    Resolving,
63 +
    Complete,
64 +
}
50 65
51 66
/// Trait definition stored in the resolver.
52 67
export record TraitType {
53 68
    /// Trait name.
54 69
    name: *[u8],
70 +
    /// Module-local identity used by semantic tables.
71 +
    moduleId: u16,
72 +
    nodeId: u32,
55 73
    /// Method signatures, including from supertraits.
56 74
    methods: *mut [TraitMethod],
57 75
    /// Supertraits that must also be implemented.
58 76
    supertraits: *mut [*TraitType],
77 +
    /// Rigid `Self` type used by static signatures.
78 +
    selfType: *GenericParamType,
79 +
    /// Whether signature resolution has started or completed.
80 +
    state: TraitState,
81 +
    /// Whether every vtable-exposed method is object-safe.
82 +
    objectSafe: bool,
59 83
}
60 84
61 85
/// A single method signature within a trait.
62 86
export record TraitMethod {
63 87
    /// Method name.
66 90
    fnType: *FnType,
67 91
    /// Whether the receiver is mutable.
68 92
    mutable: bool,
69 93
    /// Pointer-like class used by the receiver.
70 94
    receiverClass: types::PointerClass,
95 +
    /// Trait that originally declared this method.
96 +
    owner: *TraitType,
71 97
    /// V-table slot index.
72 98
    index: u32,
73 99
}
74 100
75 101
/// An entry in the trait instance registry.
76 102
export record InstanceEntry {
77 103
    /// Trait type descriptor.
78 104
    traitType: *TraitType,
79 105
    /// Concrete type that implements the trait.
80 106
    concreteType: Type,
81 -
    /// Name of the concrete type.
82 -
    concreteTypeName: *[u8],
83 107
    /// Module where this instance was declared.
84 108
    moduleId: u16,
85 109
    /// Method symbols for each trait method, in declaration order.
86 110
    methods: *mut [*mut Symbol],
87 111
}
88 112
89 113
/// An entry in the method registry.
90 114
export record MethodEntry {
91 115
    /// Concrete type that owns the method.
92 116
    concreteType: Type,
93 -
    /// Name of the concrete type.
94 -
    concreteTypeName: *[u8],
95 117
    /// Method name.
96 118
    name: *[u8],
97 119
    /// Function type excluding the receiver.
98 120
    fnType: *FnType,
99 121
    /// Whether the receiver is mutable.
158 180
export record ArrayType {
159 181
    item: *Type,
160 182
    length: u32,
161 183
}
162 184
185 +
/// Anonymous record whose field layout depends on rigid parameters.
186 +
export record GenericRecordType {
187 +
    fields: *[RecordField],
188 +
    labeled: bool,
189 +
}
190 +
163 191
/// Record nominal type.
164 192
export record RecordType {
165 193
    fields: *[RecordField],
166 194
    labeled: bool,
167 195
    /// Cached layout.
262 290
        bindingName: ?*[u8],
263 291
        indexName: ?*[u8]
264 292
    },
265 293
}
266 294
295 +
/// A rigid type parameter belonging to one generic declaration.
296 +
export record GenericParamType {
297 +
    /// Declaration that owns the parameter.
298 +
    owner: *ast::Node,
299 +
    /// Parameter declaration node.
300 +
    node: *ast::Node,
301 +
    /// Parameter name.
302 +
    name: *[u8],
303 +
    /// Position in the declaration's ordered parameter list.
304 +
    index: u32,
305 +
    /// Resolved trait bounds.
306 +
    bounds: *[*TraitType],
307 +
    /// Shared usage flag, mutable through symbol references.
308 +
    used: *mut bool,
309 +
    /// Declared integer type for a constant parameter, or `nil` for a type parameter.
310 +
    constType: ?*Type,
311 +
}
312 +
267 313
/// Resolved function signature details.
268 314
export record FnType {
269 315
    paramTypes: *[*Type],
270 316
    returnType: *Type,
271 317
    throwList: *[*Type],
272 318
    /// Whether calling this function requires an unsafe context.
273 319
    isUnsafe: bool,
274 320
    localCount: u32,
275 321
}
276 322
323 +
/// Resolved, declaration-scoped generic metadata.
324 +
export record GenericTemplate {
325 +
    /// Declaration that owns this template.
326 +
    decl: *ast::Node,
327 +
    /// Ordered rigid type parameters.
328 +
    params: *[*GenericParamType],
329 +
    /// Symbolic function signature, for function templates.
330 +
    signature: ?*FnType,
331 +
    /// Symbolic field or variant types, in declaration order.
332 +
    members: *[*Type],
333 +
    /// Whether the declaration explicitly carries the `Linear` marker.
334 +
    declaredLinear: bool,
335 +
    moduleId: ?u16,
336 +
    /// Whether a generic function body has already been checked.
337 +
    bodyResolved: bool,
338 +
    /// Number of body-analysis entries, retained to enforce check-once behavior.
339 +
    bodyChecks: u8,
340 +
}
341 +
342 +
/// Canonical concrete specialization of a generic record or union.
343 +
export record GenericDataSpecialization {
344 +
    /// Template symbol whose declaration is specialized.
345 +
    template: *mut Symbol,
346 +
    /// Ordered, interned concrete type arguments.
347 +
    args: *[*Type],
348 +
    /// Ordinary nominal type produced for this application.
349 +
    nominal: *mut NominalType,
350 +
    /// Whether an explicit `instantiate` declaration requested this type.
351 +
    rooted: *mut bool,
352 +
    /// First concrete application site, used for root diagnostics.
353 +
    site: *ast::Node,
354 +
}
355 +
356 +
/// Worklist state for a concrete generic function body.
357 +
export union GenericFnState {
358 +
    Queued,
359 +
    Lowering,
360 +
    Complete,
361 +
}
362 +
363 +
/// Canonical concrete specialization of a generic free function.
364 +
export record GenericFnSpecialization {
365 +
    /// Template symbol whose body is lowered.
366 +
    template: *mut Symbol,
367 +
    /// Ordered, interned concrete type arguments.
368 +
    args: *[*Type],
369 +
    /// Substituted concrete function signature.
370 +
    fnType: *FnType,
371 +
    /// First explicit instantiation site.
372 +
    site: *ast::Node,
373 +
    /// Dependency-closure state.
374 +
    state: GenericFnState,
375 +
    /// Distance from an explicit root, used to bound expanding recursion.
376 +
    depth: u16,
377 +
}
378 +
379 +
/// Linked cache entry for generic function specializations.
380 +
export record GenericFnSpecializationNode {
381 +
    specialization: GenericFnSpecialization,
382 +
    next: ?*mut GenericFnSpecializationNode,
383 +
}
384 +
385 +
/// A generic call retained in a checked symbolic function body.
386 +
export record GenericFnDependency {
387 +
    caller: ?*mut Symbol,
388 +
    callee: *mut Symbol,
389 +
    args: *[*Type],
390 +
    site: *ast::Node,
391 +
    next: ?*GenericFnDependency,
392 +
}
393 +
394 +
/// Concrete call selected for one symbolic edge in one caller specialization.
395 +
export record GenericFnDependencyResolution {
396 +
    dependency: *GenericFnDependency,
397 +
    caller: *GenericFnSpecialization,
398 +
    callee: *GenericFnSpecialization,
399 +
    next: ?*GenericFnDependencyResolution,
400 +
}
401 +
402 +
/// Linked cache entry for generic data specializations.
403 +
record GenericDataSpecializationNode {
404 +
    specialization: GenericDataSpecialization,
405 +
    next: ?*GenericDataSpecializationNode,
406 +
}
407 +
408 +
/// Sparse generic metadata entry, allocated only for template symbols.
409 +
record GenericTemplateNode {
410 +
    symbol: *mut Symbol,
411 +
    template: GenericTemplate,
412 +
    next: ?*mut GenericTemplateNode,
413 +
}
414 +
415 +
/// Ordered replacement types for rigid parameters.
416 +
export record Substitution {
417 +
    params: *[*GenericParamType],
418 +
    args: *[*Type],
419 +
}
420 +
421 +
/// Symbolic application of a generic data template inside another template.
422 +
export record GenericDataApplyType {
423 +
    template: *mut Symbol,
424 +
    args: *[*Type],
425 +
    site: *ast::Node,
426 +
}
427 +
428 +
/// Pointer-like address payload.
429 +
export record PointerType {
430 +
    /// Ownership and safety class.
431 +
    class: types::PointerClass,
432 +
    /// Pointer target type.
433 +
    target: *Type,
434 +
    /// Whether the pointer is mutable.
435 +
    mutable: bool,
436 +
}
437 +
438 +
/// Pointer-like slice payload.
439 +
export record SliceType {
440 +
    /// Ownership and safety class.
441 +
    class: types::PointerClass,
442 +
    /// Slice element type.
443 +
    item: *Type,
444 +
    /// Whether the slice is mutable.
445 +
    mutable: bool,
446 +
}
447 +
448 +
/// Erased pointer-like type payload.
449 +
export record TraitObjectType {
450 +
    /// Ownership and safety class.
451 +
    class: types::PointerClass,
452 +
    /// Trait definition.
453 +
    traitInfo: *TraitType,
454 +
    /// Whether the pointer is mutable.
455 +
    mutable: bool,
456 +
}
457 +
277 458
/// Describes a type computed during semantic analysis.
278 459
export union Type {
279 460
    /// A type that couldn't be decided.
280 461
    Unknown,
281 462
    /// Types only used during inference.
287 468
    /// Range types, eg. `start..end`.
288 469
    Range {
289 470
        start: ?*Type,
290 471
        end: ?*Type,
291 472
    },
292 -
    /// Owning pointer-like address.
293 -
    Pointer {
294 -
        class: types::PointerClass,
295 -
        target: *Type,
296 -
        mutable: bool,
297 -
    },
298 -
    /// Owning slice.
299 -
    Slice {
300 -
        class: types::PointerClass,
301 -
        item: *Type,
302 -
        mutable: bool,
303 -
    },
473 +
    /// Pointer-like address.
474 +
    Pointer(PointerType),
475 +
    /// Pointer-like slice.
476 +
    Slice(SliceType),
304 477
    /// Eg. `[i32; 32]`.
305 478
    Array(ArrayType),
479 +
    /// Array type whose length depends on a rigid constant parameter.
480 +
    GenericArray {
481 +
        item: *Type,
482 +
        length: *ast::Node,
483 +
    },
484 +
    /// Rigid integer constant parameter within a generic declaration.
485 +
    ConstParameter(*GenericParamType),
486 +
    /// Canonical typed integer generic argument.
487 +
    ConstArgument {
488 +
        type: *Type,
489 +
        value: ConstInt,
490 +
    },
491 +
    /// Symbolic integer expression awaiting constant-parameter substitution.
492 +
    GenericConstExpr {
493 +
        type: *Type,
494 +
        expr: *ast::Node,
495 +
    },
306 496
    /// Eg. `?T`.
307 497
    Optional(*Type),
308 498
    /// Eg. `fn id(i32) -> i32`.
309 499
    Fn(*FnType),
310 500
    /// Named, ie. user-defined types, includes union variants.
311 501
    Nominal(*NominalType),
312 -
    /// Owning trait object. An erased type with v-table.
313 -
    TraitObject {
314 -
        /// Ownership and safety class.
315 -
        class: types::PointerClass,
316 -
        /// Trait definition.
317 -
        traitInfo: *TraitType,
318 -
        /// Whether the pointer is mutable.
319 -
        mutable: bool,
320 -
    },
502 +
    /// Rigid type parameter within a generic declaration.
503 +
    Parameter(*GenericParamType),
504 +
    /// Anonymous record awaiting substitution before layout.
505 +
    GenericRecord(*GenericRecordType),
506 +
    /// Generic data application awaiting substitution of its arguments.
507 +
    GenericDataApply(*GenericDataApplyType),
508 +
    /// An erased pointer-like type with a v-table.
509 +
    TraitObject(TraitObjectType),
321 510
}
322 511
323 512
/// Structured diagnostic payload for type mismatches.
324 513
export record TypeMismatch {
325 514
    expected: Type,
377 566
        /// Module scope.
378 567
        scope: *mut Scope,
379 568
    },
380 569
    /// Payload describing type symbols with their resolved type.
381 570
    Type(*mut NominalType),
571 +
    /// Rigid generic type parameter.
572 +
    TypeParameter(*GenericParamType),
573 +
    /// Rigid generic integer constant parameter.
574 +
    ConstParameter(*GenericParamType),
382 575
    /// Trait symbol.
383 576
    Trait(*mut TraitType),
384 577
}
385 578
386 579
/// Resolved symbol allocated during semantic analysis.
575 768
    ReceiverMutabilityMismatch,
576 769
    /// Duplicate instance declaration for the same (trait, type) pair.
577 770
    DuplicateInstance,
578 771
    /// Instance declaration is missing a required trait method.
579 772
    MissingTraitMethod(*[u8]),
773 +
    /// Subtrait instance attempts to override an inherited method.
774 +
    InheritedTraitMethod(*[u8]),
580 775
    /// Trait name used as a value expression.
581 776
    UnexpectedTraitName,
582 777
    /// Trait method receiver does not point to the declaring trait.
583 778
    TraitReceiverMismatch,
779 +
    /// A trait mentioning `Self` outside its receiver cannot form an object.
780 +
    TraitNotObjectSafe,
781 +
    /// Supertrait declarations form a cycle.
782 +
    TraitInheritanceCycle,
783 +
    /// An instance target is not a supported concrete type.
784 +
    InvalidInstanceTarget,
584 785
    /// Trait declaration and instance disagree about unsafe call requirements.
585 786
    TraitMethodSafetyMismatch,
586 787
    /// Function declaration has too many parameters.
587 788
    FnParamOverflow(CountMismatch),
588 789
    /// Function declaration has too many throws.
615 816
    BorrowConflict(*[u8]),
616 817
    /// Unsafe pointer operation outside an `unsafe` declaration.
617 818
    UnsafeOperation,
618 819
    /// Safe code cannot call an `unsafe` function.
619 820
    UnsafeCall,
821 +
    /// A syntax node is not valid in a generic context.
822 +
    GenericUnsupported,
823 +
    /// A generic bound did not name a trait.
824 +
    GenericBoundNotTrait,
825 +
    /// A constant parameter type is not a concrete integer type.
826 +
    GenericConstUnsupported,
827 +
    /// An attribute cannot be applied to a generic function.
828 +
    GenericFnAttribute,
829 +
    /// Generic function declarations must be at module scope.
830 +
    GenericFnNested,
831 +
    /// A type parameter does not affect its function.
832 +
    GenericFnUnusedParameter(*[u8]),
833 +
    /// More than one bound exposes the selected method name.
834 +
    GenericBoundAmbiguous(*[u8]),
835 +
    /// A rigid parameter was used where a concrete layout is required.
836 +
    GenericLayoutRequired,
837 +
    /// A concrete generic specialization has infinitely recursive layout.
838 +
    GenericRecursiveLayout,
839 +
    /// A function specialization targeted a non-function declaration.
840 +
    GenericFunctionExpected,
841 +
    /// A concrete type argument does not satisfy a declared trait bound.
842 +
    GenericBoundUnsatisfied(*[u8]),
843 +
    /// A generic function application has no explicit instantiation root.
844 +
    GenericFunctionInstantiationRequired,
845 +
    /// A generic call graph expands beyond the specialization bound.
846 +
    GenericSpecializationChain,
847 +
    /// Generic argument inference did not determine every parameter.
848 +
    GenericInferenceIncomplete,
849 +
    /// Generic argument inference found incompatible evidence.
850 +
    GenericInferenceConflict,
851 +
    /// A generic declaration was named without required arguments.
852 +
    GenericArgumentsRequired,
853 +
    /// A concrete application is not covered by an explicit instantiation root.
854 +
    GenericInstantiationRequired,
620 855
    /// Internal error.
621 856
    Internal,
857 +
    /// A generic application supplied the wrong number of arguments.
858 +
    GenericArgumentCount(CountMismatch),
859 +
    /// A data specialization targeted a non-data generic declaration.
860 +
    GenericDataExpected,
861 +
    /// A data specialization argument still contains a rigid parameter.
862 +
    GenericConcreteArgumentsRequired,
863 +
    /// A declaration exceeds the generic parameter limit.
864 +
    GenericParameterLimit,
865 +
    /// A package exceeds the explicit generic root limit.
866 +
    GenericRootLimit,
867 +
    /// A package exceeds the canonical specialization limit.
868 +
    GenericSpecializationLimit,
622 869
}
623 870
624 871
/// Diagnostics returned by the analyzer.
625 872
export record Diagnostics {
626 873
    errors: *mut [Error],
669 916
        /// Trait definition.
670 917
        traitInfo: *TraitType,
671 918
        /// Method index in the v-table.
672 919
        methodIndex: u32,
673 920
    },
921 +
    /// Static method call through a bounded generic parameter.
922 +
    GenericBoundMethodCall {
923 +
        param: *GenericParamType,
924 +
        traitInfo: *TraitType,
925 +
        methodIndex: u32,
926 +
        /// Whether the receiver is the first explicit call argument.
927 +
        explicitReceiver: bool,
928 +
    },
674 929
    /// Standalone method call metadata.
675 930
    MethodCall { method: *MethodEntry },
676 931
    /// Slice `.append(val, allocator)` method call.
677 932
    SliceAppend { elemType: *Type },
678 933
    /// Slice `.delete(index)` method call.
679 934
    SliceDelete { elemType: *Type },
935 +
    /// Concrete specialization selected by an explicit generic function value.
936 +
    GenericFnCall(*GenericFnSpecialization),
937 +
    /// Symbolic generic call resolved under the caller's specialization.
938 +
    GenericFnDependency(*GenericFnDependency),
680 939
}
681 940
682 941
/// Combined resolver metadata for a single AST node.
683 942
export record NodeData {
684 943
    /// Resolved type for this node.
768 1027
    by: MatchBy,
769 1028
}
770 1029
771 1030
/// Unwrap a pointer type for pattern matching.
772 1031
export fn unwrapMatchSubject(ty: Type) -> MatchSubject {
773 -
    if let case Type::Pointer { target, mutable, .. } = ty {
774 -
        let by = MatchBy::MutRef if mutable else MatchBy::Ref;
775 -
        return MatchSubject { effectiveTy: *target, by };
1032 +
    if let case Type::Pointer(pointer) = ty {
1033 +
        let by = MatchBy::MutRef if pointer.mutable else MatchBy::Ref;
1034 +
        return MatchSubject { effectiveTy: *pointer.target, by };
776 1035
    }
777 1036
    return MatchSubject { effectiveTy: ty, by: MatchBy::Value };
778 1037
}
779 1038
780 1039
/// Global resolver state.
787 1046
    loopStack: [LoopCtx; MAX_LOOP_DEPTH],
788 1047
    /// Current loop depth, indexes into loop stack.
789 1048
    loopDepth: u32,
790 1049
    /// Signature of the function currently being analyzed.
791 1050
    currentFn: ?*FnType,
1051 +
    /// Rigid `Self` type while resolving a trait signature.
1052 +
    currentTraitSelf: ?*GenericParamType,
792 1053
    /// Current module being analyzed.
793 1054
    currentMod: u16,
794 1055
    /// Nesting depth of unsafe modules and function bodies.
795 1056
    unsafeDepth: u32,
796 1057
    /// Whether this compilation contains explicitly linear declarations.
815 1076
    instancesLen: u32,
816 1077
    /// Standalone method registry.
817 1078
    methods: [MethodEntry; MAX_METHODS],
818 1079
    /// Number of registered standalone methods.
819 1080
    methodsLen: u32,
1081 +
    /// Sparse metadata for generic declarations.
1082 +
    genericTemplates: ?*mut GenericTemplateNode,
1083 +
    /// Canonical generic function specializations.
1084 +
    genericFnSpecializations: ?*mut GenericFnSpecializationNode,
1085 +
    /// Symbolic and deferred generic call edges.
1086 +
    genericFnDependencies: ?*GenericFnDependency,
1087 +
    /// Concrete resolutions of symbolic generic call edges.
1088 +
    genericFnDependencyResolutions: ?*GenericFnDependencyResolution,
1089 +
    /// Package-wide canonical generic data specializations.
1090 +
    genericDataSpecializations: ?*GenericDataSpecializationNode,
1091 +
    /// Number of explicit generic roots requested by the package.
1092 +
    genericRoots: u32,
1093 +
    /// Number of canonical data and function specializations.
1094 +
    genericSpecializationCount: u32,
820 1095
}
821 1096
822 1097
/// Internal error sentinel thrown when analysis cannot proceed.
823 1098
export union ResolveError {
824 1099
    Failure,
849 1124
    set self.types = node;
850 1125
851 1126
    return &node.ty;
852 1127
}
853 1128
1129 +
/// Return whether a type contains a rigid generic parameter.
1130 +
export fn containsGenericParameter(ty: Type) -> bool {
1131 +
    match ty {
1132 +
        case Type::Pointer(pointer) =>
1133 +
            return containsGenericParameter(*pointer.target),
1134 +
        case Type::Slice(slice) =>
1135 +
            return containsGenericParameter(*slice.item),
1136 +
        case Type::Parameter(_), Type::ConstParameter(_),
1137 +
             Type::GenericConstExpr { .. } => return true,
1138 +
        case Type::Array(array) => return containsGenericParameter(*array.item),
1139 +
        case Type::GenericArray { .. } => return true,
1140 +
        case Type::Optional(inner) => return containsGenericParameter(*inner),
1141 +
        // Symbolic anonymous records require materialization even when their
1142 +
        // own fields happen not to mention a rigid parameter.
1143 +
        case Type::GenericRecord(_) => return true,
1144 +
        case Type::GenericDataApply(_) => return true,
1145 +
        case Type::Fn(info) => {
1146 +
            for param in info.paramTypes {
1147 +
                if containsGenericParameter(*param) {
1148 +
                    return true;
1149 +
                }
1150 +
            }
1151 +
            if containsGenericParameter(*info.returnType) {
1152 +
                return true;
1153 +
            }
1154 +
            for thrown in info.throwList {
1155 +
                if containsGenericParameter(*thrown) {
1156 +
                    return true;
1157 +
                }
1158 +
            }
1159 +
            return false;
1160 +
        }
1161 +
        case Type::Range { start, end } => {
1162 +
            if let ty = start {
1163 +
                if containsGenericParameter(*ty) {
1164 +
                    return true;
1165 +
                }
1166 +
            }
1167 +
            if let ty = end {
1168 +
                if containsGenericParameter(*ty) {
1169 +
                    return true;
1170 +
                }
1171 +
            }
1172 +
            return false;
1173 +
        }
1174 +
        else => return false,
1175 +
    }
1176 +
}
1177 +
1178 +
/// Return whether a by-value type reaches an in-progress nominal placeholder.
1179 +
fn hasUnresolvedNominalLayout(ty: Type) -> bool {
1180 +
    match ty {
1181 +
        case Type::Pointer(_), Type::Slice(_) => return false,
1182 +
        case Type::Array(array) => return hasUnresolvedNominalLayout(*array.item),
1183 +
        case Type::Optional(inner) => return hasUnresolvedNominalLayout(*inner),
1184 +
        case Type::Nominal(info) => {
1185 +
            if let case NominalType::Placeholder(_) = *info {
1186 +
                return true;
1187 +
            }
1188 +
            return false;
1189 +
        }
1190 +
        case Type::GenericRecord(rec) => {
1191 +
            for field in rec.fields {
1192 +
                if hasUnresolvedNominalLayout(field.fieldType) {
1193 +
                    return true;
1194 +
                }
1195 +
            }
1196 +
            return false;
1197 +
        }
1198 +
        else => return false,
1199 +
    }
1200 +
}
1201 +
1202 +
/// Materialize concrete generic data applications within a type while
1203 +
/// preserving rigid parameters and constant-dependent constructors.
1204 +
fn materializeConcreteGenericData(
1205 +
    self: *mut Resolver,
1206 +
    ty: Type,
1207 +
    site: *ast::Node,
1208 +
) -> Type throws (ResolveError) {
1209 +
    match ty {
1210 +
        case Type::Pointer(pointer) => {
1211 +
            let inner = try materializeConcreteGenericData(self, *pointer.target, site);
1212 +
            return Type::Pointer(PointerType {
1213 +
                class: pointer.class,
1214 +
                target: allocType(self, inner),
1215 +
                mutable: pointer.mutable,
1216 +
            });
1217 +
        }
1218 +
        case Type::Slice(slice) => {
1219 +
            let inner = try materializeConcreteGenericData(self, *slice.item, site);
1220 +
            return Type::Slice(SliceType {
1221 +
                class: slice.class,
1222 +
                item: allocType(self, inner),
1223 +
                mutable: slice.mutable,
1224 +
            });
1225 +
        }
1226 +
        case Type::Array(array) => {
1227 +
            let item = try materializeConcreteGenericData(self, *array.item, site);
1228 +
            return Type::Array(ArrayType {
1229 +
                item: allocType(self, item),
1230 +
                length: array.length,
1231 +
            });
1232 +
        }
1233 +
        case Type::GenericArray { item, length } => {
1234 +
            let inner = try materializeConcreteGenericData(self, *item, site);
1235 +
            return Type::GenericArray { item: allocType(self, inner), length };
1236 +
        }
1237 +
        case Type::Optional(inner) => {
1238 +
            let value = try materializeConcreteGenericData(self, *inner, site);
1239 +
            return Type::Optional(allocType(self, value));
1240 +
        }
1241 +
        case Type::GenericDataApply(app) => {
1242 +
            let a = alloc::arenaAllocator(&mut self.arena);
1243 +
            let mut args: *mut [*Type] = &mut [];
1244 +
            let mut concrete = true;
1245 +
            for arg in app.args {
1246 +
                let value = try materializeConcreteGenericData(self, *arg, site);
1247 +
                set concrete = concrete and not containsGenericParameter(value);
1248 +
                args.append(allocType(self, value), a);
1249 +
            }
1250 +
            if concrete {
1251 +
                let nominal = try specializeGenericData(
1252 +
                    self, app.site, app.template, &args[..], false
1253 +
                );
1254 +
                return Type::Nominal(nominal);
1255 +
            }
1256 +
            let application = try! alloc::alloc(
1257 +
                &mut self.arena,
1258 +
                @sizeOf(GenericDataApplyType),
1259 +
                @alignOf(GenericDataApplyType),
1260 +
            ) as *mut GenericDataApplyType;
1261 +
            set *application = GenericDataApplyType {
1262 +
                template: app.template,
1263 +
                args: &args[..],
1264 +
                site: app.site,
1265 +
            };
1266 +
            return Type::GenericDataApply(application);
1267 +
        }
1268 +
        case Type::Fn(info) => {
1269 +
            let a = alloc::arenaAllocator(&mut self.arena);
1270 +
            let mut params: *mut [*Type] = &mut [];
1271 +
            let mut throwTypes: *mut [*Type] = &mut [];
1272 +
            for param in info.paramTypes {
1273 +
                let value = try materializeConcreteGenericData(self, *param, site);
1274 +
                params.append(allocType(self, value), a);
1275 +
            }
1276 +
            for thrown in info.throwList {
1277 +
                let value = try materializeConcreteGenericData(self, *thrown, site);
1278 +
                throwTypes.append(allocType(self, value), a);
1279 +
            }
1280 +
            let result = try materializeConcreteGenericData(
1281 +
                self, *info.returnType, site
1282 +
            );
1283 +
            return Type::Fn(allocFnType(self, FnType {
1284 +
                paramTypes: &params[..],
1285 +
                returnType: allocType(self, result),
1286 +
                throwList: &throwTypes[..],
1287 +
                isUnsafe: info.isUnsafe,
1288 +
                localCount: info.localCount,
1289 +
            }));
1290 +
        }
1291 +
        case Type::GenericRecord(rec) => {
1292 +
            let a = alloc::arenaAllocator(&mut self.arena);
1293 +
            let mut fields: *mut [RecordField] = &mut [];
1294 +
            let mut symbolic = false;
1295 +
            for field in rec.fields {
1296 +
                let fieldType = try materializeConcreteGenericData(
1297 +
                    self, field.fieldType, site
1298 +
                );
1299 +
                set symbolic = symbolic or containsGenericParameter(fieldType);
1300 +
                fields.append(RecordField {
1301 +
                    name: field.name,
1302 +
                    fieldType,
1303 +
                    offset: field.offset,
1304 +
                }, a);
1305 +
            }
1306 +
            let updatedRec = try! alloc::alloc(
1307 +
                &mut self.arena,
1308 +
                @sizeOf(GenericRecordType),
1309 +
                @alignOf(GenericRecordType),
1310 +
            ) as *mut GenericRecordType;
1311 +
            set *updatedRec = GenericRecordType {
1312 +
                fields: &fields[..],
1313 +
                labeled: rec.labeled,
1314 +
            };
1315 +
            let updated = Type::GenericRecord(updatedRec);
1316 +
            if symbolic {
1317 +
                return updated;
1318 +
            }
1319 +
            let empty = Substitution { params: &[], args: &[] };
1320 +
            return try substituteType(self, updated, &empty, site);
1321 +
        }
1322 +
        else => return ty,
1323 +
    }
1324 +
}
1325 +
1326 +
/// Look up the concrete replacement for a rigid parameter.
1327 +
export fn substitutionArg(sub: *Substitution, param: *GenericParamType) -> Type {
1328 +
    assert sub.params.len == sub.args.len, "substitution length mismatch";
1329 +
    for candidate, i in sub.params {
1330 +
        if candidate == param {
1331 +
            return *sub.args[i];
1332 +
        }
1333 +
    }
1334 +
    if param.constType <> nil {
1335 +
        return Type::ConstParameter(param);
1336 +
    }
1337 +
    return Type::Parameter(param);
1338 +
}
1339 +
1340 +
/// Recursively replace rigid parameters in a resolved type.
1341 +
export fn substituteType(
1342 +
    self: *mut Resolver,
1343 +
    ty: Type,
1344 +
    sub: *Substitution,
1345 +
    site: *ast::Node,
1346 +
) -> Type throws (ResolveError) {
1347 +
    if not containsGenericParameter(ty) {
1348 +
        return ty;
1349 +
    }
1350 +
    match ty {
1351 +
        case Type::Parameter(param) => return substitutionArg(sub, param),
1352 +
        case Type::ConstParameter(param) => return substitutionArg(sub, param),
1353 +
        case Type::GenericConstExpr { type, expr } => {
1354 +
            let value = constValueWithSubstitution(self, expr, sub)
1355 +
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
1356 +
            let case ConstValue::Int(int) = value
1357 +
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
1358 +
            if not validateConstIntRange(value, *type) {
1359 +
                throw emitError(self, expr, ErrorKind::NumericLiteralOverflow);
1360 +
            }
1361 +
            let case ConstValue::Int(canonical) = castConstInt(int, *type)
1362 +
                else throw emitError(self, expr, ErrorKind::Internal);
1363 +
            return Type::ConstArgument { type, value: canonical };
1364 +
        }
1365 +
        case Type::Pointer(pointer) => {
1366 +
            let inner = try substituteType(self, *pointer.target, sub, site);
1367 +
            return Type::Pointer(PointerType {
1368 +
                class: pointer.class,
1369 +
                target: allocType(self, inner),
1370 +
                mutable: pointer.mutable,
1371 +
            });
1372 +
        }
1373 +
        case Type::Slice(slice) => {
1374 +
            let inner = try substituteType(self, *slice.item, sub, site);
1375 +
            return Type::Slice(SliceType {
1376 +
                class: slice.class,
1377 +
                item: allocType(self, inner),
1378 +
                mutable: slice.mutable,
1379 +
            });
1380 +
        }
1381 +
        case Type::Array(array) => {
1382 +
            let item = try substituteType(self, *array.item, sub, site);
1383 +
            return Type::Array(ArrayType {
1384 +
                item: allocType(self, item),
1385 +
                length: array.length,
1386 +
            });
1387 +
        }
1388 +
        case Type::GenericArray { item, length } => {
1389 +
            let concreteItem = try substituteType(self, *item, sub, site);
1390 +
            let value = constValueWithSubstitution(self, length, sub)
1391 +
                else throw emitError(self, length, ErrorKind::ConstExprRequired);
1392 +
            if not validateConstIntRange(value, Type::U32) {
1393 +
                throw emitError(self, length, ErrorKind::NumericLiteralOverflow);
1394 +
            }
1395 +
            let case ConstValue::Int(int) = value
1396 +
                else throw emitError(self, length, ErrorKind::ConstExprRequired);
1397 +
            return Type::Array(ArrayType {
1398 +
                item: allocType(self, concreteItem),
1399 +
                length: int.magnitude as u32,
1400 +
            });
1401 +
        }
1402 +
        case Type::Optional(inner) => {
1403 +
            let value = try substituteType(self, *inner, sub, site);
1404 +
            return Type::Optional(allocType(self, value));
1405 +
        }
1406 +
        case Type::GenericDataApply(app) => {
1407 +
            let a = alloc::arenaAllocator(&mut self.arena);
1408 +
            let mut args: *mut [*Type] = &mut [];
1409 +
            let mut symbolic = false;
1410 +
            for arg in app.args {
1411 +
                let replacement = try substituteType(self, *arg, sub, site);
1412 +
                set symbolic = symbolic or containsGenericParameter(replacement);
1413 +
                args.append(allocType(self, replacement), a);
1414 +
            }
1415 +
            if symbolic {
1416 +
                let application = try! alloc::alloc(
1417 +
                    &mut self.arena,
1418 +
                    @sizeOf(GenericDataApplyType),
1419 +
                    @alignOf(GenericDataApplyType),
1420 +
                ) as *mut GenericDataApplyType;
1421 +
                set *application = GenericDataApplyType {
1422 +
                    template: app.template,
1423 +
                    args: &args[..],
1424 +
                    site: app.site,
1425 +
                };
1426 +
                return Type::GenericDataApply(application);
1427 +
            }
1428 +
            let nominal = try specializeGenericData(
1429 +
                self, app.site, app.template, &args[..], false
1430 +
            );
1431 +
            return Type::Nominal(nominal);
1432 +
        }
1433 +
        case Type::GenericRecord(rec) => {
1434 +
            let a = alloc::arenaAllocator(&mut self.arena);
1435 +
            let mut fields: *mut [RecordField] = &mut [];
1436 +
            let mut offset: u32 = 0;
1437 +
            let mut alignment: u32 = 1;
1438 +
            for field in rec.fields {
1439 +
                let fieldType = try substituteType(self, field.fieldType, sub, site);
1440 +
                if hasUnresolvedNominalLayout(fieldType) {
1441 +
                    throw emitError(self, site, ErrorKind::GenericRecursiveLayout);
1442 +
                }
1443 +
                try ensureStorableType(self, site, fieldType);
1444 +
                try ensureTypeResolved(self, fieldType, site);
1445 +
                let fieldLayout = getTypeLayout(fieldType);
1446 +
                set offset = mem::alignUp(offset, fieldLayout.alignment);
1447 +
                fields.append(RecordField {
1448 +
                    name: field.name,
1449 +
                    fieldType,
1450 +
                    offset: offset as i32,
1451 +
                }, a);
1452 +
                set offset += fieldLayout.size;
1453 +
                set alignment = max(alignment, fieldLayout.alignment);
1454 +
            }
1455 +
            let layout = Layout {
1456 +
                size: mem::alignUp(offset, alignment),
1457 +
                alignment,
1458 +
            };
1459 +
            return Type::Nominal(allocNominalType(self, NominalType::Record(RecordType {
1460 +
                fields: &fields[..],
1461 +
                labeled: rec.labeled,
1462 +
                layout,
1463 +
                declaredLinear: false,
1464 +
            })));
1465 +
        }
1466 +
        case Type::Fn(info) => {
1467 +
            let a = alloc::arenaAllocator(&mut self.arena);
1468 +
            let mut params: *mut [*Type] = &mut [];
1469 +
            let mut throwTypes: *mut [*Type] = &mut [];
1470 +
            for param in info.paramTypes {
1471 +
                let concrete = try substituteType(self, *param, sub, site);
1472 +
                params.append(allocType(self, concrete), a);
1473 +
            }
1474 +
            for thrown in info.throwList {
1475 +
                let concrete = try substituteType(self, *thrown, sub, site);
1476 +
                throwTypes.append(allocType(self, concrete), a);
1477 +
            }
1478 +
            let result = try substituteType(self, *info.returnType, sub, site);
1479 +
            return Type::Fn(allocFnType(self, FnType {
1480 +
                paramTypes: &params[..],
1481 +
                returnType: allocType(self, result),
1482 +
                throwList: &throwTypes[..],
1483 +
                isUnsafe: info.isUnsafe,
1484 +
                localCount: info.localCount,
1485 +
            }));
1486 +
        }
1487 +
        case Type::Range { start, end } => {
1488 +
            let mut newStart: ?*Type = nil;
1489 +
            let mut newEnd: ?*Type = nil;
1490 +
            if let value = start {
1491 +
                let concrete = try substituteType(self, *value, sub, site);
1492 +
                set newStart = allocType(self, concrete);
1493 +
            }
1494 +
            if let value = end {
1495 +
                let concrete = try substituteType(self, *value, sub, site);
1496 +
                set newEnd = allocType(self, concrete);
1497 +
            }
1498 +
            return Type::Range { start: newStart, end: newEnd };
1499 +
        }
1500 +
        else => return ty,
1501 +
    }
1502 +
}
1503 +
854 1504
/// Allocate a nominal type descriptor and return a pointer to it.
855 1505
fn allocNominalType(self: *mut Resolver, info: NominalType) -> *mut NominalType {
856 1506
    // Nb. We don't attempt to de-duplicate nominal type entries,
857 1507
    // since they don't carry node information and we create
858 1508
    // placeholder entries when binding symbols.
949 1599
        scope: storage.pkgScope,
950 1600
        pkgScope: storage.pkgScope,
951 1601
        loopStack: undefined,
952 1602
        loopDepth: 0,
953 1603
        currentFn: nil,
1604 +
        currentTraitSelf: nil,
954 1605
        currentMod: 0,
955 1606
        unsafeDepth: 0,
956 1607
        linearEnabled: false,
957 1608
        config,
958 1609
        arena,
964 1615
        moduleScopes,
965 1616
        instances: undefined,
966 1617
        instancesLen: 0,
967 1618
        methods: undefined,
968 1619
        methodsLen: 0,
1620 +
        genericTemplates: nil,
1621 +
        genericFnSpecializations: nil,
1622 +
        genericFnDependencies: nil,
1623 +
        genericFnDependencyResolutions: nil,
1624 +
        genericDataSpecializations: nil,
1625 +
        genericRoots: 0,
1626 +
        genericSpecializationCount: 0,
969 1627
    };
970 1628
}
971 1629
972 1630
/// Return `true` if there are no errors in the diagnostics.
973 1631
export fn success(diag: *Diagnostics) -> bool {
1212 1870
/// Associate trait method call metadata with a call node.
1213 1871
fn setTraitMethodCall(self: *mut Resolver, node: *ast::Node, traitInfo: *TraitType, methodIndex: u32) {
1214 1872
    set self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex };
1215 1873
}
1216 1874
1875 +
/// Associate static generic-bound dispatch metadata with a call node.
1876 +
fn setGenericBoundMethodCall(
1877 +
    self: *mut Resolver,
1878 +
    node: *ast::Node,
1879 +
    param: *GenericParamType,
1880 +
    traitInfo: *TraitType,
1881 +
    methodIndex: u32,
1882 +
    explicitReceiver: bool,
1883 +
) {
1884 +
    set self.nodeData.entries[node.id].extra = NodeExtra::GenericBoundMethodCall {
1885 +
        param, traitInfo, methodIndex, explicitReceiver,
1886 +
    };
1887 +
}
1888 +
1217 1889
/// Associate for-loop metadata with a for-loop node.
1218 1890
fn setForLoopInfo(self: *mut Resolver, node: *ast::Node, info: ForLoopInfo) {
1219 1891
    set self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info);
1220 1892
}
1221 1893
1394 2066
}
1395 2067
1396 2068
/// Get the layout of a type.
1397 2069
export fn getTypeLayout(ty: Type) -> Layout {
1398 2070
    match ty {
1399 -
        case Type::Pointer { .. } => return Layout { size: PTR_SIZE, alignment: PTR_SIZE },
1400 -
        case Type::Slice { .. }, Type::TraitObject { .. } =>
2071 +
        case Type::Pointer(_) => return Layout { size: PTR_SIZE, alignment: PTR_SIZE },
2072 +
        case Type::Slice(_), Type::TraitObject(_) =>
1401 2073
            return Layout { size: PTR_SIZE * 2, alignment: PTR_SIZE },
1402 2074
        case Type::Void, Type::Never => return Layout { size: 0, alignment: 0 },
1403 2075
        case Type::Bool, Type::U8, Type::I8 => return Layout { size: 1, alignment: 1 },
1404 2076
        case Type::U16, Type::I16 => return Layout { size: 2, alignment: 2 },
1405 2077
        case Type::U32, Type::I32 => return Layout { size: 4, alignment: 4 },
1489 2161
1490 2162
/// Check if a type can use null to represent `nil`.
1491 2163
/// Pointers and slices have a data pointer that is never null when valid.
1492 2164
export fn isNullableType(ty: Type) -> bool {
1493 2165
    match ty {
1494 -
        case Type::Pointer { .. }, Type::Slice { .. } => return true,
2166 +
        case Type::Pointer(_), Type::Slice(_) => return true,
1495 2167
        else => return false,
1496 2168
    }
1497 2169
}
1498 2170
1499 2171
/// Get the layout of a nominal type.
1551 2223
    };
1552 2224
    return UnionLayoutInfo { layout: unionLayout, valOffset: unionValOffset, isAllVoid };
1553 2225
}
1554 2226
1555 2227
/// Compute the discriminant tag for a variant, advancing the iota counter.
1556 -
/// If the variant has an explicit `= N` value, uses that; otherwise uses iota.
1557 -
fn variantTag(variantDecl: ast::UnionDeclVariant, iota: *mut u32) -> u32 {
2228 +
fn variantTag(
2229 +
    self: *mut Resolver,
2230 +
    variantDecl: ast::UnionDeclVariant,
2231 +
    iota: *mut u32,
2232 +
    sub: ?*Substitution,
2233 +
) -> u32 throws (ResolveError) {
1558 2234
    let mut tag: u32 = *iota;
1559 2235
    if let valueNode = variantDecl.value {
1560 -
        let case ast::NodeValue::Number(lit) = valueNode.value
1561 -
            else panic "variantTag: expected number literal";
1562 -
        set tag = lit.magnitude as u32;
2236 +
        let mut value: ?ConstValue = nil;
2237 +
        if let substitution = sub {
2238 +
            set value = constValueWithSubstitution(self, valueNode, substitution);
2239 +
        } else {
2240 +
            set value = constValueEntry(self, valueNode);
2241 +
        }
2242 +
        let resolved = value
2243 +
            else throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
2244 +
        if not validateConstIntRange(resolved, Type::U32) {
2245 +
            throw emitError(self, valueNode, ErrorKind::NumericLiteralOverflow);
2246 +
        }
2247 +
        let case ConstValue::Int(int) = resolved
2248 +
            else throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
2249 +
        set tag = int.magnitude as u32;
1563 2250
    }
1564 2251
    set *iota = tag + 1;
1565 2252
    return tag;
1566 2253
}
1567 2254
1572 2259
    return unionType.isAllVoid;
1573 2260
}
1574 2261
1575 2262
/// Check if a type should be treated as an address-like value.
1576 2263
fn isAddressType(ty: Type) -> bool {
1577 -
    if isNullableType(ty) {
1578 -
        return true;
1579 -
    }
1580 2264
    match ty {
1581 -
        case Type::Fn(_) => return true,
2265 +
        case Type::Pointer(_), Type::Slice(_), Type::Fn(_) => return true,
1582 2266
        else => return false,
1583 2267
    }
1584 2268
}
1585 2269
1586 2270
/// Return the representable range for an integer type.
1649 2333
1650 2334
/// Ensure all nested nominal types in a type are resolved.
1651 2335
fn ensureTypeResolved(self: *mut Resolver, ty: Type, site: *ast::Node) throws (ResolveError) {
1652 2336
    match ty {
1653 2337
        case Type::Nominal(info) => try ensureNominalResolved(self, info, site),
1654 -
        case Type::Slice { item, .. } => try ensureTypeResolved(self, *item, site),
1655 -
        case Type::Pointer { .. } => {}, // Pointers have fixed layout, don't recurse.
2338 +
        case Type::Slice(slice) => try ensureTypeResolved(self, *slice.item, site),
2339 +
        case Type::Pointer(_) => {}, // Pointers have fixed layout, don't recurse.
1656 2340
        case Type::Array(arr) => try ensureTypeResolved(self, *arr.item, site),
1657 2341
        case Type::Optional(inner) => try ensureTypeResolved(self, *inner, site),
1658 2342
        else => {},
1659 2343
    }
1660 2344
}
1735 2419
    // The "never" type can always be assigned, since the code path is never
1736 2420
    // executed.
1737 2421
    if from == Type::Never {
1738 2422
        return Coercion::Identity;
1739 2423
    }
1740 -
    if to == from {
2424 +
    if typesEqual(to, from) {
1741 2425
        return Coercion::Identity;
1742 2426
    }
1743 -
    if let case Type::Pointer { class: lhsClass, target: lhsTarget, mutable: lhsMutable } = to {
1744 -
        let case Type::Pointer { class: rhsClass, target: rhsTarget, mutable: rhsMutable } = from
1745 -
            else return nil;
1746 -
        if not pointerClassesAssignable(self, lhsClass, rhsClass) {
2427 +
    if let case Type::Pointer(lhs) = to {
2428 +
        let case Type::Pointer(rhs) = from else return nil;
2429 +
        if not pointerClassesAssignable(self, lhs.class, rhs.class) {
1747 2430
            return nil;
1748 2431
        }
1749 2432
        // Allow coercion from `*T` to `*opaque`, and mutable counterparts.
1750 -
        if *lhsTarget == Type::Opaque {
1751 -
            if lhsMutable and not rhsMutable {
2433 +
        if *lhs.target == Type::Opaque {
2434 +
            if lhs.mutable and not rhs.mutable {
1752 2435
                return nil;
1753 2436
            }
1754 2437
            return Coercion::Identity;
1755 2438
        }
1756 -
        if lhsMutable and not rhsMutable {
2439 +
        if lhs.mutable and not rhs.mutable {
1757 2440
            return nil;
1758 2441
        }
1759 -
        return isAssignable(self, *lhsTarget, *rhsTarget, rval);
2442 +
        return isAssignable(self, *lhs.target, *rhs.target, rval);
1760 2443
    }
1761 -
    if let case Type::TraitObject { class: lhsClass, traitInfo: lhsTraitInfo, mutable: lhsMutable } = to {
1762 -
        if let case Type::Pointer { class: rhsClass, target: rhsTarget, mutable: rhsMutable } = from {
1763 -
            if not pointerClassesAssignable(self, lhsClass, rhsClass)
1764 -
                or (lhsMutable and not rhsMutable)
2444 +
    if let case Type::TraitObject(lhs) = to {
2445 +
        if let case Type::Pointer(rhs) = from {
2446 +
            if not pointerClassesAssignable(self, lhs.class, rhs.class)
2447 +
                or (lhs.mutable and not rhs.mutable)
1765 2448
            {
1766 2449
                return nil;
1767 2450
            }
1768 -
            if let inst = findInstance(self, lhsTraitInfo, *rhsTarget) {
1769 -
                return Coercion::TraitObject { traitInfo: lhsTraitInfo, inst };
2451 +
            if let inst = findInstance(self, lhs.traitInfo, *rhs.target) {
2452 +
                return Coercion::TraitObject { traitInfo: lhs.traitInfo, inst };
1770 2453
            }
1771 2454
        }
1772 -
        if let case Type::TraitObject { class: rhsClass, traitInfo: rhsTraitInfo, mutable: rhsMutable } = from {
1773 -
            if not pointerClassesAssignable(self, lhsClass, rhsClass)
1774 -
                or lhsTraitInfo <> rhsTraitInfo
2455 +
        if let case Type::TraitObject(rhs) = from {
2456 +
            if not pointerClassesAssignable(self, lhs.class, rhs.class)
2457 +
                or lhs.traitInfo <> rhs.traitInfo
1775 2458
            {
1776 2459
                return nil;
1777 2460
            }
1778 -
            if lhsMutable and not rhsMutable {
2461 +
            if lhs.mutable and not rhs.mutable {
1779 2462
                return nil;
1780 2463
            }
1781 2464
            return Coercion::Identity;
1782 2465
        }
1783 2466
        return nil;
1784 2467
    }
1785 -
    if let case Type::Slice { class: lhsClass, item: lhsItem, mutable: lhsMutable } = to {
1786 -
        let case Type::Slice { class: rhsClass, item: rhsItem, mutable: rhsMutable } = from
1787 -
            else return nil;
1788 -
        if not pointerClassesAssignable(self, lhsClass, rhsClass)
1789 -
            or (lhsMutable and not rhsMutable)
2468 +
    if let case Type::Slice(lhs) = to {
2469 +
        let case Type::Slice(rhs) = from else return nil;
2470 +
        if not pointerClassesAssignable(self, lhs.class, rhs.class)
2471 +
            or (lhs.mutable and not rhs.mutable)
1790 2472
        {
1791 2473
            return nil;
1792 2474
        }
1793 2475
        // Allow coercion from `*[T]` to `*[opaque]`, and mutable counterparts.
1794 -
        if *lhsItem == Type::Opaque {
2476 +
        if *lhs.item == Type::Opaque {
1795 2477
            return Coercion::Identity;
1796 2478
        }
1797 -
        return isAssignable(self, *lhsItem, *rhsItem, rval);
2479 +
        return isAssignable(self, *lhs.item, *rhs.item, rval);
1798 2480
    }
1799 2481
    match to {
1800 2482
        case Type::Array(lhs) => {
1801 2483
            let case Type::Array(rhs) = from
1802 2484
                else return nil;
1916 2598
/// Check if two types are structurally equal.
1917 2599
export fn typesEqual(a: Type, b: Type) -> bool {
1918 2600
    if a == b {
1919 2601
        return true;
1920 2602
    }
1921 -
    if let case Type::Pointer { class: aClass, target: aTarget, mutable: aMutable } = a {
1922 -
        let case Type::Pointer { class: bClass, target: bTarget, mutable: bMutable } = b
1923 -
            else return false;
1924 -
        return aClass == bClass and aMutable == bMutable
1925 -
            and typesEqual(*aTarget, *bTarget);
2603 +
    if let case Type::Pointer(av) = a {
2604 +
        let case Type::Pointer(bv) = b else return false;
2605 +
        return av.class == bv.class and av.mutable == bv.mutable
2606 +
            and typesEqual(*av.target, *bv.target);
1926 2607
    }
1927 -
    if let case Type::Slice { class: aClass, item: aItem, mutable: aMutable } = a {
1928 -
        let case Type::Slice { class: bClass, item: bItem, mutable: bMutable } = b
1929 -
            else return false;
1930 -
        return aClass == bClass and aMutable == bMutable
1931 -
            and typesEqual(*aItem, *bItem);
2608 +
    if let case Type::Slice(av) = a {
2609 +
        let case Type::Slice(bv) = b else return false;
2610 +
        return av.class == bv.class and av.mutable == bv.mutable
2611 +
            and typesEqual(*av.item, *bv.item);
1932 2612
    }
1933 -
    if let case Type::TraitObject { class: aClass, traitInfo: aTraitInfo, mutable: aMutable } = a {
1934 -
        let case Type::TraitObject { class: bClass, traitInfo: bTraitInfo, mutable: bMutable } = b
1935 -
            else return false;
1936 -
        return aClass == bClass and aMutable == bMutable
1937 -
            and aTraitInfo == bTraitInfo;
2613 +
    if let case Type::TraitObject(av) = a {
2614 +
        let case Type::TraitObject(bv) = b else return false;
2615 +
        return av.class == bv.class and av.mutable == bv.mutable
2616 +
            and av.traitInfo == bv.traitInfo;
1938 2617
    }
1939 2618
    match a {
1940 2619
        case Type::Array(aa) => {
1941 2620
            let case Type::Array(ab) = b else return false;
1942 2621
            return aa.length == ab.length and typesEqual(*aa.item, *ab.item);
1947 2626
        }
1948 2627
        case Type::Fn(fa) => {
1949 2628
            let case Type::Fn(fb) = b else return false;
1950 2629
            return fnTypeEqual(fa, fb);
1951 2630
        }
2631 +
        case Type::GenericDataApply(aa) => {
2632 +
            let case Type::GenericDataApply(ab) = b else return false;
2633 +
            if aa.template <> ab.template or aa.args.len <> ab.args.len {
2634 +
                return false;
2635 +
            }
2636 +
            for i in 0..aa.args.len {
2637 +
                if not typesEqual(*aa.args[i], *ab.args[i]) {
2638 +
                    return false;
2639 +
                }
2640 +
            }
2641 +
            return true;
2642 +
        }
1952 2643
        else => return false,
1953 2644
    }
1954 2645
}
1955 2646
1956 2647
/// Return whether `ty` is a direct reference.
1957 2648
export fn isRefType(ty: Type) -> bool {
1958 2649
    match ty {
1959 -
        case Type::Pointer { class: types::PointerClass::Ref, .. },
1960 -
             Type::Slice { class: types::PointerClass::Ref, .. },
1961 -
             Type::TraitObject { class: types::PointerClass::Ref, .. } => return true,
2650 +
        case Type::Pointer(PointerType { class: types::PointerClass::Ref, .. }),
2651 +
             Type::Slice(SliceType { class: types::PointerClass::Ref, .. }),
2652 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Ref, .. }) => return true,
1962 2653
        else => return false,
1963 2654
    }
1964 2655
}
1965 2656
1966 2657
/// Return whether a type contains a reference.
1967 2658
fn containsRef(ty: Type) -> bool {
1968 2659
    if isRefType(ty) {
1969 2660
        return true;
1970 2661
    }
1971 -
    if let case Type::Pointer { target, .. } = ty {
1972 -
        return containsRef(*target);
2662 +
    if let case Type::Pointer(pointer) = ty {
2663 +
        return containsRef(*pointer.target);
1973 2664
    }
1974 -
    if let case Type::Slice { item, .. } = ty {
1975 -
        return containsRef(*item);
2665 +
    if let case Type::Slice(slice) = ty {
2666 +
        return containsRef(*slice.item);
1976 2667
    }
1977 2668
    match ty {
1978 2669
        case Type::Array(array) => return containsRef(*array.item),
1979 2670
        case Type::Optional(inner) => return containsRef(*inner),
2671 +
        case Type::GenericRecord(rec) => {
2672 +
            for field in rec.fields {
2673 +
                if containsRef(field.fieldType) {
2674 +
                    return true;
2675 +
                }
2676 +
            }
2677 +
            return false;
2678 +
        }
1980 2679
        // Nominal declarations validate their own fields and variants.
1981 2680
        // Treating them as leaves also terminates recursive pointer types.
1982 2681
        case Type::Nominal(_) => return false,
1983 2682
        else => return false,
1984 2683
    }
1985 2684
}
1986 2685
1987 2686
/// Return whether a type is exact-linear.
1988 2687
export fn isLinear(ty: Type) -> bool {
1989 2688
    match ty {
1990 -
        case Type::Pointer { class: types::PointerClass::Owned, .. },
1991 -
             Type::Slice { class: types::PointerClass::Owned, .. },
1992 -
             Type::TraitObject { class: types::PointerClass::Owned, .. } => return true,
1993 -
        case Type::Pointer { class: types::PointerClass::Ref, .. },
1994 -
             Type::Pointer { class: types::PointerClass::Unsafe, .. },
1995 -
             Type::Slice { class: types::PointerClass::Ref, .. },
1996 -
             Type::Slice { class: types::PointerClass::Unsafe, .. },
1997 -
             Type::TraitObject { class: types::PointerClass::Ref, .. },
1998 -
             Type::TraitObject { class: types::PointerClass::Unsafe, .. } => return false,
2689 +
        case Type::Pointer(PointerType { class: types::PointerClass::Owned, .. }),
2690 +
             Type::Slice(SliceType { class: types::PointerClass::Owned, .. }),
2691 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Owned, .. }) => return true,
2692 +
        case Type::Pointer(PointerType { class: types::PointerClass::Ref, .. }),
2693 +
             Type::Pointer(PointerType { class: types::PointerClass::Unsafe, .. }),
2694 +
             Type::Slice(SliceType { class: types::PointerClass::Ref, .. }),
2695 +
             Type::Slice(SliceType { class: types::PointerClass::Unsafe, .. }),
2696 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Ref, .. }),
2697 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Unsafe, .. }) => return false,
1999 2698
2000 2699
        case Type::Array(array) => return isLinear(*array.item),
2001 2700
        case Type::Optional(inner) => return isLinear(*inner),
2002 2701
        case Type::Nominal(NominalType::Record(recInfo)) => {
2003 2702
            if recInfo.declaredLinear {
2026 2725
}
2027 2726
2028 2727
/// Return whether `ty` is a direct unsafe pointer-like value.
2029 2728
fn isUnsafePointerType(ty: Type) -> bool {
2030 2729
    match ty {
2031 -
        case Type::Pointer { class: types::PointerClass::Unsafe, .. },
2032 -
             Type::Slice { class: types::PointerClass::Unsafe, .. },
2033 -
             Type::TraitObject { class: types::PointerClass::Unsafe, .. } => return true,
2730 +
        case Type::Pointer(PointerType { class: types::PointerClass::Unsafe, .. }),
2731 +
             Type::Slice(SliceType { class: types::PointerClass::Unsafe, .. }),
2732 +
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Unsafe, .. }) => return true,
2034 2733
        else => return false,
2035 2734
    }
2036 2735
}
2037 2736
2038 2737
/// Get the record info from a record type.
2041 2740
    return recInfo;
2042 2741
}
2043 2742
2044 2743
/// Auto-dereference a type: if it's a pointer, return the target type.
2045 2744
export fn autoDeref(ty: Type) -> Type {
2046 -
    if let case Type::Pointer { target, .. } = ty {
2047 -
        return *target;
2745 +
    if let case Type::Pointer(view) = ty {
2746 +
        return *view.target;
2048 2747
    }
2049 2748
    return ty;
2050 2749
}
2051 2750
2052 2751
/// Get field info for a record-like type (records, slices) by field index.
2053 2752
export fn getRecordField(ty: Type, index: u32) -> ?RecordField {
2054 -
    if let case Type::Slice { class, item, mutable } = ty {
2753 +
    if let case Type::Slice(slice) = ty {
2055 2754
        match index {
2056 2755
            case 0 => return RecordField {
2057 2756
                name: PTR_FIELD,
2058 -
                fieldType: Type::Pointer { class, target: item, mutable },
2757 +
                fieldType: Type::Pointer(PointerType {
2758 +
                    class: slice.class,
2759 +
                    target: slice.item,
2760 +
                    mutable: slice.mutable,
2761 +
                }),
2059 2762
                offset: 0,
2060 2763
            },
2061 2764
            case 1 => return RecordField {
2062 2765
                name: LEN_FIELD,
2063 2766
                fieldType: Type::U32,
2097 2800
        return isComparable(*l, right);
2098 2801
    } else if let case Type::Optional(_) = right {
2099 2802
        return isComparable(right, left); // Flip order.
2100 2803
    }
2101 2804
    // Pointer comparisons ignore mutability.
2102 -
    if let case Type::Pointer { target: lTarget, .. } = left {
2103 -
        if let case Type::Pointer { target: rTarget, .. } = right {
2104 -
            return typesEqual(*lTarget, *rTarget);
2805 +
    if let case Type::Pointer(l) = left {
2806 +
        if let case Type::Pointer(r) = right {
2807 +
            return typesEqual(*l.target, *r.target);
2105 2808
        }
2106 2809
    }
2107 2810
    // Numeric types.
2108 2811
    if isNumericType(left) and isNumericType(right) {
2109 2812
        return true;
2275 2978
    return false;
2276 2979
}
2277 2980
2278 2981
/// Predicate that matches type symbols.
2279 2982
fn isTypeSymbol(sym: *mut Symbol) -> bool {
2280 -
    if let case SymbolData::Type(_) = sym.data {
2281 -
        return true;
2983 +
    match sym.data {
2984 +
        case SymbolData::Type(_), SymbolData::TypeParameter(_) => return true,
2985 +
        else => return false,
2282 2986
    }
2283 -
    return false;
2284 2987
}
2285 2988
2286 2989
/// Find a symbol by name in a specific scope, filtered by a predicate.
2287 2990
fn findInScope(scope: *Scope, name: *[u8], predicate: fn(*mut Symbol) -> bool) -> ?*mut Symbol {
2288 2991
    for i in 0..scope.symbolsLen {
2448 3151
    self: *mut Resolver,
2449 3152
    node: *ast::Node,
2450 3153
    access: ast::Access,
2451 3154
    scope: *Scope
2452 3155
) -> *mut Symbol throws (ResolveError) {
2453 -
    // Handle `super` access by adjusting scope and node.
3156 +
    // A specialized union application introduces the variant namespace.
3157 +
    if let case ast::NodeValue::GenericApply(app) = access.parent.value {
3158 +
        let nominal = try resolveGenericDataApply(self, access.parent, app, false);
3159 +
        let case NominalType::Union(unionType) = *nominal
3160 +
            else throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3161 +
        let variantName = try nodeName(self, access.child);
3162 +
        let variant = try resolveUnionVariantAccess(
3163 +
            self, node, access, unionType, variantName
3164 +
        );
3165 +
        setNodeType(self, node, Type::Nominal(nominal));
3166 +
        return variant;
3167 +
    }
2454 3168
    let mut startScope = scope;
2455 3169
    let mut pathNode = node;
2456 3170
    if let superAccess = try checkSuperAccess(self, node) {
2457 3171
        set startScope = superAccess.scope;
2458 3172
        set pathNode = superAccess.child;
2575 3289
        &path[1..],
2576 3290
        childSym
2577 3291
    );
2578 3292
}
2579 3293
2580 -
/// Resolve a type name, which could be an identifier or scoped path.
2581 -
fn resolveTypeName(self: *mut Resolver, node: *ast::Node) -> *NominalType throws (ResolveError) {
3294 +
/// Return whether a declaration requires generic arguments.
3295 +
fn isGenericDeclaration(node: *ast::Node) -> bool {
2582 3296
    match node.value {
2583 -
        case ast::NodeValue::Ident(name) => {
2584 -
            let sym = findTypeSymbol(self.scope, name)
2585 -
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
2586 -
            let case SymbolData::Type(ty) = sym.data
2587 -
                else throw emitError(self, node, ErrorKind::Internal);
2588 -
2589 -
            setNodeSymbol(self, node, sym);
2590 -
2591 -
            return ty;
2592 -
        }
2593 -
        case ast::NodeValue::ScopeAccess(access) => {
2594 -
            let sym = try resolveAccess(self, node, access, self.scope);
2595 -
            let case SymbolData::Type(ty) = sym.data
2596 -
                else throw emitError(self, node, ErrorKind::Internal);
2597 -
2598 -
            setNodeSymbol(self, node, sym);
2599 -
2600 -
            return ty;
2601 -
        }
2602 -
        else => panic "resolveTypeName: unsupported node value",
3297 +
        case ast::NodeValue::RecordDecl(decl) => return decl.params.len > 0,
3298 +
        case ast::NodeValue::UnionDecl(decl) => return decl.params.len > 0,
3299 +
        case ast::NodeValue::FnDecl(decl) => return decl.params.len > 0,
3300 +
        else => return false,
2603 3301
    }
2604 3302
}
2605 3303
2606 -
/// Visit a top-level declaration in the declaration phase.
2607 -
/// This binds all names and analyzes signatures, types, and initializers.
2608 -
/// Function bodies are deferred to the definition phase.
2609 -
///
2610 -
/// Nb. User-defined types are already handled by this point.
2611 -
fn visitDecl(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
2612 -
    match node.value {
2613 -
        case ast::NodeValue::FnDecl(_),
2614 -
             ast::NodeValue::ConstDecl(_),
2615 -
             ast::NodeValue::Mod(_),
2616 -
             ast::NodeValue::Use(_) => {
2617 -
            // Handled in previous passes.
2618 -
        }
2619 -
        case ast::NodeValue::StaticDecl(_) => {
2620 -
            try infer(self, node);
2621 -
        }
2622 -
        case ast::NodeValue::InstanceDecl { traitName, targetType, methods } => {
2623 -
            try resolveInstanceDecl(self, node, traitName, targetType, methods);
2624 -
        }
2625 -
        case ast::NodeValue::MethodDecl { name, receiverName, receiverType, sig, body, attrs } => {
2626 -
            try resolveMethodDecl(self, node, name, receiverName, receiverType, sig, attrs);
2627 -
        }
2628 -
        else => {
2629 -
            // Ignore non-declaration nodes.
2630 -
        }
2631 -
    }
3304 +
/// Stack node used to stop cycles while walking ordinary nominal containers.
3305 +
record GenericRootVisit {
3306 +
    /// Nominal type visited at this stack entry.
3307 +
    nominal: *NominalType,
3308 +
    /// Previous stack entry.
3309 +
    parent: ?*GenericRootVisit,
2632 3310
}
2633 3311
2634 -
/// Require the current declaration to be unsafe.
2635 -
fn requireUnsafe(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
2636 -
    if self.unsafeDepth == 0 {
2637 -
        throw emitError(self, node, ErrorKind::UnsafeOperation);
3312 +
/// Return whether a nominal type is present in the visit stack.
3313 +
fn genericRootVisited(visit: ?*GenericRootVisit, nominal: *NominalType) -> bool {
3314 +
    let mut cursor = visit;
3315 +
    while let entry = cursor {
3316 +
        if entry.nominal == nominal {
3317 +
            return true;
3318 +
        }
3319 +
        set cursor = entry.parent;
2638 3320
    }
3321 +
    return false;
2639 3322
}
2640 3323
2641 -
/// Reject calls from safe code through unsafe function types.
3324 +
/// Mark generic specializations reached through one concrete type.
3325 +
fn markGenericDataTypeRootedInner(
3326 +
    self: *mut Resolver,
3327 +
    ty: Type,
3328 +
    visited: ?*GenericRootVisit,
3329 +
) -> bool {
3330 +
    match ty {
3331 +
        case Type::Pointer(pointer) =>
3332 +
            return markGenericDataTypeRootedInner(self, *pointer.target, visited),
3333 +
        case Type::Slice(slice) =>
3334 +
            return markGenericDataTypeRootedInner(self, *slice.item, visited),
3335 +
        case Type::Array(array) =>
3336 +
            return markGenericDataTypeRootedInner(self, *array.item, visited),
3337 +
        case Type::Optional(inner) =>
3338 +
            return markGenericDataTypeRootedInner(self, *inner, visited),
3339 +
        case Type::Fn(info) => {
3340 +
            let mut changed = markGenericDataTypeRootedInner(
3341 +
                self, *info.returnType, visited
3342 +
            );
3343 +
            for param in info.paramTypes {
3344 +
                set changed = markGenericDataTypeRootedInner(
3345 +
                    self, *param, visited
3346 +
                ) or changed;
3347 +
            }
3348 +
            for thrown in info.throwList {
3349 +
                set changed = markGenericDataTypeRootedInner(
3350 +
                    self, *thrown, visited
3351 +
                ) or changed;
3352 +
            }
3353 +
            return changed;
3354 +
        }
3355 +
        case Type::Nominal(nominal) => {
3356 +
            let mut cursor = self.genericDataSpecializations;
3357 +
            while let node = cursor {
3358 +
                let specialization = &node.specialization;
3359 +
                if specialization.nominal == nominal {
3360 +
                    if not *specialization.rooted {
3361 +
                        set *specialization.rooted = true;
3362 +
                        return true;
3363 +
                    }
3364 +
                    return false;
3365 +
                }
3366 +
                set cursor = node.next;
3367 +
            }
3368 +
            if genericRootVisited(visited, nominal) {
3369 +
                return false;
3370 +
            }
3371 +
            let visit = GenericRootVisit { nominal, parent: visited };
3372 +
            let mut changed = false;
3373 +
            match *nominal {
3374 +
                case NominalType::Record(recordType) => {
3375 +
                    for field in recordType.fields {
3376 +
                        set changed = markGenericDataTypeRootedInner(
3377 +
                            self, field.fieldType, &visit
3378 +
                        ) or changed;
3379 +
                    }
3380 +
                }
3381 +
                case NominalType::Union(unionType) => {
3382 +
                    for variant in unionType.variants {
3383 +
                        set changed = markGenericDataTypeRootedInner(
3384 +
                            self, variant.valueType, &visit
3385 +
                        ) or changed;
3386 +
                    }
3387 +
                }
3388 +
                case NominalType::Placeholder(_) => {}
3389 +
            }
3390 +
            return changed;
3391 +
        }
3392 +
        else => return false,
3393 +
    }
3394 +
}
3395 +
3396 +
/// Mark generic data specializations reachable from a concrete type.
3397 +
fn markGenericDataTypeRooted(self: *mut Resolver, ty: Type) -> bool {
3398 +
    return markGenericDataTypeRootedInner(self, ty, nil);
3399 +
}
3400 +
3401 +
/// Propagate explicit roots through arguments and specialized data members.
3402 +
fn validateGenericDataRoots(self: *mut Resolver) throws (ResolveError) {
3403 +
    loop {
3404 +
        let mut changed = false;
3405 +
        let mut cursor = self.genericDataSpecializations;
3406 +
        while let node = cursor {
3407 +
            let specialization = &node.specialization;
3408 +
            if *specialization.rooted {
3409 +
                for arg in specialization.args {
3410 +
                    set changed = markGenericDataTypeRooted(self, *arg) or changed;
3411 +
                }
3412 +
                match *specialization.nominal {
3413 +
                    case NominalType::Record(recordType) => {
3414 +
                        for field in recordType.fields {
3415 +
                            set changed = markGenericDataTypeRooted(
3416 +
                                self, field.fieldType
3417 +
                            ) or changed;
3418 +
                        }
3419 +
                    }
3420 +
                    case NominalType::Union(unionType) => {
3421 +
                        for variant in unionType.variants {
3422 +
                            set changed = markGenericDataTypeRooted(
3423 +
                                self, variant.valueType
3424 +
                            ) or changed;
3425 +
                        }
3426 +
                    }
3427 +
                    case NominalType::Placeholder(_) => {}
3428 +
                }
3429 +
            }
3430 +
            set cursor = node.next;
3431 +
        }
3432 +
        if not changed {
3433 +
            break;
3434 +
        }
3435 +
    }
3436 +
    let mut cursor = self.genericDataSpecializations;
3437 +
    while let node = cursor {
3438 +
        let specialization = &node.specialization;
3439 +
        if not *specialization.rooted {
3440 +
            throw emitError(
3441 +
                self, specialization.site, ErrorKind::GenericInstantiationRequired
3442 +
            );
3443 +
        }
3444 +
        set cursor = node.next;
3445 +
    }
3446 +
}
3447 +
3448 +
/// Look up a cached specialization by template and ordered arguments.
3449 +
export fn findGenericDataSpecialization(
3450 +
    self: *Resolver,
3451 +
    template: *Symbol,
3452 +
    args: *[*Type],
3453 +
) -> ?*GenericDataSpecialization {
3454 +
    let mut cursor = self.genericDataSpecializations;
3455 +
    while let node = cursor {
3456 +
        let entry = &node.specialization;
3457 +
        if entry.template == template and entry.args.len == args.len {
3458 +
            let mut equal = true;
3459 +
            for arg, i in args {
3460 +
                if not typesEqual(*entry.args[i], *arg) {
3461 +
                    set equal = false;
3462 +
                    break;
3463 +
                }
3464 +
            }
3465 +
            if equal {
3466 +
                return entry;
3467 +
            }
3468 +
        }
3469 +
        set cursor = node.next;
3470 +
    }
3471 +
    return nil;
3472 +
}
3473 +
3474 +
/// Look up a generic data specialization by its concrete nominal identity.
3475 +
export fn genericDataSpecializationForNominal(
3476 +
    self: *Resolver,
3477 +
    nominal: *NominalType,
3478 +
) -> ?*GenericDataSpecialization {
3479 +
    let mut cursor = self.genericDataSpecializations;
3480 +
    while let node = cursor {
3481 +
        if node.specialization.nominal == nominal {
3482 +
            return &node.specialization;
3483 +
        }
3484 +
        set cursor = node.next;
3485 +
    }
3486 +
    return nil;
3487 +
}
3488 +
3489 +
/// Find the declaration symbol that owns an ordinary nominal type.
3490 +
export fn symbolForNominal(
3491 +
    self: *Resolver,
3492 +
    nominal: *NominalType,
3493 +
) -> ?*Symbol {
3494 +
    for data in self.nodeData.entries {
3495 +
        if let sym = data.sym {
3496 +
            if let case SymbolData::Type(candidate) = sym.data; candidate == nominal {
3497 +
                return sym;
3498 +
            }
3499 +
        }
3500 +
    }
3501 +
    return nil;
3502 +
}
3503 +
3504 +
/// Resolve generic metadata lazily so applications are source-order independent.
3505 +
fn ensureGenericDataTemplate(self: *mut Resolver, sym: *mut Symbol)
3506 +
    throws (ResolveError)
3507 +
{
3508 +
    if genericTemplateFor(self, sym) <> nil {
3509 +
        return;
3510 +
    }
3511 +
    let prevScope = self.scope;
3512 +
    let prevMod = self.currentMod;
3513 +
    if let mid = moduleIdForSymbol(self, sym) {
3514 +
        if let moduleScope = self.moduleScopes[mid as u32] {
3515 +
            set self.scope = moduleScope;
3516 +
            set self.currentMod = mid;
3517 +
        }
3518 +
    }
3519 +
    match sym.node.value {
3520 +
        case ast::NodeValue::RecordDecl(decl) => {
3521 +
            try resolveGenericDataTemplate(
3522 +
                self, sym.node, decl.params, decl.fields, decl.derives, true
3523 +
            ) catch e {
3524 +
                set self.scope = prevScope;
3525 +
                set self.currentMod = prevMod;
3526 +
                throw e;
3527 +
            };
3528 +
        }
3529 +
        case ast::NodeValue::UnionDecl(decl) => {
3530 +
            try resolveGenericDataTemplate(
3531 +
                self, sym.node, decl.params, decl.variants, decl.derives, false
3532 +
            ) catch e {
3533 +
                set self.scope = prevScope;
3534 +
                set self.currentMod = prevMod;
3535 +
                throw e;
3536 +
            };
3537 +
        }
3538 +
        else => {
3539 +
            set self.scope = prevScope;
3540 +
            set self.currentMod = prevMod;
3541 +
            throw emitError(self, sym.node, ErrorKind::GenericDataExpected);
3542 +
        }
3543 +
    }
3544 +
    set self.scope = prevScope;
3545 +
    set self.currentMod = prevMod;
3546 +
}
3547 +
3548 +
/// Look up a possible inferred generic call target without emitting diagnostics.
3549 +
fn findGenericCandidateSymbol(
3550 +
    self: *Resolver,
3551 +
    node: *ast::Node,
3552 +
) -> ?*mut Symbol {
3553 +
    if let sym = symbolFor(self, node) {
3554 +
        return sym;
3555 +
    }
3556 +
    match node.value {
3557 +
        case ast::NodeValue::Ident(name) =>
3558 +
            return findAnySymbol(self.scope, name),
3559 +
        case ast::NodeValue::ScopeAccess(access) => {
3560 +
            let case ast::NodeValue::Ident(childName) = access.child.value
3561 +
                else return nil;
3562 +
            if let case ast::NodeValue::Super = access.parent.value {
3563 +
                let current = module::get(self.moduleGraph, self.currentMod) else return nil;
3564 +
                let parentId = current.parent else return nil;
3565 +
                let parentScope = self.moduleScopes[parentId as u32] else return nil;
3566 +
                return findSymbolInScope(parentScope, childName);
3567 +
            }
3568 +
            let sym = findGenericCandidateSymbol(self, access.parent) else return nil;
3569 +
            let case SymbolData::Module { scope, .. } = sym.data else return nil;
3570 +
            return findSymbolInScope(scope, childName);
3571 +
        }
3572 +
        else => return nil,
3573 +
    }
3574 +
}
3575 +
3576 +
/// Resolve a generic application's declaration symbol without requiring arguments.
3577 +
fn resolveGenericTarget(
3578 +
    self: *mut Resolver,
3579 +
    node: *ast::Node,
3580 +
) -> *mut Symbol throws (ResolveError) {
3581 +
    if let existing = symbolFor(self, node) {
3582 +
        return existing;
3583 +
    }
3584 +
    let mut sym: *mut Symbol = undefined;
3585 +
    match node.value {
3586 +
        case ast::NodeValue::Ident(name) => {
3587 +
            let found = findAnySymbol(self.scope, name) else {
3588 +
                throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
3589 +
            };
3590 +
            set sym = found;
3591 +
        }
3592 +
        case ast::NodeValue::ScopeAccess(access) => {
3593 +
            set sym = try resolveAccess(self, node, access, self.scope);
3594 +
        }
3595 +
        else => throw emitError(self, node, ErrorKind::GenericUnsupported),
3596 +
    }
3597 +
    if not isGenericDeclaration(sym.node) {
3598 +
        throw emitError(self, node, ErrorKind::GenericUnsupported);
3599 +
    }
3600 +
    setNodeSymbol(self, node, sym);
3601 +
    return sym;
3602 +
}
3603 +
3604 +
/// Resolve a generic record or union target.
3605 +
fn resolveGenericDataTarget(
3606 +
    self: *mut Resolver,
3607 +
    node: *ast::Node,
3608 +
) -> *mut Symbol throws (ResolveError) {
3609 +
    let sym = try resolveGenericTarget(self, node);
3610 +
    let case SymbolData::Type(_) = sym.data
3611 +
        else throw emitError(self, node, ErrorKind::GenericDataExpected);
3612 +
    match sym.node.value {
3613 +
        case ast::NodeValue::RecordDecl(_), ast::NodeValue::UnionDecl(_) => {}
3614 +
        else => throw emitError(self, node, ErrorKind::GenericDataExpected),
3615 +
    }
3616 +
    return sym;
3617 +
}
3618 +
3619 +
/// Build a concrete record specialization from substituted member types.
3620 +
fn specializeGenericRecord(
3621 +
    self: *mut Resolver,
3622 +
    template: *GenericTemplate,
3623 +
    decl: ast::RecordDecl,
3624 +
    sub: *Substitution,
3625 +
) -> RecordType throws (ResolveError) {
3626 +
    let a = alloc::arenaAllocator(&mut self.arena);
3627 +
    let mut fields: *mut [RecordField] = &mut [];
3628 +
    let mut offset: u32 = 0;
3629 +
    let mut alignment: u32 = 1;
3630 +
    for member, i in decl.fields {
3631 +
        let case ast::NodeValue::RecordField { field, type, .. } = member.value
3632 +
            else throw emitError(self, member, ErrorKind::Internal);
3633 +
        let concrete = try substituteType(self, *template.members[i], sub, type);
3634 +
        if hasUnresolvedNominalLayout(concrete) {
3635 +
            throw emitError(self, type, ErrorKind::GenericRecursiveLayout);
3636 +
        }
3637 +
        try ensureStorableType(self, type, concrete);
3638 +
        try ensureTypeResolved(self, concrete, type);
3639 +
        let layout = getTypeLayout(concrete);
3640 +
        set offset = mem::alignUp(offset, layout.alignment);
3641 +
        let mut name: ?*[u8] = nil;
3642 +
        if decl.labeled {
3643 +
            let nameNode = field else throw emitError(self, member, ErrorKind::Internal);
3644 +
            set name = try nodeName(self, nameNode);
3645 +
        }
3646 +
        fields.append(RecordField {
3647 +
            name,
3648 +
            fieldType: concrete,
3649 +
            offset: offset as i32,
3650 +
        }, a);
3651 +
        set offset += layout.size;
3652 +
        set alignment = max(alignment, layout.alignment);
3653 +
    }
3654 +
    return RecordType {
3655 +
        fields: &fields[..],
3656 +
        labeled: decl.labeled,
3657 +
        layout: Layout {
3658 +
            size: mem::alignUp(offset, alignment),
3659 +
            alignment,
3660 +
        },
3661 +
        declaredLinear: template.declaredLinear,
3662 +
    };
3663 +
}
3664 +
3665 +
/// Build a concrete union specialization from substituted variant types.
3666 +
fn specializeGenericUnion(
3667 +
    self: *mut Resolver,
3668 +
    templateSym: *mut Symbol,
3669 +
    template: *GenericTemplate,
3670 +
    decl: ast::UnionDecl,
3671 +
    sub: *Substitution,
3672 +
) -> UnionType throws (ResolveError) {
3673 +
    let a = alloc::arenaAllocator(&mut self.arena);
3674 +
    let mut variants: *mut [UnionVariant] = &mut [];
3675 +
    let mut iota: u32 = 0;
3676 +
    for variantNode, i in decl.variants {
3677 +
        let case ast::NodeValue::UnionDeclVariant(variantDecl) = variantNode.value
3678 +
            else throw emitError(self, variantNode, ErrorKind::Internal);
3679 +
        let valueType = try substituteType(
3680 +
            self, *template.members[i], sub, variantNode
3681 +
        );
3682 +
        if hasUnresolvedNominalLayout(valueType) {
3683 +
            throw emitError(self, variantNode, ErrorKind::GenericRecursiveLayout);
3684 +
        }
3685 +
        if let typeNode = variantDecl.type {
3686 +
            try ensureStorableType(self, typeNode, valueType);
3687 +
            try ensureTypeResolved(self, valueType, typeNode);
3688 +
        }
3689 +
        let name = try nodeName(self, variantDecl.name);
3690 +
        let tag = try variantTag(self, variantDecl, &mut iota, sub);
3691 +
        let symbol = allocSymbol(
3692 +
            self,
3693 +
            SymbolData::Variant {
3694 +
                type: valueType,
3695 +
                decl: template.decl,
3696 +
                ordinal: i,
3697 +
                index: tag,
3698 +
            },
3699 +
            name,
3700 +
            variantNode,
3701 +
            0,
3702 +
        );
3703 +
        set symbol.moduleId = templateSym.moduleId;
3704 +
        variants.append(UnionVariant { name, valueType, symbol }, a);
3705 +
    }
3706 +
    let info = computeUnionLayout(&variants[..]);
3707 +
    return UnionType {
3708 +
        variants: &variants[..],
3709 +
        layout: info.layout,
3710 +
        valOffset: info.valOffset,
3711 +
        isAllVoid: info.isAllVoid,
3712 +
        declaredLinear: template.declaredLinear,
3713 +
    };
3714 +
}
3715 +
3716 +
/// Return one canonical concrete specialization for a generic data application.
3717 +
fn specializeGenericData(
3718 +
    self: *mut Resolver,
3719 +
    site: *ast::Node,
3720 +
    templateSym: *mut Symbol,
3721 +
    args: *[*Type],
3722 +
    rooted: bool,
3723 +
) -> *mut NominalType throws (ResolveError) {
3724 +
    if let existing = findGenericDataSpecialization(self, templateSym, args) {
3725 +
        if rooted {
3726 +
            set *existing.rooted = true;
3727 +
        }
3728 +
        return existing.nominal;
3729 +
    }
3730 +
    if self.genericSpecializationCount >= MAX_GENERIC_SPECIALIZATIONS {
3731 +
        throw emitError(self, site, ErrorKind::GenericSpecializationLimit);
3732 +
    }
3733 +
    set self.genericSpecializationCount += 1;
3734 +
    let template = genericTemplateFor(self, templateSym)
3735 +
        else throw emitError(self, site, ErrorKind::Internal);
3736 +
    let a = alloc::arenaAllocator(&mut self.arena);
3737 +
    let mut storedArgs: *mut [*Type] = &mut [];
3738 +
    let rootedFlag = try! alloc::alloc(
3739 +
        &mut self.arena, @sizeOf(bool), @alignOf(bool)
3740 +
    ) as *mut bool;
3741 +
    set *rootedFlag = rooted;
3742 +
    for arg in args {
3743 +
        storedArgs.append(arg, a);
3744 +
    }
3745 +
    let nominal = allocNominalType(self, NominalType::Placeholder(template.decl));
3746 +
    let cacheNode = try! alloc::alloc(
3747 +
        &mut self.arena,
3748 +
        @sizeOf(GenericDataSpecializationNode),
3749 +
        @alignOf(GenericDataSpecializationNode),
3750 +
    ) as *mut GenericDataSpecializationNode;
3751 +
    set *cacheNode = GenericDataSpecializationNode {
3752 +
        specialization: GenericDataSpecialization {
3753 +
            template: templateSym,
3754 +
            args: &storedArgs[..],
3755 +
            nominal,
3756 +
            rooted: rootedFlag,
3757 +
            site,
3758 +
        },
3759 +
        next: self.genericDataSpecializations,
3760 +
    };
3761 +
    set self.genericDataSpecializations = cacheNode;
3762 +
    let sub = Substitution { params: template.params, args: &storedArgs[..] };
3763 +
    match template.decl.value {
3764 +
        case ast::NodeValue::RecordDecl(decl) => {
3765 +
            let recordType = try specializeGenericRecord(self, template, decl, &sub);
3766 +
            set *nominal = NominalType::Record(recordType);
3767 +
        }
3768 +
        case ast::NodeValue::UnionDecl(decl) => {
3769 +
            let unionType = try specializeGenericUnion(
3770 +
                self, templateSym, template, decl, &sub
3771 +
            );
3772 +
            set *nominal = NominalType::Union(unionType);
3773 +
        }
3774 +
        else => throw emitError(self, site, ErrorKind::GenericDataExpected),
3775 +
    }
3776 +
    return nominal;
3777 +
}
3778 +
3779 +
/// Resolve one generic argument according to its declaration kind.
3780 +
fn resolveGenericArgument(
3781 +
    self: *mut Resolver,
3782 +
    argNode: *ast::Node,
3783 +
    param: *GenericParamType,
3784 +
) -> Type throws (ResolveError) {
3785 +
    if let constType = param.constType {
3786 +
        let mut expr = argNode;
3787 +
        if let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(name)) = argNode.value {
3788 +
            set expr = name;
3789 +
        }
3790 +
        let actual = try visit(self, expr, *constType);
3791 +
        if let value = constValueEntry(self, expr) {
3792 +
            let case ConstValue::Int(int) = value
3793 +
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
3794 +
            if not validateConstIntRange(value, *constType) {
3795 +
                throw emitError(self, expr, ErrorKind::NumericLiteralOverflow);
3796 +
            }
3797 +
            let _ = try expectAssignable(self, *constType, actual, expr);
3798 +
            let case ConstValue::Int(canonical) = castConstInt(int, *constType)
3799 +
                else throw emitError(self, expr, ErrorKind::Internal);
3800 +
            return Type::ConstArgument { type: constType, value: canonical };
3801 +
        }
3802 +
        let _ = try expectAssignable(self, *constType, actual, expr);
3803 +
        if isConstExpr(self, expr) and containsGenericConstExpr(self, expr) {
3804 +
            return Type::GenericConstExpr { type: constType, expr };
3805 +
        }
3806 +
        throw emitError(self, expr, ErrorKind::ConstExprRequired);
3807 +
    }
3808 +
    if let case ast::NodeValue::TypeSig(_) = argNode.value {
3809 +
        let arg = try resolveGenericValueType(self, argNode);
3810 +
        return try materializeConcreteGenericData(self, arg, argNode);
3811 +
    }
3812 +
    throw emitError(self, argNode, ErrorKind::GenericUnsupported);
3813 +
}
3814 +
3815 +
/// Resolve and canonicalize one generic data type application.
3816 +
fn resolveGenericDataApply(
3817 +
    self: *mut Resolver,
3818 +
    node: *ast::Node,
3819 +
    app: ast::GenericApply,
3820 +
    rooted: bool,
3821 +
) -> *mut NominalType throws (ResolveError) {
3822 +
    let templateSym = try resolveGenericDataTarget(self, app.target);
3823 +
    try ensureGenericDataTemplate(self, templateSym);
3824 +
    let template = genericTemplateFor(self, templateSym)
3825 +
        else throw emitError(self, node, ErrorKind::Internal);
3826 +
    if app.args.len <> template.params.len {
3827 +
        throw emitError(self, node, ErrorKind::GenericArgumentCount(CountMismatch {
3828 +
            expected: template.params.len,
3829 +
            actual: app.args.len,
3830 +
        }));
3831 +
    }
3832 +
    let a = alloc::arenaAllocator(&mut self.arena);
3833 +
    let mut args: *mut [*Type] = &mut [];
3834 +
    for argNode, i in app.args {
3835 +
        let argType = try resolveGenericArgument(self, argNode, template.params[i]);
3836 +
        if containsGenericParameter(argType) {
3837 +
            throw emitError(self, argNode, ErrorKind::GenericConcreteArgumentsRequired);
3838 +
        }
3839 +
        args.append(allocType(self, argType), a);
3840 +
    }
3841 +
    let nominal = try specializeGenericData(
3842 +
        self, node, templateSym, &args[..], rooted
3843 +
    );
3844 +
3845 +
    setNodeSymbol(self, node, templateSym);
3846 +
    setNodeType(self, node, Type::Nominal(nominal));
3847 +
    return nominal;
3848 +
}
3849 +
3850 +
/// Return the function specialization list for lowering.
3851 +
export fn genericFnSpecializations(
3852 +
    self: *Resolver,
3853 +
) -> ?*GenericFnSpecializationNode {
3854 +
    return self.genericFnSpecializations;
3855 +
}
3856 +
3857 +
/// Look up a canonical function specialization.
3858 +
export fn findGenericFnSpecialization(
3859 +
    self: *Resolver,
3860 +
    template: *Symbol,
3861 +
    args: *[*Type],
3862 +
) -> ?*GenericFnSpecialization {
3863 +
    let mut cursor = self.genericFnSpecializations;
3864 +
    while let node = cursor {
3865 +
        let entry = &node.specialization;
3866 +
        if entry.template == template and entry.args.len == args.len {
3867 +
            let mut equal = true;
3868 +
            for arg, i in args {
3869 +
                if not typesEqual(*entry.args[i], *arg) {
3870 +
                    set equal = false;
3871 +
                    break;
3872 +
                }
3873 +
            }
3874 +
            if equal {
3875 +
                return entry;
3876 +
            }
3877 +
        }
3878 +
        set cursor = node.next;
3879 +
    }
3880 +
    return nil;
3881 +
}
3882 +
3883 +
/// Create or retrieve one concrete generic function specialization.
3884 +
fn internGenericFnSpecialization(
3885 +
    self: *mut Resolver,
3886 +
    templateSym: *mut Symbol,
3887 +
    args: *[*Type],
3888 +
    site: *ast::Node,
3889 +
    depth: u16,
3890 +
) -> *GenericFnSpecialization throws (ResolveError) {
3891 +
    if let existing = findGenericFnSpecialization(self, templateSym, args) {
3892 +
        return existing;
3893 +
    }
3894 +
    if self.genericSpecializationCount >= MAX_GENERIC_SPECIALIZATIONS {
3895 +
        throw emitError(self, site, ErrorKind::GenericSpecializationLimit);
3896 +
    }
3897 +
    set self.genericSpecializationCount += 1;
3898 +
    let template = genericTemplateFor(self, templateSym)
3899 +
        else throw emitError(self, site, ErrorKind::Internal);
3900 +
    let signature = template.signature
3901 +
        else throw emitError(self, site, ErrorKind::GenericFunctionExpected);
3902 +
    let a = alloc::arenaAllocator(&mut self.arena);
3903 +
    let mut storedArgs: *mut [*Type] = &mut [];
3904 +
    for arg in args {
3905 +
        storedArgs.append(allocType(self, *arg), a);
3906 +
    }
3907 +
    let sub = Substitution { params: template.params, args: &storedArgs[..] };
3908 +
    let concrete = try substituteType(self, Type::Fn(signature), &sub, site);
3909 +
    let case Type::Fn(fnType) = concrete
3910 +
        else throw emitError(self, site, ErrorKind::Internal);
3911 +
    let _ = markGenericDataTypeRooted(self, concrete);
3912 +
    let cacheNode = try! alloc::alloc(
3913 +
        &mut self.arena,
3914 +
        @sizeOf(GenericFnSpecializationNode),
3915 +
        @alignOf(GenericFnSpecializationNode),
3916 +
    ) as *mut GenericFnSpecializationNode;
3917 +
    set *cacheNode = GenericFnSpecializationNode {
3918 +
        specialization: GenericFnSpecialization {
3919 +
            template: templateSym,
3920 +
            args: &storedArgs[..],
3921 +
            fnType,
3922 +
            site,
3923 +
            state: GenericFnState::Queued,
3924 +
            depth,
3925 +
        },
3926 +
        next: self.genericFnSpecializations,
3927 +
    };
3928 +
    set self.genericFnSpecializations = cacheNode;
3929 +
    return &cacheNode.specialization;
3930 +
}
3931 +
3932 +
/// Retain a generic call edge for package-wide specialization closure.
3933 +
fn recordGenericFnDependency(
3934 +
    self: *mut Resolver,
3935 +
    node: *ast::Node,
3936 +
    caller: ?*mut Symbol,
3937 +
    callee: *mut Symbol,
3938 +
    args: *[*Type],
3939 +
    fnType: *FnType,
3940 +
) {
3941 +
    let a = alloc::arenaAllocator(&mut self.arena);
3942 +
    let mut storedArgs: *mut [*Type] = &mut [];
3943 +
    for arg in args {
3944 +
        storedArgs.append(allocType(self, *arg), a);
3945 +
    }
3946 +
    let dependency = try! alloc::alloc(
3947 +
        &mut self.arena,
3948 +
        @sizeOf(GenericFnDependency),
3949 +
        @alignOf(GenericFnDependency),
3950 +
    ) as *mut GenericFnDependency;
3951 +
    set *dependency = GenericFnDependency {
3952 +
        caller,
3953 +
        callee,
3954 +
        args: &storedArgs[..],
3955 +
        site: node,
3956 +
        next: self.genericFnDependencies,
3957 +
    };
3958 +
    set self.genericFnDependencies = dependency;
3959 +
    setNodeSymbol(self, node, callee);
3960 +
    setNodeType(self, node, Type::Fn(fnType));
3961 +
    set self.nodeData.entries[node.id].extra =
3962 +
        NodeExtra::GenericFnDependency(dependency);
3963 +
}
3964 +
3965 +
/// Resolve a generic function application as a root, concrete call, or symbolic edge.
3966 +
fn resolveGenericFnApply(
3967 +
    self: *mut Resolver,
3968 +
    node: *ast::Node,
3969 +
    app: ast::GenericApply,
3970 +
    rooted: bool,
3971 +
) -> *FnType throws (ResolveError) {
3972 +
    let templateSym = try resolveGenericTarget(self, app.target);
3973 +
    let case SymbolData::Value { type: Type::Fn(_), .. } = templateSym.data
3974 +
        else throw emitError(self, app.target, ErrorKind::GenericFunctionExpected);
3975 +
    let template = genericTemplateFor(self, templateSym)
3976 +
        else throw emitError(self, node, ErrorKind::Internal);
3977 +
    let signature = template.signature
3978 +
        else throw emitError(self, app.target, ErrorKind::GenericFunctionExpected);
3979 +
    if app.args.len <> template.params.len {
3980 +
        throw emitError(self, node, ErrorKind::GenericArgumentCount(CountMismatch {
3981 +
            expected: template.params.len,
3982 +
            actual: app.args.len,
3983 +
        }));
3984 +
    }
3985 +
    let a = alloc::arenaAllocator(&mut self.arena);
3986 +
    let mut args: *mut [*Type] = &mut [];
3987 +
    let caller = currentGenericTemplateSymbol(self);
3988 +
    for argNode, i in app.args {
3989 +
        let argType = try resolveGenericArgument(self, argNode, template.params[i]);
3990 +
        let symbolic = containsGenericParameter(argType);
3991 +
        if symbolic and caller == nil {
3992 +
            throw emitError(
3993 +
                self, argNode, ErrorKind::GenericConcreteArgumentsRequired
3994 +
            );
3995 +
        }
3996 +
        if not symbolic {
3997 +
            for bound in template.params[i].bounds {
3998 +
                if findInstance(self, bound, argType) == nil {
3999 +
                    throw emitError(
4000 +
                        self, argNode, ErrorKind::GenericBoundUnsatisfied(bound.name)
4001 +
                    );
4002 +
                }
4003 +
            }
4004 +
        }
4005 +
        args.append(allocType(self, argType), a);
4006 +
    }
4007 +
    let sub = Substitution { params: template.params, args: &args[..] };
4008 +
    let applied = try substituteType(self, Type::Fn(signature), &sub, node);
4009 +
    let case Type::Fn(appliedFn) = applied
4010 +
        else throw emitError(self, node, ErrorKind::Internal);
4011 +
    if rooted {
4012 +
        if caller <> nil {
4013 +
            throw emitError(self, node, ErrorKind::GenericConcreteArgumentsRequired);
4014 +
        }
4015 +
        let specialization = try internGenericFnSpecialization(
4016 +
            self, templateSym, &args[..], node, 0
4017 +
        );
4018 +
        setNodeSymbol(self, node, templateSym);
4019 +
        setNodeType(self, node, Type::Fn(specialization.fnType));
4020 +
        set self.nodeData.entries[node.id].extra =
4021 +
            NodeExtra::GenericFnCall(specialization);
4022 +
        return specialization.fnType;
4023 +
    }
4024 +
    if caller == nil {
4025 +
        if let existing = findGenericFnSpecialization(self, templateSym, &args[..]) {
4026 +
            setNodeSymbol(self, node, templateSym);
4027 +
            setNodeType(self, node, Type::Fn(existing.fnType));
4028 +
            set self.nodeData.entries[node.id].extra =
4029 +
                NodeExtra::GenericFnCall(existing);
4030 +
            return existing.fnType;
4031 +
        }
4032 +
    }
4033 +
    recordGenericFnDependency(
4034 +
        self, node, caller, templateSym, &args[..], appliedFn
4035 +
    );
4036 +
    return appliedFn;
4037 +
}
4038 +
4039 +
/// Expand explicit roots through symbolic generic calls to a fixed point.
4040 +
fn closeGenericFnSpecializations(self: *mut Resolver) throws (ResolveError) {
4041 +
    loop {
4042 +
        let mut queued: ?*mut GenericFnSpecialization = nil;
4043 +
        let mut cursor = self.genericFnSpecializations;
4044 +
        while let node = cursor {
4045 +
            if let case GenericFnState::Queued = node.specialization.state {
4046 +
                set queued = &mut node.specialization;
4047 +
                break;
4048 +
            }
4049 +
            set cursor = node.next;
4050 +
        }
4051 +
        let specialization = queued else break;
4052 +
        set specialization.state = GenericFnState::Lowering;
4053 +
        let callerTemplate = genericTemplateFor(self, specialization.template)
4054 +
            else throw emitError(self, specialization.site, ErrorKind::Internal);
4055 +
        let callerSub = Substitution {
4056 +
            params: callerTemplate.params,
4057 +
            args: specialization.args,
4058 +
        };
4059 +
        let mut edge = self.genericFnDependencies;
4060 +
        while let dependency = edge {
4061 +
            if dependency.caller == specialization.template {
4062 +
                let a = alloc::arenaAllocator(&mut self.arena);
4063 +
                let mut concreteArgs: *mut [*Type] = &mut [];
4064 +
                for arg in dependency.args {
4065 +
                    let concrete = try substituteType(
4066 +
                        self, *arg, &callerSub, dependency.site
4067 +
                    );
4068 +
                    if containsGenericParameter(concrete) {
4069 +
                        throw emitError(
4070 +
                            self,
4071 +
                            dependency.site,
4072 +
                            ErrorKind::GenericConcreteArgumentsRequired,
4073 +
                        );
4074 +
                    }
4075 +
                    concreteArgs.append(allocType(self, concrete), a);
4076 +
                }
4077 +
                let calleeTemplate = genericTemplateFor(self, dependency.callee)
4078 +
                    else throw emitError(
4079 +
                        self, dependency.site, ErrorKind::Internal
4080 +
                    );
4081 +
                for arg, i in concreteArgs {
4082 +
                    for bound in calleeTemplate.params[i].bounds {
4083 +
                        if findInstance(self, bound, *arg) == nil {
4084 +
                            throw emitError(
4085 +
                                self,
4086 +
                                dependency.site,
4087 +
                                ErrorKind::GenericBoundUnsatisfied(bound.name),
4088 +
                            );
4089 +
                        }
4090 +
                    }
4091 +
                }
4092 +
                let mut callee = findGenericFnSpecialization(
4093 +
                    self, dependency.callee, &concreteArgs[..]
4094 +
                );
4095 +
                if callee == nil {
4096 +
                    if specialization.depth >= MAX_GENERIC_SPECIALIZATION_DEPTH {
4097 +
                        throw emitError(
4098 +
                            self,
4099 +
                            dependency.site,
4100 +
                            ErrorKind::GenericSpecializationChain,
4101 +
                        );
4102 +
                    }
4103 +
                    set callee = try internGenericFnSpecialization(
4104 +
                        self,
4105 +
                        dependency.callee,
4106 +
                        &concreteArgs[..],
4107 +
                        dependency.site,
4108 +
                        specialization.depth + 1,
4109 +
                    );
4110 +
                }
4111 +
                let concreteCallee = callee
4112 +
                    else throw emitError(
4113 +
                        self, dependency.site, ErrorKind::Internal
4114 +
                    );
4115 +
                let resolution = try! alloc::alloc(
4116 +
                    &mut self.arena,
4117 +
                    @sizeOf(GenericFnDependencyResolution),
4118 +
                    @alignOf(GenericFnDependencyResolution),
4119 +
                ) as *mut GenericFnDependencyResolution;
4120 +
                set *resolution = GenericFnDependencyResolution {
4121 +
                    dependency,
4122 +
                    caller: specialization,
4123 +
                    callee: concreteCallee,
4124 +
                    next: self.genericFnDependencyResolutions,
4125 +
                };
4126 +
                set self.genericFnDependencyResolutions = resolution;
4127 +
            }
4128 +
            set edge = dependency.next;
4129 +
        }
4130 +
        set specialization.state = GenericFnState::Complete;
4131 +
    }
4132 +
4133 +
    // Non-generic calls may only select entries made reachable by the closure.
4134 +
    let mut edge = self.genericFnDependencies;
4135 +
    while let dependency = edge {
4136 +
        if dependency.caller == nil {
4137 +
            let specialization = findGenericFnSpecialization(
4138 +
                self, dependency.callee, dependency.args
4139 +
            ) else {
4140 +
                throw emitError(
4141 +
                    self,
4142 +
                    dependency.site,
4143 +
                    ErrorKind::GenericFunctionInstantiationRequired,
4144 +
                );
4145 +
            };
4146 +
            set self.nodeData.entries[dependency.site.id].extra =
4147 +
                NodeExtra::GenericFnCall(specialization);
4148 +
            set self.nodeData.entries[dependency.site.id].ty =
4149 +
                Type::Fn(specialization.fnType);
4150 +
        }
4151 +
        set edge = dependency.next;
4152 +
    }
4153 +
}
4154 +
4155 +
/// Select the concrete callee for a symbolic edge while lowering a specialization.
4156 +
export fn genericFnSpecializationForDependency(
4157 +
    self: *Resolver,
4158 +
    dependency: *GenericFnDependency,
4159 +
    caller: *GenericFnSpecialization,
4160 +
) -> ?*GenericFnSpecialization {
4161 +
    let mut resolution = self.genericFnDependencyResolutions;
4162 +
    while let entry = resolution {
4163 +
        if entry.dependency == dependency and entry.caller == caller {
4164 +
            return entry.callee;
4165 +
        }
4166 +
        set resolution = entry.next;
4167 +
    }
4168 +
    return nil;
4169 +
}
4170 +
4171 +
/// Resolve a type name, which could be an identifier or scoped path.
4172 +
fn resolveTypeName(self: *mut Resolver, node: *ast::Node) -> *NominalType throws (ResolveError) {
4173 +
    match node.value {
4174 +
        case ast::NodeValue::Ident(name) => {
4175 +
            let sym = findTypeSymbol(self.scope, name)
4176 +
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
4177 +
            let case SymbolData::Type(ty) = sym.data
4178 +
                else throw emitError(self, node, ErrorKind::Internal);
4179 +
            if isGenericDeclaration(sym.node) {
4180 +
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4181 +
            }
4182 +
4183 +
            setNodeSymbol(self, node, sym);
4184 +
4185 +
            return ty;
4186 +
        }
4187 +
        case ast::NodeValue::ScopeAccess(access) => {
4188 +
            let sym = try resolveAccess(self, node, access, self.scope);
4189 +
            let case SymbolData::Type(ty) = sym.data
4190 +
                else throw emitError(self, node, ErrorKind::Internal);
4191 +
            if isGenericDeclaration(sym.node) {
4192 +
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4193 +
            }
4194 +
4195 +
            setNodeSymbol(self, node, sym);
4196 +
4197 +
            return ty;
4198 +
        }
4199 +
        case ast::NodeValue::GenericApply(app) =>
4200 +
            return try resolveGenericDataApply(self, node, app, false),
4201 +
        else => panic "resolveTypeName: unsupported node value",
4202 +
    }
4203 +
}
4204 +
4205 +
/// Visit a top-level declaration in the declaration phase.
4206 +
/// This binds all names and analyzes signatures, types, and initializers.
4207 +
/// Function bodies are deferred to the definition phase.
4208 +
///
4209 +
/// Nb. User-defined types are already handled by this point.
4210 +
fn visitDecl(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
4211 +
    match node.value {
4212 +
        case ast::NodeValue::FnDecl(_),
4213 +
             ast::NodeValue::ConstDecl(_),
4214 +
             ast::NodeValue::Mod(_),
4215 +
             ast::NodeValue::Use(_) => {
4216 +
            // Handled in previous passes.
4217 +
        }
4218 +
        case ast::NodeValue::StaticDecl(_) => {
4219 +
            try infer(self, node);
4220 +
        }
4221 +
        case ast::NodeValue::InstanceDecl { traitName, targetType, methods } => {
4222 +
            try resolveInstanceDecl(self, node, traitName, targetType, methods);
4223 +
        }
4224 +
        case ast::NodeValue::MethodDecl { name, receiverName, receiverType, sig, body, attrs } => {
4225 +
            try resolveMethodDecl(self, node, name, receiverName, receiverType, sig, attrs);
4226 +
        }
4227 +
        case ast::NodeValue::Instantiate(applications) => {
4228 +
            for application in applications {
4229 +
                let case ast::NodeValue::GenericApply(app) = application.value
4230 +
                    else throw emitError(self, application, ErrorKind::GenericUnsupported);
4231 +
                if self.genericRoots >= MAX_GENERIC_ROOTS {
4232 +
                    throw emitError(self, application, ErrorKind::GenericRootLimit);
4233 +
                }
4234 +
                set self.genericRoots += 1;
4235 +
                let target = try resolveGenericTarget(self, app.target);
4236 +
                match target.data {
4237 +
                    case SymbolData::Type(_) => {
4238 +
                        let _ = try resolveGenericDataApply(self, application, app, true);
4239 +
                    }
4240 +
                    case SymbolData::Value { type: Type::Fn(_), .. } => {
4241 +
                        let _ = try resolveGenericFnApply(self, application, app, true);
4242 +
                    }
4243 +
                    else => {
4244 +
                        throw emitError(self, app.target, ErrorKind::GenericUnsupported);
4245 +
                    }
4246 +
                }
4247 +
            }
4248 +
            setNodeType(self, node, Type::Void);
4249 +
        }
4250 +
        else => {
4251 +
            // Ignore non-declaration nodes.
4252 +
        }
4253 +
    }
4254 +
}
4255 +
4256 +
/// Require the current declaration to be unsafe.
4257 +
fn requireUnsafe(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
4258 +
    if self.unsafeDepth == 0 {
4259 +
        throw emitError(self, node, ErrorKind::UnsafeOperation);
4260 +
    }
4261 +
}
4262 +
4263 +
/// Reject calls from safe code through unsafe function types.
2642 4264
fn checkUnsafeCall(self: *mut Resolver, node: *ast::Node, info: *FnType)
2643 4265
    throws (ResolveError)
2644 4266
{
2645 4267
    if info.isUnsafe and self.unsafeDepth == 0 {
2646 4268
        throw emitError(self, node, ErrorKind::UnsafeCall);
2712 4334
/// Reject nested references while allowing a direct parameter reference.
2713 4335
fn validateValueTypeReferences(self: *mut Resolver, node: *ast::Node, ty: Type)
2714 4336
    throws (ResolveError)
2715 4337
{
2716 4338
    if isRefType(ty) {
2717 -
        if let case Type::Pointer { target, .. } = ty {
2718 -
            if containsRef(*target) {
4339 +
        if let case Type::Pointer(pointer) = ty {
4340 +
            if containsRef(*pointer.target) {
2719 4341
                throw emitError(self, node, ErrorKind::InvalidRefPosition);
2720 4342
            }
2721 -
        } else if let case Type::Slice { item, .. } = ty {
2722 -
            if containsRef(*item) {
4343 +
        } else if let case Type::Slice(slice) = ty {
4344 +
            if containsRef(*slice.item) {
2723 4345
                throw emitError(self, node, ErrorKind::InvalidRefPosition);
2724 4346
            }
2725 4347
        }
2726 4348
    } else if containsRef(ty) {
2727 4349
        throw emitError(self, node, ErrorKind::InvalidRefPosition);
2768 4390
        case ast::NodeValue::Ident(name) => {
2769 4391
            let sym = findAnySymbol(self.scope, name)
2770 4392
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
2771 4393
            setNodeSymbol(self, node, sym);
2772 4394
            match sym.data {
2773 -
                case SymbolData::Value { type, .. } =>
2774 -
                    return setNodeType(self, node, type),
4395 +
                case SymbolData::Value { type, .. } => {
4396 +
                    if isGenericDeclaration(sym.node) {
4397 +
                        throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4398 +
                    }
4399 +
                    return setNodeType(self, node, type);
4400 +
                }
2775 4401
                case SymbolData::Constant { type, value } => {
2776 4402
                    if let val = value {
2777 4403
                        setNodeConstValue(self, node, val);
2778 4404
                    }
2779 4405
                    return setNodeType(self, node, type);
2780 4406
                },
2781 -
                case SymbolData::Type(t) =>
2782 -
                    return setNodeType(self, node, Type::Nominal(t)),
4407 +
                case SymbolData::Type(t) => {
4408 +
                    if isGenericDeclaration(sym.node) {
4409 +
                        throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4410 +
                    }
4411 +
                    return setNodeType(self, node, Type::Nominal(t));
4412 +
                }
4413 +
                case SymbolData::TypeParameter(param) => {
4414 +
                    set *param.used = true;
4415 +
                    return setNodeType(self, node, Type::Parameter(param));
4416 +
                }
4417 +
                case SymbolData::ConstParameter(param) => {
4418 +
                    set *param.used = true;
4419 +
                    let ty = param.constType else {
4420 +
                        throw emitError(self, node, ErrorKind::Internal);
4421 +
                    };
4422 +
                    return setNodeType(self, node, *ty);
4423 +
                }
2783 4424
                case SymbolData::Variant { .. } =>
2784 4425
                    return Type::Void,
2785 4426
                case SymbolData::Module { .. } =>
2786 4427
                    throw emitError(self, node, ErrorKind::UnexpectedModuleName),
2787 4428
                case SymbolData::Trait(_) =>
2788 4429
                    throw emitError(self, node, ErrorKind::UnexpectedTraitName),
2789 4430
            }
2790 4431
        },
2791 -
        case ast::NodeValue::Call(call) => return try resolveCall(self, node, call, CallCtx::Normal),
4432 +
        case ast::NodeValue::Call(call) =>
4433 +
            return try resolveCall(self, node, call, CallCtx::Normal, hint),
2792 4434
        case ast::NodeValue::FieldAccess(access) => return try resolveFieldAccess(self, node, access),
2793 4435
        case ast::NodeValue::BinOp(binop) => return try resolveBinOp(self, node, binop),
2794 4436
        case ast::NodeValue::Block(block) => return try resolveBlock(self, node, block),
4437 +
        case ast::NodeValue::FnDecl(decl) => {
4438 +
            if decl.params.len > 0 {
4439 +
                throw emitError(self, node, ErrorKind::GenericFnNested);
4440 +
            }
4441 +
            throw emitError(self, node, ErrorKind::UnexpectedNode(node));
4442 +
        }
2795 4443
        case ast::NodeValue::Let(decl) => return try resolveLet(self, node, decl),
2796 4444
        case ast::NodeValue::ConstDecl(decl) => return try resolveConstOrStatic(
2797 4445
            self, node, decl.ident, decl.type, decl.value, decl.attrs, true
2798 4446
        ),
2799 4447
        case ast::NodeValue::StaticDecl(decl) => return try resolveConstOrStatic(
2828 4476
        case ast::NodeValue::Assign(assign) => return try resolveAssign(self, node, assign),
2829 4477
        case ast::NodeValue::RecordLit(lit) => return try resolveRecordLit(self, node, lit, hint),
2830 4478
        case ast::NodeValue::ArrayLit(items) => return try resolveArrayLit(self, node, items, hint),
2831 4479
        case ast::NodeValue::ArrayRepeatLit(lit) => return try resolveArrayRepeat(self, node, lit, hint),
2832 4480
        case ast::NodeValue::Subscript { container, index } => return try resolveSubscript(self, node, container, index),
4481 +
        case ast::NodeValue::GenericApply(app) => {
4482 +
            let fnType = try resolveGenericFnApply(self, node, app, false);
4483 +
            return setNodeType(self, node, Type::Fn(fnType));
4484 +
        }
4485 +
        case ast::NodeValue::Instantiate(_) =>
4486 +
            throw emitError(self, node, ErrorKind::GenericUnsupported),
2833 4487
        case ast::NodeValue::ScopeAccess(access) => return try resolveScopeAccess(self, node, access),
2834 4488
        case ast::NodeValue::AddressOf(addr) => return try resolveAddressOf(self, node, addr, hint),
2835 4489
        case ast::NodeValue::Deref(target) => return try resolveDeref(self, node, target, hint),
2836 4490
        case ast::NodeValue::As(expr) => return try resolveAs(self, node, expr),
2837 4491
        case ast::NodeValue::Range(range) => return try resolveRange(self, node, range),
2838 4492
        case ast::NodeValue::Try(expr) => return try resolveTry(self, node, expr, hint),
2839 4493
        case ast::NodeValue::Return { value } => return try resolveReturn(self, node, value),
2840 4494
        case ast::NodeValue::Throw { expr } => return try resolveThrow(self, node, expr),
2841 4495
        case ast::NodeValue::Panic { message } => {
2842 -
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
4496 +
            // TODO: Have easy access to string type.
4497 +
            try visitOptional(self, message, Type::Slice(SliceType {
2843 4498
                class: types::PointerClass::Owned,
2844 4499
                item: allocType(self, Type::U8),
2845 4500
                mutable: false,
2846 -
            });
4501 +
            }));
2847 4502
            return setNodeType(self, node, Type::Never);
2848 4503
        },
2849 4504
        case ast::NodeValue::Assert { condition, message } => {
2850 4505
            try visit(self, condition, Type::Bool);
2851 -
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
4506 +
            // TODO: Have easy access to string type.
4507 +
            try visitOptional(self, message, Type::Slice(SliceType {
2852 4508
                class: types::PointerClass::Owned,
2853 4509
                item: allocType(self, Type::U8),
2854 4510
                mutable: false,
2855 -
            });
4511 +
            }));
2856 4512
            return setNodeType(self, node, Type::Void);
2857 4513
        },
2858 4514
        case ast::NodeValue::UnOp(unop) => return try resolveUnOp(self, node, unop),
2859 4515
        case ast::NodeValue::ExprStmt(expr) => {
2860 4516
            // Pass `Void` as expected type to indicate value is discarded.
2885 4541
            return setNodeType(self, node, Type::U8);
2886 4542
        }
2887 4543
        case ast::NodeValue::String(text) => {
2888 4544
            setNodeConstValue(self, node, ConstValue::String(text));
2889 4545
            let byteTy = allocType(self, Type::U8);
2890 -
            let sliceTy = allocType(self, Type::Slice {
4546 +
            let sliceTy = allocType(self, Type::Slice(SliceType {
2891 4547
                class: types::PointerClass::Owned,
2892 4548
                item: byteTy,
2893 4549
                mutable: false,
2894 -
            });
4550 +
            }));
2895 4551
            return setNodeType(self, node, *sliceTy);
2896 4552
        },
2897 4553
        case ast::NodeValue::Number(lit) => {
2898 4554
            setNodeConstValue(self, node, ConstValue::Int(ConstInt {
2899 4555
                magnitude: lit.magnitude,
3064 4720
        },
3065 4721
        case ast::NodeValue::AddressOf(addr) => {
3066 4722
            let ty = typeFor(self, node) else {
3067 4723
                return false;
3068 4724
            };
3069 -
            if let case Type::Slice { .. } = ty {
4725 +
            if let case Type::Slice(_) = ty {
3070 4726
                return isConstExpr(self, addr.target);
3071 4727
            }
3072 4728
            return false;
3073 4729
        },
3074 4730
        case ast::NodeValue::RecordLit(lit) => {
3087 4743
            // Identifiers and scope accesses referencing constants, union
3088 4744
            // variants, or function values are constant expressions.
3089 4745
            if let sym = symbolFor(self, node) {
3090 4746
                match sym.data {
3091 4747
                    case SymbolData::Variant { .. },
3092 -
                         SymbolData::Constant { .. } => return true,
4748 +
                         SymbolData::Constant { .. },
4749 +
                         SymbolData::ConstParameter(_) => return true,
3093 4750
                    case SymbolData::Value { type, .. } => {
3094 4751
                        if let case Type::Fn(_) = type {
3095 4752
                            return true;
3096 4753
                        }
3097 4754
                    }
3158 4815
        case IntegerRange::Signed { bits, .. } =>
3159 4816
            return ConstValue::Int(constIntFromBits(raw, bits, true)),
3160 4817
    }
3161 4818
}
3162 4819
4820 +
/// Return whether a constant expression depends on a rigid constant parameter.
4821 +
fn containsGenericConstExpr(self: *Resolver, node: *ast::Node) -> bool {
4822 +
    match node.value {
4823 +
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) => {
4824 +
            let sym = symbolFor(self, node) else return false;
4825 +
            if let case SymbolData::ConstParameter(_) = sym.data {
4826 +
                return true;
4827 +
            }
4828 +
            return false;
4829 +
        }
4830 +
        case ast::NodeValue::BinOp(binop) =>
4831 +
            return containsGenericConstExpr(self, binop.left) or
4832 +
                   containsGenericConstExpr(self, binop.right),
4833 +
        case ast::NodeValue::UnOp(unop) =>
4834 +
            return containsGenericConstExpr(self, unop.value),
4835 +
        case ast::NodeValue::As(expr) =>
4836 +
            return containsGenericConstExpr(self, expr.value),
4837 +
        else => return false,
4838 +
    }
4839 +
}
4840 +
4841 +
/// Evaluate an integer constant expression after replacing rigid parameters.
4842 +
fn constValueWithSubstitution(
4843 +
    self: *mut Resolver,
4844 +
    node: *ast::Node,
4845 +
    sub: *Substitution,
4846 +
) -> ?ConstValue {
4847 +
    if let value = constValueEntry(self, node) {
4848 +
        return value;
4849 +
    }
4850 +
    match node.value {
4851 +
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) => {
4852 +
            let sym = symbolFor(self, node) else return nil;
4853 +
            let case SymbolData::ConstParameter(param) = sym.data else return nil;
4854 +
            let arg = substitutionArg(sub, param);
4855 +
            let case Type::ConstArgument { value, .. } = arg else return nil;
4856 +
            return ConstValue::Int(value);
4857 +
        }
4858 +
        case ast::NodeValue::BinOp(binop) => {
4859 +
            let left = constValueWithSubstitution(self, binop.left, sub)
4860 +
                else return nil;
4861 +
            let right = constValueWithSubstitution(self, binop.right, sub)
4862 +
                else return nil;
4863 +
            let case ConstValue::Int(leftInt) = left else return nil;
4864 +
            let case ConstValue::Int(rightInt) = right else return nil;
4865 +
            return foldIntBinOp(binop.op, leftInt, rightInt);
4866 +
        }
4867 +
        case ast::NodeValue::UnOp(unop) => {
4868 +
            let value = constValueWithSubstitution(self, unop.value, sub)
4869 +
                else return nil;
4870 +
            match unop.op {
4871 +
                case ast::UnaryOp::Not => {
4872 +
                    let case ConstValue::Bool(v) = value else return nil;
4873 +
                    return ConstValue::Bool(not v);
4874 +
                }
4875 +
                case ast::UnaryOp::Neg => {
4876 +
                    let case ConstValue::Int(v) = value else return nil;
4877 +
                    return constInt(v.magnitude, v.bits, true, not v.negative);
4878 +
                }
4879 +
                case ast::UnaryOp::BitNot => {
4880 +
                    let case ConstValue::Int(v) = value else return nil;
4881 +
                    return ConstValue::Int(
4882 +
                        constIntFromSigned(
4883 +
                            -(constIntToSigned(v) + 1), v.bits, v.signed
4884 +
                        )
4885 +
                    );
4886 +
                }
4887 +
            }
4888 +
        }
4889 +
        case ast::NodeValue::As(expr) => {
4890 +
            let value = constValueWithSubstitution(self, expr.value, sub)
4891 +
                else return nil;
4892 +
            let case ConstValue::Int(v) = value else return nil;
4893 +
            let target = typeFor(self, node) else return nil;
4894 +
            if integerRange(target) == nil {
4895 +
                return nil;
4896 +
            }
4897 +
            return castConstInt(v, target);
4898 +
        }
4899 +
        else => return nil,
4900 +
    }
4901 +
}
4902 +
3163 4903
/// Return the constant `u32` value for a slice bound when known.
3164 4904
fn constSliceIndex(self: *mut Resolver, node: *ast::Node) -> ?u32 {
3165 4905
    let value = constValueEntry(self, node)
3166 4906
        else return nil;
3167 4907
    let case ConstValue::Int(int) = value
3261 5001
    setNodeType(self, valueNode, bindingTy);
3262 5002
3263 5003
    return Type::Void;
3264 5004
}
3265 5005
5006 +
/// Bind one declaration's rigid generic parameters in its child scope.
5007 +
fn resolveGenericParams(
5008 +
    self: *mut Resolver,
5009 +
    owner: *ast::Node,
5010 +
    nodes: *mut [*ast::Node],
5011 +
) -> *[*GenericParamType] throws (ResolveError) {
5012 +
    if nodes.len > MAX_GENERIC_PARAMS {
5013 +
        throw emitError(self, owner, ErrorKind::GenericParameterLimit);
5014 +
    }
5015 +
    let a = alloc::arenaAllocator(&mut self.arena);
5016 +
    let mut result: *mut [*GenericParamType] = &mut [];
5017 +
    for paramNode, index in nodes {
5018 +
        let case ast::NodeValue::GenericParam(param) = paramNode.value
5019 +
            else throw emitError(self, paramNode, ErrorKind::Internal);
5020 +
        let mut paramName: *[u8] = undefined;
5021 +
        let mut nameNode: *ast::Node = undefined;
5022 +
        let mut traitBounds: *mut [*TraitType] = &mut [];
5023 +
        let mut constType: ?*Type = nil;
5024 +
        match param {
5025 +
            case ast::GenericParam::Const { name, type } => {
5026 +
                set nameNode = name;
5027 +
                set paramName = try nodeName(self, name);
5028 +
                let ty = try resolveValueType(self, type);
5029 +
                if integerRange(ty) == nil or ty == Type::Int {
5030 +
                    throw emitError(self, type, ErrorKind::GenericConstUnsupported);
5031 +
                }
5032 +
                set constType = allocType(self, ty);
5033 +
            }
5034 +
            case ast::GenericParam::Type { name, bounds } => {
5035 +
                set nameNode = name;
5036 +
                set paramName = try nodeName(self, name);
5037 +
                for bound in bounds {
5038 +
                    let boundSym = try resolveNamePath(self, bound);
5039 +
                    let case SymbolData::Trait(traitInfo) = boundSym.data else {
5040 +
                        throw emitError(self, bound, ErrorKind::GenericBoundNotTrait);
5041 +
                    };
5042 +
                    setNodeSymbol(self, bound, boundSym);
5043 +
                    traitBounds.append(traitInfo, a);
5044 +
                }
5045 +
            }
5046 +
        }
5047 +
        let used = try! alloc::alloc(
5048 +
            &mut self.arena, @sizeOf(bool), @alignOf(bool)
5049 +
        ) as *mut bool;
5050 +
        set *used = false;
5051 +
        let p = try! alloc::alloc(
5052 +
            &mut self.arena,
5053 +
            @sizeOf(GenericParamType),
5054 +
            @alignOf(GenericParamType),
5055 +
        ) as *mut GenericParamType;
5056 +
        set *p = GenericParamType {
5057 +
            owner,
5058 +
            node: paramNode,
5059 +
            name: paramName,
5060 +
            index,
5061 +
            bounds: &traitBounds[..],
5062 +
            used,
5063 +
            constType,
5064 +
        };
5065 +
        let data = SymbolData::ConstParameter(p) if constType <> nil
5066 +
            else SymbolData::TypeParameter(p);
5067 +
        let sym = try bindIdent(
5068 +
            self, paramName, paramNode, data, 0, self.scope
5069 +
        );
5070 +
        setNodeSymbol(self, nameNode, sym);
5071 +
        if let ty = constType {
5072 +
            setNodeType(self, nameNode, *ty);
5073 +
            setNodeType(self, paramNode, *ty);
5074 +
        } else {
5075 +
            setNodeType(self, nameNode, Type::Parameter(p));
5076 +
            setNodeType(self, paramNode, Type::Parameter(p));
5077 +
        }
5078 +
        result.append(p, a);
5079 +
    }
5080 +
    return &result[..];
5081 +
}
5082 +
5083 +
/// Retrieve sparse metadata for a generic declaration symbol.
5084 +
export fn genericTemplateFor(self: *Resolver, symbol: *Symbol) -> ?*GenericTemplate {
5085 +
    let mut cursor = self.genericTemplates;
5086 +
    while let entry = cursor {
5087 +
        if entry.symbol == symbol {
5088 +
            return &entry.template;
5089 +
        }
5090 +
        set cursor = entry.next;
5091 +
    }
5092 +
    return nil;
5093 +
}
5094 +
5095 +
/// Retrieve mutable metadata while checking a generic function body.
5096 +
fn genericTemplateForMut(
5097 +
    self: *mut Resolver,
5098 +
    symbol: *Symbol,
5099 +
) -> ?*mut GenericTemplate {
5100 +
    let mut cursor = self.genericTemplates;
5101 +
    while let entry = cursor {
5102 +
        if entry.symbol == symbol {
5103 +
            return &mut entry.template;
5104 +
        }
5105 +
        set cursor = entry.next;
5106 +
    }
5107 +
    return nil;
5108 +
}
5109 +
5110 +
/// Return the generic template whose symbolic body is currently being checked.
5111 +
fn currentGenericTemplateSymbol(self: *Resolver) -> ?*mut Symbol {
5112 +
    let current = self.currentFn else return nil;
5113 +
    let mut cursor = self.genericTemplates;
5114 +
    while let entry = cursor {
5115 +
        if let signature = entry.template.signature; signature == current {
5116 +
            return entry.symbol;
5117 +
        }
5118 +
        set cursor = entry.next;
5119 +
    }
5120 +
    return nil;
5121 +
}
5122 +
5123 +
/// Attach generic metadata without increasing every symbol's allocation.
5124 +
fn registerGenericTemplate(
5125 +
    self: *mut Resolver,
5126 +
    symbol: *mut Symbol,
5127 +
    template: GenericTemplate,
5128 +
) -> *mut GenericTemplate {
5129 +
    let entry = try! alloc::alloc(
5130 +
        &mut self.arena,
5131 +
        @sizeOf(GenericTemplateNode),
5132 +
        @alignOf(GenericTemplateNode),
5133 +
    ) as *mut GenericTemplateNode;
5134 +
    set *entry = GenericTemplateNode {
5135 +
        symbol,
5136 +
        template,
5137 +
        next: self.genericTemplates,
5138 +
    };
5139 +
    set self.genericTemplates = entry;
5140 +
    return &mut entry.template;
5141 +
}
5142 +
5143 +
/// Resolve a function signature type without laying out generic aggregates.
5144 +
fn resolveFnSignatureType(self: *mut Resolver, node: *ast::Node, generic: bool) -> Type
5145 +
    throws (ResolveError)
5146 +
{
5147 +
    if generic {
5148 +
        return try resolveGenericValueType(self, node);
5149 +
    }
5150 +
    return try infer(self, node);
5151 +
}
5152 +
5153 +
/// Resolve and bind a function parameter using its signature mode.
5154 +
fn resolveFnSignatureParam(self: *mut Resolver, node: *ast::Node, generic: bool) -> Type
5155 +
    throws (ResolveError)
5156 +
{
5157 +
    if not generic {
5158 +
        return try infer(self, node);
5159 +
    }
5160 +
    let case ast::NodeValue::FnParam(param) = node.value
5161 +
        else throw emitError(self, node, ErrorKind::Internal);
5162 +
    let ty = try resolveGenericValueType(self, param.type);
5163 +
    let _ = try bindValueIdent(self, param.name, node, ty, false, 0, 0);
5164 +
    return setNodeType(self, node, ty);
5165 +
}
5166 +
3266 5167
/// Analyze a function declaration signature and bind the function name.
3267 5168
fn resolveFnDecl(self: *mut Resolver, node: *ast::Node, decl: ast::FnDecl) -> Type
3268 5169
    throws (ResolveError)
3269 5170
{
3270 5171
    let attrMask = resolveAttributes(self, decl.attrs);
3271 -
    let mut retTy = Type::Void;
3272 -
    if let retNode = decl.sig.returnType {
3273 -
        set retTy = try infer(self, retNode);
3274 -
        try ensureStorableType(self, retNode, retTy);
5172 +
    if decl.params.len > 0 {
5173 +
        if self.currentFn <> nil {
5174 +
            throw emitError(self, node, ErrorKind::GenericFnNested);
5175 +
        }
5176 +
        if ast::hasAttribute(attrMask, ast::Attribute::Extern)
5177 +
            or ast::hasAttribute(attrMask, ast::Attribute::Default)
5178 +
            or ast::hasAttribute(attrMask, ast::Attribute::Intrinsic)
5179 +
        {
5180 +
            throw emitError(self, node, ErrorKind::GenericFnAttribute);
5181 +
        }
3275 5182
    }
3276 5183
    let a = alloc::arenaAllocator(&mut self.arena);
3277 5184
    let mut paramTypes: *mut [*Type] = &mut [];
3278 5185
    let mut throwList: *mut [*Type] = &mut [];
3279 5186
    let mut fnType = FnType {
3280 5187
        paramTypes: &[],
3281 -
        returnType: allocType(self, retTy),
5188 +
        returnType: allocType(self, Type::Void),
3282 5189
        throwList: &[],
3283 5190
        isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe),
3284 5191
        localCount: 0,
3285 5192
    };
3286 -
    // Enter the function scope to process parameters.
3287 5193
    enterFn(self, node, &fnType);
3288 -
5194 +
    let genericParams = try resolveGenericParams(self, node, decl.params) catch e {
5195 +
        exitFn(self);
5196 +
        throw e;
5197 +
    };
5198 +
    if let retNode = decl.sig.returnType {
5199 +
        let retTy = try resolveFnSignatureType(
5200 +
            self, retNode, genericParams.len > 0
5201 +
        ) catch e {
5202 +
            exitFn(self);
5203 +
            throw e;
5204 +
        };
5205 +
        try ensureStorableType(self, retNode, retTy) catch e {
5206 +
            exitFn(self);
5207 +
            throw e;
5208 +
        };
5209 +
        set fnType.returnType = allocType(self, retTy);
5210 +
    }
3289 5211
    if decl.sig.params.len > MAX_FN_PARAMS {
3290 5212
        exitFn(self);
3291 5213
        throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
3292 5214
            expected: MAX_FN_PARAMS,
3293 5215
            actual: decl.sig.params.len,
3294 5216
        }));
3295 5217
    }
3296 5218
    for paramNode in decl.sig.params {
3297 -
        let paramTy = try infer(self, paramNode) catch e {
5219 +
        let paramTy = try resolveFnSignatureParam(
5220 +
            self, paramNode, genericParams.len > 0
5221 +
        ) catch e {
3298 5222
            exitFn(self);
3299 5223
            throw e;
3300 5224
        };
3301 5225
        paramTypes.append(allocType(self, paramTy), a);
3302 5226
    }
3303 -
3304 5227
    if decl.sig.throwList.len > MAX_FN_THROWS {
3305 5228
        exitFn(self);
3306 5229
        throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch {
3307 5230
            expected: MAX_FN_THROWS,
3308 5231
            actual: decl.sig.throwList.len,
3309 5232
        }));
3310 5233
    }
3311 5234
    for throwNode in decl.sig.throwList {
3312 -
        let throwTy = try infer(self, throwNode) catch e {
5235 +
        let throwTy = try resolveFnSignatureType(
5236 +
            self, throwNode, genericParams.len > 0
5237 +
        ) catch e {
5238 +
            exitFn(self);
5239 +
            throw e;
5240 +
        };
5241 +
        try ensureStorableType(self, throwNode, throwTy) catch e {
3313 5242
            exitFn(self);
3314 5243
            throw e;
3315 5244
        };
3316 5245
        throwList.append(allocType(self, throwTy), a);
3317 -
        try ensureStorableType(self, throwNode, throwTy);
3318 5246
    }
3319 5247
    exitFn(self);
3320 5248
    set fnType.paramTypes = &paramTypes[..];
3321 5249
    set fnType.throwList = &throwList[..];
3322 5250
3323 -
    // Bind the function name.
3324 -
    let ty = Type::Fn(allocFnType(self, fnType));
5251 +
    let fnInfo = allocFnType(self, fnType);
5252 +
    let ty = Type::Fn(fnInfo);
3325 5253
    let sym = try bindValueIdent(self, decl.name, node, ty, false, 0, attrMask)
3326 5254
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
3327 -
5255 +
    if genericParams.len > 0 {
5256 +
        registerGenericTemplate(self, sym, GenericTemplate {
5257 +
            decl: node,
5258 +
            params: genericParams,
5259 +
            signature: fnInfo,
5260 +
            members: &[],
5261 +
            declaredLinear: false,
5262 +
            moduleId: sym.moduleId,
5263 +
            bodyResolved: false,
5264 +
            bodyChecks: 0,
5265 +
        });
5266 +
    }
3328 5267
    return ty;
3329 5268
}
3330 5269
3331 5270
/// Analyze a function body.
3332 5271
fn resolveFnDeclBody(self: *mut Resolver, node: *ast::Node, decl: ast::FnDecl) throws (ResolveError) {
3333 5272
    let sym = symbolFor(self, node) else {
3334 5273
        // The function declaration failed to type check, therefore
3335 5274
        // no symbol was associated with it.
3336 5275
        return;
3337 5276
    };
5277 +
    let generic = genericTemplateForMut(self, sym);
5278 +
    if let template = generic {
5279 +
        if template.bodyResolved {
5280 +
            return;
5281 +
        }
5282 +
        set template.bodyResolved = true;
5283 +
        set template.bodyChecks += 1;
5284 +
    }
3338 5285
    let case SymbolData::Value { type: Type::Fn(fnType), .. } = sym.data else {
3339 5286
        panic "resolveFnDeclBody: unexpected symbol data for function";
3340 5287
    };
3341 5288
    let retTy = *fnType.returnType;
3342 5289
    let isExtern = ast::hasAttribute(sym.attrs, ast::Attribute::Extern);
3370 5317
            set self.unsafeDepth -= 1;
3371 5318
        }
3372 5319
        if self.linearEnabled {
3373 5320
            try checkLinearFn(self, nil, decl.sig.params, body);
3374 5321
        }
5322 +
        if let template = generic {
5323 +
            for param in template.params {
5324 +
                if not *param.used {
5325 +
                    throw emitError(
5326 +
                        self,
5327 +
                        param.node,
5328 +
                        ErrorKind::GenericFnUnusedParameter(param.name),
5329 +
                    );
5330 +
                }
5331 +
            }
5332 +
        }
3375 5333
    } else if not isExtern {
3376 5334
        throw emitError(self, node, ErrorKind::FnMissingBody);
3377 5335
    }
3378 5336
}
3379 5337
3406 5364
        }
3407 5365
    }
3408 5366
    return linear;
3409 5367
}
3410 5368
5369 +
/// Resolve a type used in generic data without requiring aggregate layout.
5370 +
fn resolveGenericValueType(self: *mut Resolver, node: *ast::Node) -> Type
5371 +
    throws (ResolveError)
5372 +
{
5373 +
    let case ast::NodeValue::TypeSig(sig) = node.value
5374 +
        else return try resolveValueType(self, node);
5375 +
    let mut ty: Type = undefined;
5376 +
    match sig {
5377 +
        case ast::TypeSig::Array { itemType, length } => {
5378 +
            let item = try resolveGenericValueType(self, itemType);
5379 +
            let _ = try checkNumeric(self, length);
5380 +
            if let value = constValueEntry(self, length) {
5381 +
                if not validateConstIntRange(value, Type::U32) {
5382 +
                    throw emitError(self, length, ErrorKind::NumericLiteralOverflow);
5383 +
                }
5384 +
                let case ConstValue::Int(int) = value
5385 +
                    else throw emitError(self, length, ErrorKind::ConstExprRequired);
5386 +
                set ty = Type::Array(ArrayType {
5387 +
                    item: allocType(self, item),
5388 +
                    length: int.magnitude as u32,
5389 +
                });
5390 +
            } else if isConstExpr(self, length) and
5391 +
                      containsGenericConstExpr(self, length)
5392 +
            {
5393 +
                set ty = Type::GenericArray {
5394 +
                    item: allocType(self, item),
5395 +
                    length,
5396 +
                };
5397 +
            } else {
5398 +
                throw emitError(self, length, ErrorKind::ConstExprRequired);
5399 +
            }
5400 +
        }
5401 +
        case ast::TypeSig::Slice { class, itemType, mutable } => {
5402 +
            let item = try resolveGenericValueType(self, itemType);
5403 +
            set ty = Type::Slice(SliceType {
5404 +
                class,
5405 +
                item: allocType(self, item),
5406 +
                mutable,
5407 +
            });
5408 +
        }
5409 +
        case ast::TypeSig::Pointer { class, valueType, mutable } => {
5410 +
            let target = try resolveGenericValueType(self, valueType);
5411 +
            set ty = Type::Pointer(PointerType {
5412 +
                class,
5413 +
                target: allocType(self, target),
5414 +
                mutable,
5415 +
            });
5416 +
        }
5417 +
        case ast::TypeSig::Optional { valueType } => {
5418 +
            let payload = try resolveGenericValueType(self, valueType);
5419 +
            set ty = Type::Optional(allocType(self, payload));
5420 +
        }
5421 +
        case ast::TypeSig::Nominal(typeName) => {
5422 +
            let case ast::NodeValue::GenericApply(app) = typeName.value
5423 +
                else return try resolveValueType(self, node);
5424 +
            let templateSym = try resolveGenericDataTarget(self, app.target);
5425 +
            try ensureGenericDataTemplate(self, templateSym);
5426 +
            let template = genericTemplateFor(self, templateSym)
5427 +
                else throw emitError(self, typeName, ErrorKind::Internal);
5428 +
            if app.args.len <> template.params.len {
5429 +
                throw emitError(self, typeName, ErrorKind::GenericArgumentCount(
5430 +
                    CountMismatch {
5431 +
                        expected: template.params.len,
5432 +
                        actual: app.args.len,
5433 +
                    }
5434 +
                ));
5435 +
            }
5436 +
            let a = alloc::arenaAllocator(&mut self.arena);
5437 +
            let mut args: *mut [*Type] = &mut [];
5438 +
            for argNode, i in app.args {
5439 +
                let arg = try resolveGenericArgument(
5440 +
                    self, argNode, template.params[i]
5441 +
                );
5442 +
                args.append(allocType(self, arg), a);
5443 +
            }
5444 +
            let symbolic = try! alloc::alloc(
5445 +
                &mut self.arena,
5446 +
                @sizeOf(GenericDataApplyType),
5447 +
                @alignOf(GenericDataApplyType),
5448 +
            ) as *mut GenericDataApplyType;
5449 +
            set *symbolic = GenericDataApplyType {
5450 +
                template: templateSym,
5451 +
                args: &args[..],
5452 +
                site: typeName,
5453 +
            };
5454 +
            set ty = Type::GenericDataApply(symbolic);
5455 +
        }
5456 +
        case ast::TypeSig::Record { fields, labeled } => {
5457 +
            let a = alloc::arenaAllocator(&mut self.arena);
5458 +
            let mut result: *mut [RecordField] = &mut [];
5459 +
            for field in fields {
5460 +
                let case ast::NodeValue::RecordField {
5461 +
                    field: fieldNameNode,
5462 +
                    type: typeNode,
5463 +
                    value,
5464 +
                } = field.value else panic "resolveGenericValueType: invalid record field";
5465 +
                let fieldType = try resolveGenericValueType(self, typeNode);
5466 +
                try ensureStorableType(self, typeNode, fieldType);
5467 +
                if let initializer = value {
5468 +
                    let _ = try checkAssignable(self, initializer, fieldType);
5469 +
                }
5470 +
                let mut fieldName: ?*[u8] = nil;
5471 +
                if let name = fieldNameNode {
5472 +
                    set fieldName = try nodeName(self, name);
5473 +
                }
5474 +
                result.append(RecordField {
5475 +
                    name: fieldName,
5476 +
                    fieldType,
5477 +
                    offset: -1,
5478 +
                }, a);
5479 +
            }
5480 +
            let rec = try! alloc::alloc(
5481 +
                &mut self.arena,
5482 +
                @sizeOf(GenericRecordType),
5483 +
                @alignOf(GenericRecordType),
5484 +
            ) as *mut GenericRecordType;
5485 +
            set *rec = GenericRecordType {
5486 +
                fields: &result[..],
5487 +
                labeled,
5488 +
            };
5489 +
            set ty = Type::GenericRecord(rec);
5490 +
        }
5491 +
        case ast::TypeSig::Fn(fnSig) => {
5492 +
            if fnSig.params.len > MAX_FN_PARAMS {
5493 +
                throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
5494 +
                    expected: MAX_FN_PARAMS,
5495 +
                    actual: fnSig.params.len,
5496 +
                }));
5497 +
            }
5498 +
            if fnSig.throwList.len > MAX_FN_THROWS {
5499 +
                throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch {
5500 +
                    expected: MAX_FN_THROWS,
5501 +
                    actual: fnSig.throwList.len,
5502 +
                }));
5503 +
            }
5504 +
            let a = alloc::arenaAllocator(&mut self.arena);
5505 +
            let mut params: *mut [*Type] = &mut [];
5506 +
            let mut throwTypes: *mut [*Type] = &mut [];
5507 +
            for param in fnSig.params {
5508 +
                let paramType = try resolveGenericValueType(self, param);
5509 +
                params.append(allocType(self, paramType), a);
5510 +
            }
5511 +
            for throwNode in fnSig.throwList {
5512 +
                let throwType = try resolveGenericValueType(self, throwNode);
5513 +
                try ensureStorableType(self, throwNode, throwType);
5514 +
                throwTypes.append(allocType(self, throwType), a);
5515 +
            }
5516 +
            let mut returnType = allocType(self, Type::Void);
5517 +
            if let returnNode = fnSig.returnType {
5518 +
                let resolved = try resolveGenericValueType(self, returnNode);
5519 +
                try ensureStorableType(self, returnNode, resolved);
5520 +
                set returnType = allocType(self, resolved);
5521 +
            }
5522 +
            set ty = Type::Fn(allocFnType(self, FnType {
5523 +
                paramTypes: &params[..],
5524 +
                returnType,
5525 +
                throwList: &throwTypes[..],
5526 +
                isUnsafe: false,
5527 +
                localCount: 0,
5528 +
            }));
5529 +
        }
5530 +
        else => return try resolveValueType(self, node),
5531 +
    }
5532 +
    return setNodeType(self, node, ty);
5533 +
}
5534 +
5535 +
/// Resolve symbolic field or variant types for a generic data template.
5536 +
fn resolveGenericDataTemplate(
5537 +
    self: *mut Resolver,
5538 +
    node: *ast::Node,
5539 +
    params: *mut [*ast::Node],
5540 +
    members: *mut [*ast::Node],
5541 +
    derives: *mut [*ast::Node],
5542 +
    isRecord: bool,
5543 +
) throws (ResolveError) {
5544 +
    let sym = symbolFor(self, node) else return;
5545 +
    if genericTemplateFor(self, sym) <> nil {
5546 +
        return;
5547 +
    }
5548 +
    enterScope(self, node);
5549 +
    let genericParams = try resolveGenericParams(self, node, params) catch e {
5550 +
        exitScope(self);
5551 +
        throw e;
5552 +
    };
5553 +
    let declaredLinear = try resolveLinearDerive(self, derives) catch e {
5554 +
        exitScope(self);
5555 +
        throw e;
5556 +
    };
5557 +
    // Publish the rigid parameters before resolving members so recursive and
5558 +
    // mutually recursive applications can observe the in-progress template.
5559 +
    let metadata = registerGenericTemplate(self, sym, GenericTemplate {
5560 +
        decl: node,
5561 +
        params: genericParams,
5562 +
        signature: nil,
5563 +
        members: &[],
5564 +
        declaredLinear,
5565 +
        moduleId: sym.moduleId,
5566 +
        bodyResolved: true,
5567 +
        bodyChecks: 0,
5568 +
    });
5569 +
    let a = alloc::arenaAllocator(&mut self.arena);
5570 +
    let mut memberTypes: *mut [*Type] = &mut [];
5571 +
    for member in members {
5572 +
        let mut memberTy = Type::Void;
5573 +
        let mut defaultValue: ?*ast::Node = nil;
5574 +
        if isRecord {
5575 +
            let case ast::NodeValue::RecordField { type, value, .. } = member.value
5576 +
                else panic "resolveGenericDataTemplate: invalid record field";
5577 +
            set memberTy = try resolveGenericValueType(self, type) catch e {
5578 +
                exitScope(self);
5579 +
                throw e;
5580 +
            };
5581 +
            set defaultValue = value;
5582 +
            try ensureStorableType(self, type, memberTy) catch e {
5583 +
                exitScope(self);
5584 +
                throw e;
5585 +
            };
5586 +
        } else {
5587 +
            let case ast::NodeValue::UnionDeclVariant(variant) = member.value
5588 +
                else panic "resolveGenericDataTemplate: invalid union variant";
5589 +
            if let type = variant.type {
5590 +
                set memberTy = try resolveGenericValueType(self, type) catch e {
5591 +
                    exitScope(self);
5592 +
                    throw e;
5593 +
                };
5594 +
                try ensureStorableType(self, type, memberTy) catch e {
5595 +
                    exitScope(self);
5596 +
                    throw e;
5597 +
                };
5598 +
            }
5599 +
            set defaultValue = variant.value;
5600 +
        }
5601 +
        if let value = defaultValue {
5602 +
            if isRecord {
5603 +
                let _ = try checkAssignable(self, value, memberTy) catch e {
5604 +
                    exitScope(self);
5605 +
                    throw e;
5606 +
                };
5607 +
            } else {
5608 +
                let _ = try checkNumeric(self, value) catch e {
5609 +
                    exitScope(self);
5610 +
                    throw e;
5611 +
                };
5612 +
                if constValueEntry(self, value) == nil and
5613 +
                   (not isConstExpr(self, value) or
5614 +
                    not containsGenericConstExpr(self, value))
5615 +
                {
5616 +
                    exitScope(self);
5617 +
                    throw emitError(self, value, ErrorKind::ConstExprRequired);
5618 +
                }
5619 +
            }
5620 +
        }
5621 +
        memberTypes.append(allocType(self, memberTy), a);
5622 +
    }
5623 +
    exitScope(self);
5624 +
    set *metadata = GenericTemplate {
5625 +
        decl: node,
5626 +
        params: genericParams,
5627 +
        signature: nil,
5628 +
        members: &memberTypes[..],
5629 +
        declaredLinear,
5630 +
        moduleId: sym.moduleId,
5631 +
        bodyResolved: true,
5632 +
        bodyChecks: 0,
5633 +
    };
5634 +
}
5635 +
3411 5636
/// Resolve record fields from a node list.
3412 5637
fn resolveRecordFields(self: *mut Resolver, node: *ast::Node, fields: *mut [*ast::Node], labeled: bool) -> RecordType
3413 5638
    throws (ResolveError)
3414 5639
{
3415 5640
    let a = alloc::arenaAllocator(&mut self.arena);
3506 5731
3507 5732
    return try bindTypeIdent(self, name, node, nominalTy, attrMask);
3508 5733
}
3509 5734
3510 5735
/// Allocate a trait type descriptor and return a pointer to it.
3511 -
fn allocTraitType(self: *mut Resolver, name: *[u8]) -> *mut TraitType {
5736 +
fn allocTraitType(
5737 +
    self: *mut Resolver,
5738 +
    name: *[u8],
5739 +
    node: *ast::Node,
5740 +
) -> *mut TraitType {
3512 5741
    let p = try! alloc::alloc(&mut self.arena, @sizeOf(TraitType), @alignOf(TraitType));
3513 5742
    let entry = p as *mut TraitType;
3514 -
    set *entry = TraitType { name, methods: &mut [], supertraits: &mut [] };
3515 -
5743 +
    let used = try! alloc::alloc(
5744 +
        &mut self.arena, @sizeOf(bool), @alignOf(bool)
5745 +
    ) as *mut bool;
5746 +
    set *used = false;
5747 +
    let selfType = try! alloc::alloc(
5748 +
        &mut self.arena, @sizeOf(GenericParamType), @alignOf(GenericParamType)
5749 +
    ) as *mut GenericParamType;
5750 +
    set *selfType = GenericParamType {
5751 +
        owner: node,
5752 +
        node,
5753 +
        name: "Self",
5754 +
        index: 0,
5755 +
        bounds: &[],
5756 +
        used,
5757 +
        constType: nil,
5758 +
    };
5759 +
    set *entry = TraitType {
5760 +
        name,
5761 +
        moduleId: self.currentMod,
5762 +
        nodeId: node.id,
5763 +
        methods: &mut [],
5764 +
        supertraits: &mut [],
5765 +
        selfType,
5766 +
        state: TraitState::Queued,
5767 +
        objectSafe: true,
5768 +
    };
3516 5769
    return entry;
3517 5770
}
3518 5771
3519 5772
/// Bind a trait name in the current scope.
3520 -
fn bindTraitName(self: *mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol
3521 -
    throws (ResolveError)
3522 -
{
5773 +
fn bindTraitName(
5774 +
    self: *mut Resolver,
5775 +
    node: *ast::Node,
5776 +
    name: *ast::Node,
5777 +
    attrs: ?ast::Attributes,
5778 +
) -> *mut Symbol throws (ResolveError) {
3523 5779
    let attrMask = resolveAttributes(self, attrs);
3524 5780
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
3525 -
3526 5781
    let traitName = try nodeName(self, name);
3527 -
    let traitType = allocTraitType(self, traitName);
5782 +
    let traitType = allocTraitType(self, traitName, node);
3528 5783
    let data = SymbolData::Trait(traitType);
3529 5784
    let sym = try bindIdent(self, traitName, node, data, attrMask, self.scope);
3530 -
3531 5785
    setNodeType(self, node, Type::Void);
3532 5786
    setNodeType(self, name, Type::Void);
3533 -
3534 5787
    return sym;
3535 5788
}
3536 5789
3537 5790
/// Find a trait method by name.
3538 5791
export fn findTraitMethod(traitType: *TraitType, name: *[u8]) -> ?*TraitMethod {
3542 5795
        }
3543 5796
    }
3544 5797
    return nil;
3545 5798
}
3546 5799
5800 +
/// Resolve one trait signature type with the declaring trait's rigid `Self`.
5801 +
fn resolveTraitSignatureType(
5802 +
    self: *mut Resolver,
5803 +
    traitType: *TraitType,
5804 +
    node: *ast::Node,
5805 +
) -> Type throws (ResolveError) {
5806 +
    let previous = self.currentTraitSelf;
5807 +
    set self.currentTraitSelf = traitType.selfType;
5808 +
    let resolved = try resolveValueType(self, node) catch {
5809 +
        set self.currentTraitSelf = previous;
5810 +
        throw ResolveError::Failure;
5811 +
    };
5812 +
    set self.currentTraitSelf = previous;
5813 +
    return resolved;
5814 +
}
5815 +
3547 5816
/// Resolve a trait declaration body: supertrait methods, then own methods.
3548 5817
fn resolveTraitBody(self: *mut Resolver, node: *ast::Node, supertraits: *mut [*ast::Node], methods: *mut [*ast::Node])
3549 5818
    throws (ResolveError)
3550 5819
{
3551 5820
    let sym = symbolFor(self, node)
3552 5821
        else return;
3553 5822
    let case SymbolData::Trait(traitType) = sym.data
3554 5823
        else return;
3555 -
    if traitType.methods.len > 0 {
3556 -
        return;
5824 +
    match traitType.state {
5825 +
        case TraitState::Complete, TraitState::Resolving => return,
5826 +
        case TraitState::Queued => set traitType.state = TraitState::Resolving,
3557 5827
    }
3558 5828
3559 5829
    // Resolve supertrait bounds and copy their methods into this trait.
3560 5830
    for superNode in supertraits {
3561 5831
        let superSym = try resolveNamePath(self, superNode);
3562 5832
        let case SymbolData::Trait(superTrait) = superSym.data
3563 5833
            else throw emitError(self, superNode, ErrorKind::Internal);
3564 -
        // Trait bodies are otherwise resolved in source order. Recursively
3565 -
        // resolve a supertrait only when it is declared later.
3566 -
        if superSym.node.id > node.id {
3567 -
            let case ast::NodeValue::TraitDecl {
3568 -
                supertraits: inheritedTraits, methods: inheritedMethods, ..
3569 -
            } = superSym.node.value else throw emitError(self, superNode, ErrorKind::Internal);
3570 -
            try resolveTraitBody(self, superSym.node, inheritedTraits, inheritedMethods);
5834 +
        // Resolve queued supertraits before consuming their method tables.
5835 +
        match superTrait.state {
5836 +
            case TraitState::Queued => {
5837 +
                let case ast::NodeValue::TraitDecl {
5838 +
                    supertraits: inheritedTraits, methods: inheritedMethods, ..
5839 +
                } = superSym.node.value
5840 +
                    else throw emitError(self, superNode, ErrorKind::Internal);
5841 +
                try resolveTraitBody(
5842 +
                    self, superSym.node, inheritedTraits, inheritedMethods
5843 +
                );
5844 +
            }
5845 +
            case TraitState::Resolving => {
5846 +
                throw emitError(self, superNode, ErrorKind::TraitInheritanceCycle);
5847 +
            }
5848 +
            case TraitState::Complete => {}
3571 5849
        }
3572 5850
3573 5851
        setNodeSymbol(self, superNode, superSym);
3574 5852
3575 5853
        let a = alloc::arenaAllocator(&mut self.arena);
3587 5865
            traitType.methods.append(TraitMethod {
3588 5866
                name: inherited.name,
3589 5867
                fnType: inherited.fnType,
3590 5868
                mutable: inherited.mutable,
3591 5869
                receiverClass: inherited.receiverClass,
5870 +
                owner: inherited.owner,
3592 5871
                index: traitType.methods.len as u32,
3593 5872
            }, a);
3594 5873
        }
3595 5874
        traitType.supertraits.append(superTrait, a);
5875 +
        if not superTrait.objectSafe {
5876 +
            set traitType.objectSafe = false;
5877 +
        }
3596 5878
    }
3597 5879
3598 5880
    if traitType.methods.len + methods.len > ast::MAX_TRAIT_METHODS {
3599 5881
        throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
3600 5882
            expected: ast::MAX_TRAIT_METHODS,
3640 5922
                expected: MAX_FN_PARAMS,
3641 5923
                actual: sig.params.len,
3642 5924
            }));
3643 5925
        }
3644 5926
        for paramNode in sig.params {
3645 -
            let paramTy = try infer(self, paramNode);
5927 +
            let case ast::NodeValue::FnParam(param) = paramNode.value
5928 +
                else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
5929 +
            let paramTy = try resolveTraitSignatureType(self, traitType, param.type);
3646 5930
            paramTypes.append(allocType(self, paramTy), a);
3647 5931
        }
3648 5932
        if let ret = sig.returnType {
3649 -
            set retType = allocType(self, try infer(self, ret));
5933 +
            set retType = allocType(
5934 +
                self, try resolveTraitSignatureType(self, traitType, ret)
5935 +
            );
3650 5936
        }
3651 5937
        // Resolve throws list.
3652 5938
        if sig.throwList.len > MAX_FN_THROWS {
3653 5939
            throw emitError(self, methodNode, ErrorKind::FnThrowOverflow(CountMismatch {
3654 5940
                expected: MAX_FN_THROWS,
3655 5941
                actual: sig.throwList.len,
3656 5942
            }));
3657 5943
        }
3658 5944
        for throwNode in sig.throwList {
3659 -
            let throwTy = try infer(self, throwNode);
5945 +
            let throwTy = try resolveTraitSignatureType(self, traitType, throwNode);
3660 5946
            throwList.append(allocType(self, throwTy), a);
3661 5947
        }
3662 5948
        let fnType = FnType {
3663 5949
            paramTypes: &paramTypes[..],
3664 5950
            returnType: retType,
3665 5951
            throwList: &throwList[..],
3666 5952
            isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe),
3667 5953
            localCount: 0,
3668 5954
        };
5955 +
        if containsGenericParameter(Type::Fn(&fnType)) {
5956 +
            set traitType.objectSafe = false;
5957 +
        }
3669 5958
        traitType.methods.append(TraitMethod {
3670 5959
            name: methodName,
3671 5960
            fnType: allocFnType(self, fnType),
3672 5961
            mutable,
3673 5962
            receiverClass,
5963 +
            owner: traitType,
3674 5964
            index: traitType.methods.len as u32,
3675 5965
        }, a);
3676 5966
3677 5967
        setNodeType(self, methodNode, Type::Void);
3678 5968
    }
5969 +
    set traitType.state = TraitState::Complete;
3679 5970
}
3680 5971
3681 5972
/// Resolve a name path node to a symbol.
3682 5973
/// Used for trait and type references in instance declarations and trait objects.
3683 5974
fn resolveNamePath(self: *mut Resolver, node: *ast::Node) -> *mut Symbol
3713 6004
    let case SymbolData::Trait(traitInfo) = traitSym.data
3714 6005
        else throw emitError(self, traitName, ErrorKind::Internal);
3715 6006
3716 6007
    setNodeSymbol(self, traitName, traitSym);
3717 6008
3718 -
    // Look up the target type.
3719 -
    let typeSym = try resolveNamePath(self, targetType);
3720 -
    let case SymbolData::Type(nominalTy) = typeSym.data
3721 -
        else throw emitError(self, targetType, ErrorKind::Internal);
3722 -
    setNodeSymbol(self, targetType, typeSym);
3723 -
    // Ensure the concrete type body is resolved.
3724 -
    try ensureNominalResolved(self, nominalTy, targetType);
3725 -
3726 -
    // Reject duplicate instance for the same (trait, type) pair.
3727 -
    let concreteType = Type::Nominal(nominalTy);
6009 +
    // Resolve a concrete target type, including built-in scalar types.
6010 +
    let concreteType = try resolveValueType(self, targetType);
6011 +
    if containsGenericParameter(concreteType) {
6012 +
        throw emitError(self, targetType, ErrorKind::InvalidInstanceTarget);
6013 +
    }
6014 +
    if let case Type::Nominal(nominalTy) = concreteType {
6015 +
        try ensureNominalResolved(self, nominalTy, targetType);
6016 +
    }
3728 6017
    if let _ = findInstance(self, traitInfo, concreteType) {
3729 6018
        throw emitError(self, node, ErrorKind::DuplicateInstance);
3730 6019
    }
3731 6020
3732 6021
    // Build the instance entry.
3737 6026
        &mut self.arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), traitInfo.methods.len as u32
3738 6027
    ) as *mut [*mut Symbol];
3739 6028
    let mut entry = InstanceEntry {
3740 6029
        traitType: traitInfo,
3741 6030
        concreteType,
3742 -
        concreteTypeName: typeSym.name,
3743 6031
        moduleId: self.currentMod,
3744 6032
        methods: methodSlice,
3745 6033
    };
3746 6034
    // Track which trait methods are covered by the instance.
3747 6035
    let mut covered: [bool; ast::MAX_TRAIT_METHODS] = [false; ast::MAX_TRAIT_METHODS];
3756 6044
        let attrMask = resolveAttributes(self, attrs);
3757 6045
3758 6046
        // Find the matching trait method.
3759 6047
        let tm = findTraitMethod(traitInfo, methodName)
3760 6048
            else throw emitError(self, name, ErrorKind::UnresolvedSymbol(methodName));
6049 +
        if tm.owner <> traitInfo {
6050 +
            throw emitError(self, name, ErrorKind::InheritedTraitMethod(methodName));
6051 +
        }
6052 +
        let selfArg = allocType(self, concreteType);
6053 +
        let selfParams: [*GenericParamType; 1] = [tm.owner.selfType];
6054 +
        let selfArgs: [*Type; 1] = [selfArg];
6055 +
        let selfSub = Substitution {
6056 +
            params: &selfParams[..],
6057 +
            args: &selfArgs[..],
6058 +
        };
6059 +
        let concreteMethodType = try substituteType(
6060 +
            self, Type::Fn(tm.fnType), &selfSub, methodNode
6061 +
        );
6062 +
        let case Type::Fn(expectedFn) = concreteMethodType
6063 +
            else throw emitError(self, methodNode, ErrorKind::Internal);
3761 6064
        let instanceUnsafe = ast::hasAttribute(attrMask, ast::Attribute::Unsafe);
3762 6065
        if instanceUnsafe <> tm.fnType.isUnsafe {
3763 6066
            throw emitError(self, methodNode, ErrorKind::TraitMethodSafetyMismatch);
3764 6067
        }
3765 6068
3793 6096
            throw emitError(self, receiverType, ErrorKind::ReceiverMutabilityMismatch);
3794 6097
        }
3795 6098
3796 6099
        // Build the function type for the instance method.
3797 6100
        // The receiver becomes the first parameter.
3798 -
        let receiverPtrType = Type::Pointer {
6101 +
        let receiverPtrType = Type::Pointer(PointerType {
3799 6102
            class: receiverClass,
3800 6103
            target: allocType(self, concreteType),
3801 6104
            mutable: receiverMut,
3802 -
        };
6105 +
        });
3803 6106
3804 6107
        // Validate that the instance method's signature matches the
3805 6108
        // trait method's signature exactly (params, return type, throws).
3806 -
        if sig.params.len <> tm.fnType.paramTypes.len {
6109 +
        if sig.params.len <> expectedFn.paramTypes.len {
3807 6110
            throw emitError(self, methodNode, ErrorKind::FnArgCountMismatch(CountMismatch {
3808 -
                expected: tm.fnType.paramTypes.len as u32,
6111 +
                expected: expectedFn.paramTypes.len as u32,
3809 6112
                actual: sig.params.len,
3810 6113
            }));
3811 6114
        }
3812 6115
        for paramNode, j in sig.params {
3813 6116
            let case ast::NodeValue::FnParam(param) = paramNode.value
3814 6117
                else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
3815 6118
            let instanceParamTy = try resolveValueType(self, param.type);
3816 -
            if not typesEqual(instanceParamTy, *tm.fnType.paramTypes[j]) {
6119 +
            if not typesEqual(instanceParamTy, *expectedFn.paramTypes[j]) {
3817 6120
                throw emitTypeMismatch(self, paramNode, TypeMismatch {
3818 -
                    expected: *tm.fnType.paramTypes[j],
6121 +
                    expected: *expectedFn.paramTypes[j],
3819 6122
                    actual: instanceParamTy,
3820 6123
                });
3821 6124
            }
3822 6125
        }
3823 6126
        let mut instanceRetTy = Type::Void;
3824 6127
        if let retNode = sig.returnType {
3825 6128
            set instanceRetTy = try resolveValueType(self, retNode);
3826 6129
        }
3827 -
        if not typesEqual(instanceRetTy, *tm.fnType.returnType) {
6130 +
        if not typesEqual(instanceRetTy, *expectedFn.returnType) {
3828 6131
            throw emitTypeMismatch(self, methodNode, TypeMismatch {
3829 -
                expected: *tm.fnType.returnType,
6132 +
                expected: *expectedFn.returnType,
3830 6133
                actual: instanceRetTy,
3831 6134
            });
3832 6135
        }
3833 -
        if sig.throwList.len <> tm.fnType.throwList.len {
6136 +
        if sig.throwList.len <> expectedFn.throwList.len {
3834 6137
            throw emitError(self, methodNode, ErrorKind::FnThrowCountMismatch(CountMismatch {
3835 -
                expected: tm.fnType.throwList.len as u32,
6138 +
                expected: expectedFn.throwList.len as u32,
3836 6139
                actual: sig.throwList.len,
3837 6140
            }));
3838 6141
        }
3839 6142
        for throwNode, j in sig.throwList {
3840 6143
            let instanceThrowTy = try resolveValueType(self, throwNode);
3841 -
            if not typesEqual(instanceThrowTy, *tm.fnType.throwList[j]) {
6144 +
            if not typesEqual(instanceThrowTy, *expectedFn.throwList[j]) {
3842 6145
                throw emitTypeMismatch(self, throwNode, TypeMismatch {
3843 -
                    expected: *tm.fnType.throwList[j],
6146 +
                    expected: *expectedFn.throwList[j],
3844 6147
                    actual: instanceThrowTy,
3845 6148
                });
3846 6149
            }
3847 6150
        }
3848 6151
3850 6153
        let a = alloc::arenaAllocator(&mut self.arena);
3851 6154
        // TODO: Improve this pattern, maybe via something like `(&[]).append(..)`?
3852 6155
        let mut paramTypes: *mut [*Type] = &mut [];
3853 6156
        paramTypes.append(allocType(self, receiverPtrType), a);
3854 6157
3855 -
        for ty in tm.fnType.paramTypes {
6158 +
        for ty in expectedFn.paramTypes {
3856 6159
            paramTypes.append(ty, a);
3857 6160
        }
3858 6161
        let fnType = FnType {
3859 6162
            paramTypes: &paramTypes[..],
3860 -
            returnType: tm.fnType.returnType,
3861 -
            throwList: tm.fnType.throwList,
3862 -
            isUnsafe: tm.fnType.isUnsafe,
6163 +
            returnType: expectedFn.returnType,
6164 +
            throwList: expectedFn.throwList,
6165 +
            isUnsafe: expectedFn.isUnsafe,
3863 6166
            localCount: 0,
3864 6167
        };
3865 6168
3866 6169
        // Create a symbol for the instance method without binding it into the
3867 6170
        // module scope. Instance methods are dispatched via v-table, so they
3997 6300
    attrs: ?ast::Attributes,
3998 6301
) throws (ResolveError) {
3999 6302
    // Resolve the receiver type: must be `*Type` or `*mut Type` pointing to a
4000 6303
    // nominal type.
4001 6304
    let fullReceiverTy = try infer(self, receiverType);
4002 -
    let case Type::Pointer {
4003 -
        class: receiverClass, target: receiverTarget, mutable: receiverMut,
4004 -
    } = fullReceiverTy
6305 +
    let case Type::Pointer(receiver) = fullReceiverTy
4005 6306
        else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
4006 -
    let concreteType = *receiverTarget;
6307 +
    let concreteType = *receiver.target;
4007 6308
    let case Type::Nominal(nominalTy) = concreteType
4008 6309
        else throw emitError(self, receiverType, ErrorKind::ExpectedRecord);
4009 6310
    try ensureNominalResolved(self, nominalTy, receiverType);
4010 6311
4011 -
    // Get the type name from the inner type node's symbol.
4012 -
    let typeName = try receiverTypeName(self, receiverType);
4013 6312
    let methodName = try nodeName(self, name);
4014 6313
    let attrMask = resolveAttributes(self, attrs);
4015 6314
4016 6315
    // Reject duplicate method for the same (type, name).
4017 6316
    if let _ = findMethod(self, concreteType, methodName) {
4021 6320
    // Resolve parameter types.
4022 6321
    let a = alloc::arenaAllocator(&mut self.arena);
4023 6322
    let mut paramTypes: *mut [*Type] = &mut [];
4024 6323
4025 6324
    // Receiver is the first parameter.
4026 -
    let receiverPtrType = Type::Pointer {
4027 -
        class: receiverClass,
6325 +
    let receiverPtrType = Type::Pointer(PointerType {
6326 +
        class: receiver.class,
4028 6327
        target: allocType(self, concreteType),
4029 -
        mutable: receiverMut,
4030 -
    };
6328 +
        mutable: receiver.mutable,
6329 +
    });
4031 6330
    paramTypes.append(allocType(self, receiverPtrType), a);
4032 6331
4033 6332
    for paramNode in sig.params {
4034 6333
        let case ast::NodeValue::FnParam(param) = paramNode.value
4035 6334
            else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
4086 6385
    if self.methodsLen >= MAX_METHODS {
4087 6386
        throw emitError(self, node, ErrorKind::Internal);
4088 6387
    }
4089 6388
    set self.methods[self.methodsLen] = MethodEntry {
4090 6389
        concreteType,
4091 -
        concreteTypeName: typeName,
4092 6390
        name: methodName,
4093 6391
        fnType: allocFnType(self, checkFnType),
4094 -
        mutable: receiverMut,
4095 -
        receiverClass,
6392 +
        mutable: receiver.mutable,
6393 +
        receiverClass: receiver.class,
4096 6394
        symbol: sym,
4097 6395
    };
4098 6396
    set self.methodsLen += 1;
4099 6397
}
4100 6398
4101 6399
/// Look up an instance entry by trait and concrete type.
4102 -
fn findInstance(self: *Resolver, traitInfo: *TraitType, concreteType: Type) -> ?*InstanceEntry {
6400 +
export fn findInstance(self: *Resolver, traitInfo: *TraitType, concreteType: Type) -> ?*InstanceEntry {
4103 6401
    for i in 0..self.instancesLen {
4104 6402
        let entry = &self.instances[i];
4105 6403
        if entry.traitType == traitInfo and typesEqual(entry.concreteType, concreteType) {
4106 6404
            return entry;
4107 6405
        }
4173 6471
        if let typeNode = variantDecl.type {
4174 6472
            set variantType = try infer(self, typeNode);
4175 6473
            try ensureStorableType(self, typeNode, variantType);
4176 6474
        }
4177 6475
        // Process the variant's explicit discriminant value if present.
4178 -
        try visitOptional(self, variantDecl.value, variantType);
4179 -
        let tag = variantTag(variantDecl, &mut iota);
6476 +
        if let value = variantDecl.value {
6477 +
            let _ = try checkSizeInt(self, value);
6478 +
        }
6479 +
        let tag = try variantTag(self, variantDecl, &mut iota, nil);
4180 6480
        // Create a symbol for this variant.
4181 6481
        let data = SymbolData::Variant { type: variantType, decl: node, ordinal: i, index: tag };
4182 6482
        let variantSym = allocSymbol(self, data, variantName, variantNode, 0);
4183 6483
4184 6484
        variants.append(UnionVariant {
4378 6678
    pattern: *ast::Node,
4379 6679
    scrutineeTy: Type,
4380 6680
    mode: IdentMode,
4381 6681
    matchBy: MatchBy
4382 6682
) throws (ResolveError) {
4383 -
    if let case Type::Pointer { target, .. } = scrutineeTy; isDestructuringPattern(pattern) {
4384 -
        try resolveCasePattern(self, pattern, *target, mode, matchBy);
6683 +
    if let case Type::Pointer(pointer) = scrutineeTy; isDestructuringPattern(pattern) {
6684 +
        try resolveCasePattern(self, pattern, *pointer.target, mode, matchBy);
4385 6685
        return;
4386 6686
    }
4387 6687
    // TODO: Collapse these nested matches.
4388 6688
    match scrutineeTy {
4389 6689
        case Type::Nominal(info) => {
4482 6782
        }
4483 6783
    }
4484 6784
    // Extract item type and store pre-computed loop metadata for the lowerer.
4485 6785
    let mut itemTy: Type = undefined;
4486 6786
    match iterableTy {
4487 -
        case Type::Slice { item, .. } => {
4488 -
            set itemTy = *item;
6787 +
        case Type::Slice(slice) => {
6788 +
            set itemTy = *slice.item;
4489 6789
            setForLoopInfo(self, node, ForLoopInfo::Collection {
4490 -
                elemType: item, length: nil, bindingName, indexName
6790 +
                elemType: slice.item, length: nil, bindingName, indexName
4491 6791
            });
4492 6792
        }
4493 6793
        case Type::Range { start, .. } => {
4494 6794
            // Iterable ranges must have a start, and since we enforce type
4495 6795
            // equality for start and end, that is always the item type.
5048 7348
    throws (ResolveError)
5049 7349
{
5050 7350
    let mut bindTy = ty;
5051 7351
    match matchBy {
5052 7352
        case MatchBy::Value => {}
5053 -
        case MatchBy::Ref => set bindTy = Type::Pointer {
7353 +
        case MatchBy::Ref => set bindTy = Type::Pointer(PointerType {
5054 7354
            class: types::PointerClass::Ref,
5055 7355
            target: allocType(self, ty),
5056 7356
            mutable: false,
5057 -
        },
5058 -
        case MatchBy::MutRef => set bindTy = Type::Pointer {
7357 +
        }),
7358 +
        case MatchBy::MutRef => set bindTy = Type::Pointer(PointerType {
5059 7359
            class: types::PointerClass::Ref,
5060 7360
            target: allocType(self, ty),
5061 7361
            mutable: true,
5062 -
        },
7362 +
        }),
5063 7363
    }
5064 7364
    match binding.value {
5065 7365
        case ast::NodeValue::Placeholder => {
5066 7366
            // Nothing to do.
5067 7367
        }
5271 7571
                expected: 2,
5272 7572
                actual: args.len as u32,
5273 7573
            }));
5274 7574
        }
5275 7575
        let ptrType = try visit(self, args[0], Type::Unknown);
5276 -
        let case Type::Pointer { class, target, mutable } = ptrType else {
7576 +
        let case Type::Pointer(ptr) = ptrType else {
5277 7577
            throw emitError(self, node, ErrorKind::ExpectedPointer);
5278 7578
        };
5279 7579
        let _ = try checkAssignable(self, args[1], Type::U32);
5280 7580
        if args.len == 3 {
5281 7581
            let _ = try checkAssignable(self, args[2], Type::U32);
5282 7582
        }
5283 -
        return setNodeType(self, node, Type::Slice { class, item: target, mutable });
7583 +
        return setNodeType(self, node, Type::Slice(SliceType {
7584 +
            class: ptr.class,
7585 +
            item: ptr.target,
7586 +
            mutable: ptr.mutable,
7587 +
        }));
5284 7588
    }
5285 7589
    if args.len <> 1 {
5286 7590
        throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch {
5287 7591
            expected: 1,
5288 7592
            actual: args.len as u32,
5292 7596
    let ty = try resolveValueType(self, args[0]);
5293 7597
    // Ensure the type body is resolved before computing layout.
5294 7598
    // TODO: Somehow, ensuring the type is resolved should just happen all
5295 7599
    // the time, lazily.
5296 7600
    try ensureTypeResolved(self, ty, args[0]);
7601 +
    if containsGenericParameter(ty) {
7602 +
        throw emitError(self, args[0], ErrorKind::GenericLayoutRequired);
7603 +
    }
5297 7604
    // TODO: This should be stored in `symbol` instead of having to recompute it.
5298 7605
    // That way there's a canonical place to look for code gen.
5299 7606
    let layout = getTypeLayout(ty);
5300 7607
5301 7608
    // Evaluate the built-in.
5340 7647
5341 7648
        try checkAssignable(self, argNode, expectedTy);
5342 7649
    }
5343 7650
}
5344 7651
7652 +
/// Unify one symbolic parameter type with exact call-site evidence.
7653 +
fn inferGenericArgument(
7654 +
    self: *mut Resolver,
7655 +
    pattern: Type,
7656 +
    actual: Type,
7657 +
    params: *[*GenericParamType],
7658 +
    inferred: *mut [?*Type],
7659 +
) -> bool {
7660 +
    if let case Type::Parameter(param) = pattern {
7661 +
        let mut evidence = actual;
7662 +
        match actual {
7663 +
            case Type::Unknown, Type::Nil, Type::Undefined => return true,
7664 +
            case Type::Int => set evidence = Type::I64,
7665 +
            else => {},
7666 +
        }
7667 +
        for candidate, i in params {
7668 +
            if candidate == param {
7669 +
                if let prior = inferred[i] {
7670 +
                    return typesEqual(*prior, evidence);
7671 +
                }
7672 +
                set inferred[i] = allocType(self, evidence);
7673 +
                return true;
7674 +
            }
7675 +
        }
7676 +
        return typesEqual(pattern, evidence);
7677 +
    }
7678 +
    if typesEqual(pattern, actual) {
7679 +
        return true;
7680 +
    }
7681 +
    if not containsGenericParameter(pattern) {
7682 +
        return true;
7683 +
    }
7684 +
    match pattern {
7685 +
        case Type::Pointer(pointer) => {
7686 +
            let case Type::Pointer(actualPointer) = actual else return false;
7687 +
            return pointer.class == actualPointer.class
7688 +
                and pointer.mutable == actualPointer.mutable
7689 +
                and inferGenericArgument(
7690 +
                    self,
7691 +
                    *pointer.target,
7692 +
                    *actualPointer.target,
7693 +
                    params,
7694 +
                    inferred,
7695 +
                );
7696 +
        }
7697 +
        case Type::Slice(slice) => {
7698 +
            let case Type::Slice(actualSlice) = actual else return false;
7699 +
            return slice.class == actualSlice.class
7700 +
                and slice.mutable == actualSlice.mutable
7701 +
                and inferGenericArgument(
7702 +
                    self,
7703 +
                    *slice.item,
7704 +
                    *actualSlice.item,
7705 +
                    params,
7706 +
                    inferred,
7707 +
                );
7708 +
        }
7709 +
        case Type::Optional(inner) => {
7710 +
            let case Type::Optional(actualInner) = actual else return false;
7711 +
            return inferGenericArgument(
7712 +
                self, *inner, *actualInner, params, inferred
7713 +
            );
7714 +
        }
7715 +
        case Type::Array(array) => {
7716 +
            let case Type::Array(actualArray) = actual else return false;
7717 +
            return array.length == actualArray.length and inferGenericArgument(
7718 +
                self, *array.item, *actualArray.item, params, inferred
7719 +
            );
7720 +
        }
7721 +
        case Type::GenericDataApply(application) => {
7722 +
            let case Type::Nominal(nominal) = actual else return false;
7723 +
            let concrete = genericDataSpecializationForNominal(self, nominal)
7724 +
                else return false;
7725 +
            if concrete.template <> application.template
7726 +
                or concrete.args.len <> application.args.len
7727 +
            {
7728 +
                return false;
7729 +
            }
7730 +
            for arg, i in application.args {
7731 +
                if not inferGenericArgument(
7732 +
                    self, *arg, *concrete.args[i], params, inferred
7733 +
                ) {
7734 +
                    return false;
7735 +
                }
7736 +
            }
7737 +
            return true;
7738 +
        }
7739 +
        else => return false,
7740 +
    }
7741 +
}
7742 +
7743 +
/// Infer and resolve a direct call to a generic function template.
7744 +
fn resolveInferredGenericCall(
7745 +
    self: *mut Resolver,
7746 +
    callee: *ast::Node,
7747 +
    call: ast::Call,
7748 +
    expected: Type,
7749 +
) -> ?*FnType throws (ResolveError) {
7750 +
    let templateSym = findGenericCandidateSymbol(self, callee) else return nil;
7751 +
    let template = genericTemplateFor(self, templateSym) else return nil;
7752 +
    let signature = template.signature else return nil;
7753 +
    if call.args.len <> signature.paramTypes.len {
7754 +
        return nil;
7755 +
    }
7756 +
    let mut inferred: [?*Type; MAX_FN_PARAMS] = undefined;
7757 +
    for i in 0..inferred.len {
7758 +
        set inferred[i] = nil;
7759 +
    }
7760 +
    for argNode, i in call.args {
7761 +
        let actual = try infer(self, argNode);
7762 +
        if not inferGenericArgument(
7763 +
            self,
7764 +
            *signature.paramTypes[i],
7765 +
            actual,
7766 +
            template.params,
7767 +
            &mut inferred[..],
7768 +
        ) {
7769 +
            throw emitError(self, argNode, ErrorKind::GenericInferenceConflict);
7770 +
        }
7771 +
    }
7772 +
    if expected <> Type::Unknown and expected <> Type::Void and not inferGenericArgument(
7773 +
        self,
7774 +
        *signature.returnType,
7775 +
        expected,
7776 +
        template.params,
7777 +
        &mut inferred[..],
7778 +
    ) {
7779 +
        throw emitError(self, callee, ErrorKind::GenericInferenceConflict);
7780 +
    }
7781 +
    let a = alloc::arenaAllocator(&mut self.arena);
7782 +
    let mut args: *mut [*Type] = &mut [];
7783 +
    for _, i in template.params {
7784 +
        let arg = inferred[i] else {
7785 +
            throw emitError(
7786 +
                self, callee, ErrorKind::GenericInferenceIncomplete
7787 +
            );
7788 +
        };
7789 +
        args.append(arg, a);
7790 +
    }
7791 +
    for arg, i in args {
7792 +
        if not containsGenericParameter(*arg) {
7793 +
            for bound in template.params[i].bounds {
7794 +
                if findInstance(self, bound, *arg) == nil {
7795 +
                    throw emitError(
7796 +
                        self,
7797 +
                        callee,
7798 +
                        ErrorKind::GenericBoundUnsatisfied(bound.name),
7799 +
                    );
7800 +
                }
7801 +
            }
7802 +
        }
7803 +
    }
7804 +
    let sub = Substitution { params: template.params, args: &args[..] };
7805 +
    let applied = try substituteType(self, Type::Fn(signature), &sub, callee);
7806 +
    let case Type::Fn(appliedFn) = applied
7807 +
        else throw emitError(self, callee, ErrorKind::Internal);
7808 +
    let caller = currentGenericTemplateSymbol(self);
7809 +
    if caller == nil {
7810 +
        if let existing = findGenericFnSpecialization(
7811 +
            self, templateSym, &args[..]
7812 +
        ) {
7813 +
            setNodeSymbol(self, callee, templateSym);
7814 +
            setNodeType(self, callee, Type::Fn(existing.fnType));
7815 +
            set self.nodeData.entries[callee.id].extra =
7816 +
                NodeExtra::GenericFnCall(existing);
7817 +
            return existing.fnType;
7818 +
        }
7819 +
    }
7820 +
    recordGenericFnDependency(
7821 +
        self, callee, caller, templateSym, &args[..], appliedFn
7822 +
    );
7823 +
    return appliedFn;
7824 +
}
7825 +
7826 +
/// Resolve `Trait::method(receiver, ...)` for a rigid bounded parameter.
7827 +
fn resolveQualifiedGenericBoundCall(
7828 +
    self: *mut Resolver,
7829 +
    node: *ast::Node,
7830 +
    call: ast::Call,
7831 +
    ctx: CallCtx,
7832 +
) -> ?Type throws (ResolveError) {
7833 +
    let case ast::NodeValue::ScopeAccess(access) = call.callee.value
7834 +
        else return nil;
7835 +
    if currentGenericTemplateSymbol(self) == nil or call.args.len == 0 {
7836 +
        return nil;
7837 +
    }
7838 +
    let traitSym = try resolveNamePath(self, access.parent);
7839 +
    let case SymbolData::Trait(traitInfo) = traitSym.data else return nil;
7840 +
    let receiverTy = try infer(self, call.args[0]);
7841 +
    let case Type::Pointer(receiver) = receiverTy else return nil;
7842 +
    let case Type::Parameter(param) = *receiver.target else return nil;
7843 +
    let mut hasBound = false;
7844 +
    for bound in param.bounds {
7845 +
        if bound == traitInfo {
7846 +
            set hasBound = true;
7847 +
            break;
7848 +
        }
7849 +
    }
7850 +
    if not hasBound {
7851 +
        return nil;
7852 +
    }
7853 +
    if isUnsafePointerType(receiverTy) {
7854 +
        try requireUnsafe(self, call.args[0]);
7855 +
    }
7856 +
    let methodName = try nodeName(self, access.child);
7857 +
    let method = findTraitMethod(traitInfo, methodName)
7858 +
        else throw emitError(
7859 +
            self, access.child, ErrorKind::RecordFieldUnknown(methodName)
7860 +
        );
7861 +
    if method.mutable and not receiver.mutable {
7862 +
        throw emitError(self, call.args[0], ErrorKind::ImmutableBinding);
7863 +
    }
7864 +
    let selfParam: [*GenericParamType; 1] = [method.owner.selfType];
7865 +
    let selfArg: [*Type; 1] = [allocType(self, Type::Parameter(param))];
7866 +
    let sub = Substitution {
7867 +
        params: &selfParam[..],
7868 +
        args: &selfArg[..],
7869 +
    };
7870 +
    let substituted = try substituteType(
7871 +
        self, Type::Fn(method.fnType), &sub, node
7872 +
    );
7873 +
    let case Type::Fn(methodFn) = substituted
7874 +
        else throw emitError(self, node, ErrorKind::Internal);
7875 +
    let a = alloc::arenaAllocator(&mut self.arena);
7876 +
    let mut params: *mut [*Type] = &mut [];
7877 +
    params.append(allocType(self, receiverTy), a);
7878 +
    for methodParam in methodFn.paramTypes {
7879 +
        params.append(methodParam, a);
7880 +
    }
7881 +
    let fullFn = allocFnType(self, FnType {
7882 +
        paramTypes: &params[..],
7883 +
        returnType: methodFn.returnType,
7884 +
        throwList: methodFn.throwList,
7885 +
        isUnsafe: methodFn.isUnsafe,
7886 +
        localCount: 0,
7887 +
    });
7888 +
    try checkUnsafeCall(self, call.callee, fullFn);
7889 +
    try checkCallArgs(self, node, call, fullFn, ctx);
7890 +
    setNodeSymbol(self, access.parent, traitSym);
7891 +
    setNodeType(self, call.callee, Type::Fn(fullFn));
7892 +
    setGenericBoundMethodCall(
7893 +
        self, node, param, traitInfo, method.index, true
7894 +
    );
7895 +
    return setNodeType(self, node, *methodFn.returnType);
7896 +
}
7897 +
5345 7898
/// Analyze a function call expression.
5346 -
fn resolveCall(self: *mut Resolver, node: *ast::Node, call: ast::Call, ctx: CallCtx) -> Type
5347 -
    throws (ResolveError)
7899 +
fn resolveCall(
7900 +
    self: *mut Resolver,
7901 +
    node: *ast::Node,
7902 +
    call: ast::Call,
7903 +
    ctx: CallCtx,
7904 +
    expected: Type,
7905 +
) -> Type throws (ResolveError)
5348 7906
{
5349 7907
    // Intercept method calls on slices before inferring the callee.
5350 7908
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
5351 7909
        let parentTy = try infer(self, access.parent);
5352 7910
        if isUnsafePointerType(parentTy) {
5353 7911
            try requireUnsafe(self, access.parent);
5354 7912
        }
7913 +
5355 7914
        let subjectTy = autoDeref(parentTy);
5356 7915
5357 -
        if let case Type::Slice { item, mutable, .. } = subjectTy {
7916 +
        if let case Type::Slice(slice) = subjectTy {
5358 7917
            let methodName = try nodeName(self, access.child);
5359 7918
            if methodName == "append" {
5360 7919
                return try resolveSliceAppend(
5361 -
                    self, node, access.parent, parentTy, call.args, item, mutable
7920 +
                    self, node, access.parent, parentTy, call.args, slice.item, slice.mutable
5362 7921
                );
5363 7922
            }
5364 7923
            if methodName == "delete" {
5365 7924
                return try resolveSliceDelete(
5366 -
                    self, node, access.parent, call.args, item, mutable
7925 +
                    self, node, access.parent, call.args, slice.item, slice.mutable
5367 7926
                );
5368 7927
            }
5369 7928
        }
5370 7929
    }
7930 +
    if let bounded = try resolveQualifiedGenericBoundCall(
7931 +
        self, node, call, ctx
7932 +
    ) {
7933 +
        return bounded;
7934 +
    }
7935 +
    if let inferred = try resolveInferredGenericCall(
7936 +
        self, call.callee, call, expected
7937 +
    ) {
7938 +
        try checkUnsafeCall(self, call.callee, inferred);
7939 +
        try checkCallArgs(self, node, call, inferred, ctx);
7940 +
        return setNodeType(self, node, *inferred.returnType);
7941 +
    }
5371 7942
    let calleeTy = try infer(self, call.callee);
5372 7943
    if let case Type::Fn(info) = calleeTy {
5373 7944
        try checkUnsafeCall(self, call.callee, info);
5374 7945
    }
5375 7946
5376 7947
    // Check if callee is a union variant and dispatch to constructor handler.
5377 7948
    // TODO: Move this out. We should decide on this earlier, based on the callee.
5378 7949
    if let calleeSym = symbolFor(self, call.callee) {
5379 -
        if let case SymbolData::Variant { decl, .. } = calleeSym.data {
5380 -
            // TODO: Don't pass the callee type, pass the union type by getting it from
5381 -
            // the symbol.
5382 -
            let declSym = symbolFor(self, decl) else panic;
5383 -
            let case SymbolData::Type(ty) = declSym.data else panic;
5384 -
5385 -
            return try resolveUnionConstructorCall(self, node, call, ty);
7950 +
        if let case SymbolData::Variant { .. } = calleeSym.data {
7951 +
            let case Type::Nominal(unionType) = calleeTy
7952 +
                else throw emitError(self, call.callee, ErrorKind::Internal);
7953 +
            return try resolveUnionConstructorCall(self, node, call, unionType);
5386 7954
        }
5387 7955
        // Check if callee is an unlabeled record type for constructor call syntax.
5388 7956
        if let case SymbolData::Type(ty) = calleeSym.data {
5389 7957
            // Ensure the record body is resolved before checking if labeled.
5390 7958
            try ensureNominalResolved(self, ty, call.callee);
5402 7970
        if let t = typeFor(self, access.parent) {
5403 7971
            set parentTy = t;
5404 7972
        }
5405 7973
        let subjectTy = autoDeref(parentTy);
5406 7974
5407 -
        if let case Type::TraitObject { traitInfo, mutable: objMutable, .. } = subjectTy {
7975 +
        if let case Type::Parameter(param) = subjectTy; param.bounds.len > 0 {
7976 +
            let methodName = try nodeName(self, access.child);
7977 +
            let selected = try findGenericBoundMethod(
7978 +
                self, access.child, param, methodName
7979 +
            );
7980 +
            let case Type::Fn(info) = calleeTy
7981 +
                else throw emitError(self, call.callee, ErrorKind::Internal);
7982 +
            if selected.method.mutable {
7983 +
                let mut isMutPtr = false;
7984 +
                if let case Type::Pointer(pointer) = parentTy {
7985 +
                    set isMutPtr = pointer.mutable;
7986 +
                }
7987 +
                if not isMutPtr and not (try canBorrowMutFrom(self, access.parent)) {
7988 +
                    throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
7989 +
                }
7990 +
            }
7991 +
            try checkUnsafeCall(self, call.callee, info);
7992 +
            try checkCallArgs(self, node, call, info, ctx);
7993 +
            setGenericBoundMethodCall(
7994 +
                self,
7995 +
                node,
7996 +
                param,
7997 +
                selected.traitInfo,
7998 +
                selected.method.index,
7999 +
                false,
8000 +
            );
8001 +
            return setNodeType(self, node, *info.returnType);
8002 +
        }
8003 +
8004 +
        if let case Type::TraitObject(traitObject) = subjectTy {
5408 8005
            let methodName = try nodeName(self, access.child);
5409 -
            let method = findTraitMethod(traitInfo, methodName)
8006 +
            let method = findTraitMethod(traitObject.traitInfo, methodName)
5410 8007
                else throw emitError(self, access.child, ErrorKind::RecordFieldUnknown(methodName));
5411 8008
            // Reject mutable-receiver methods called on immutable trait objects.
5412 -
            if method.mutable and not objMutable {
8009 +
            if method.mutable and not traitObject.mutable {
5413 8010
                throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
5414 8011
            }
5415 8012
            try checkCallArgs(self, node, call, method.fnType, ctx);
5416 -
            setTraitMethodCall(self, node, traitInfo, method.index);
8013 +
            setTraitMethodCall(self, node, traitObject.traitInfo, method.index);
5417 8014
            return setNodeType(self, node, *method.fnType.returnType);
5418 8015
        }
5419 8016
5420 8017
        // Check for a standalone method call on a concrete type.
5421 8018
        if let case Type::Nominal(_) = subjectTy {
5424 8021
                // Reject mutable-receiver methods on immutable bindings.
5425 8022
                // If the parent is already a mutable pointer, the receiver is fine.
5426 8023
                // Otherwise, check that the parent can yield a mutable borrow.
5427 8024
                if method.mutable {
5428 8025
                    let mut isMutPtr = false;
5429 -
                    if let case Type::Pointer { mutable, .. } = parentTy {
5430 -
                        set isMutPtr = mutable;
8026 +
                    if let case Type::Pointer(pointer) = parentTy {
8027 +
                        set isMutPtr = pointer.mutable;
5431 8028
                    }
5432 8029
                    if not isMutPtr and not (try canBorrowMutFrom(self, access.parent)) {
5433 8030
                        throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
5434 8031
                    }
5435 8032
                }
5525 8122
            try checkSliceRangeIndices(self, range);
5526 8123
5527 8124
            let mut item: *Type = undefined;
5528 8125
            let mut capacity: ?u32 = nil;
5529 8126
5530 -
            if let case Type::Slice { item: sliceItem, mutable: sliceMutable, .. } = subjectTy {
5531 -
                if not sliceMutable {
8127 +
            if let case Type::Slice(slice) = subjectTy {
8128 +
                if not slice.mutable {
5532 8129
                    throw emitError(self, container, ErrorKind::ImmutableBinding);
5533 8130
                }
5534 -
                set item = sliceItem;
8131 +
                set item = slice.item;
5535 8132
            } else {
5536 8133
                match subjectTy {
5537 8134
                    case Type::Array(a) => {
5538 8135
                        try validateArraySliceBounds(self, range, a.length, node);
5539 8136
                        set item = a.item;
5542 8139
                    else => throw emitError(self, container, ErrorKind::ExpectedIndexable),
5543 8140
                }
5544 8141
            }
5545 8142
            // RHS is either a fill value or a source slice.
5546 8143
            let rhsTy = try infer(self, assign.right);
5547 -
            if let case Type::Slice { item: sourceItem, .. } = rhsTy {
5548 -
                if *sourceItem <> *item {
8144 +
            if let case Type::Slice(source) = rhsTy {
8145 +
                if *source.item <> *item {
5549 8146
                    throw emitTypeMismatch(
5550 8147
                        self,
5551 8148
                        assign.right,
5552 -
                        TypeMismatch { expected: *item, actual: *sourceItem },
8149 +
                        TypeMismatch { expected: *item, actual: *source.item },
5553 8150
                    );
5554 8151
                }
5555 8152
            } else {
5556 8153
                try checkAssignable(self, assign.right, *item);
5557 8154
            }
5649 8246
    if isUnsafePointerType(containerTy) {
5650 8247
        try requireUnsafe(self, container);
5651 8248
    }
5652 8249
    try checkIndex(self, indexNode);
5653 8250
    let subjectTy = autoDeref(containerTy);
5654 -
    if let case Type::Slice { item, .. } = subjectTy {
5655 -
        return setNodeType(self, node, *item);
8251 +
    if let case Type::Slice(slice) = subjectTy {
8252 +
        return setNodeType(self, node, *slice.item);
5656 8253
    }
5657 8254
5658 8255
    match subjectTy {
5659 8256
        case Type::Array(arrayInfo) => {
5660 8257
            return setNodeType(self, node, *arrayInfo.item);
5661 8258
        }
8259 +
        case Type::GenericArray { item, .. } => {
8260 +
            return setNodeType(self, node, *item);
8261 +
        }
5662 8262
        else => {
5663 8263
            throw emitError(self, container, ErrorKind::ExpectedIndexable);
5664 8264
        }
5665 8265
    }
5666 8266
}
5733 8333
    // Check if this is a scope access that might be a union variant.
5734 8334
    if let case ast::NodeValue::ScopeAccess(access) = typeIdent.value {
5735 8335
        let sym = try resolveAccess(self, typeIdent, access, self.scope);
5736 8336
5737 8337
        // Check if resolved symbol is a union variant.
5738 -
        if let case SymbolData::Variant { type, decl, ordinal, index } = sym.data {
5739 -
            // Get the union type from the variant's declaration.
5740 -
            let declSym = symbolFor(self, decl)
8338 +
        if let case SymbolData::Variant { type, ordinal, index, .. } = sym.data {
8339 +
            let resolved = typeFor(self, typeIdent)
5741 8340
                else throw emitError(self, node, ErrorKind::Internal);
5742 -
            let case SymbolData::Type(unionNominalType) = declSym.data
8341 +
            let case Type::Nominal(unionNominalType) = resolved
5743 8342
                else throw emitError(self, node, ErrorKind::Internal);
5744 8343
5745 8344
            // Get the variant's payload type.
5746 8345
            let case Type::Nominal(payloadInfo) = type
5747 8346
                else throw emitError(self, node, ErrorKind::ExpectedRecord);
5922 8521
    throws (ResolveError)
5923 8522
{
5924 8523
    let mut itemHint = hint;
5925 8524
    if let case Type::Array(ary) = hint {
5926 8525
        set itemHint = *ary.item;
8526 +
    } else if let case Type::GenericArray { item, .. } = hint {
8527 +
        set itemHint = *item;
5927 8528
    } else if let case Type::Optional(inner) = hint {
5928 8529
        if let case Type::Array(ary) = *inner {
5929 8530
            set itemHint = *ary.item;
5930 8531
        }
5931 8532
    }
5932 8533
    let valueTy = try visit(self, lit.item, itemHint);
5933 -
    let count = try checkSizeInt(self, lit.count);
5934 -
    let arrayTy = Type::Array(ArrayType {
5935 -
        item: allocType(self, valueTy),
5936 -
        length: count,
5937 -
    });
8534 +
    let _ = try checkNumeric(self, lit.count);
8535 +
    let mut arrayTy: Type = undefined;
8536 +
    if let value = constValueEntry(self, lit.count) {
8537 +
        if not validateConstIntRange(value, Type::U32) {
8538 +
            throw emitError(self, lit.count, ErrorKind::NumericLiteralOverflow);
8539 +
        }
8540 +
        let case ConstValue::Int(int) = value
8541 +
            else throw emitError(self, lit.count, ErrorKind::ConstExprRequired);
8542 +
        set arrayTy = Type::Array(ArrayType {
8543 +
            item: allocType(self, valueTy),
8544 +
            length: int.magnitude as u32,
8545 +
        });
8546 +
    } else if isConstExpr(self, lit.count) and
8547 +
              containsGenericConstExpr(self, lit.count)
8548 +
    {
8549 +
        set arrayTy = Type::GenericArray {
8550 +
            item: allocType(self, valueTy),
8551 +
            length: lit.count,
8552 +
        };
8553 +
    } else {
8554 +
        throw emitError(self, lit.count, ErrorKind::ConstExprRequired);
8555 +
    }
5938 8556
    return setNodeType(self, node, arrayTy);
5939 8557
}
5940 8558
5941 8559
/// Resolve union variant access.
5942 8560
fn resolveUnionVariantAccess(
5973 8591
    let sym = try resolveAccess(self, node, access, self.scope);
5974 8592
    let mut ty: Type = undefined;
5975 8593
5976 8594
    match sym.data {
5977 8595
        case SymbolData::Value { type, .. } => {
8596 +
            if isGenericDeclaration(sym.node) {
8597 +
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
8598 +
            }
5978 8599
            setNodeSymbol(self, node, sym);
5979 8600
            set ty = type;
5980 8601
        }
5981 8602
        case SymbolData::Constant { type, value } => {
5982 8603
            // Propagate the constant value.
5985 8606
            }
5986 8607
            setNodeSymbol(self, node, sym);
5987 8608
            set ty = type;
5988 8609
        }
5989 8610
        case SymbolData::Type(t) => {
8611 +
            if isGenericDeclaration(sym.node) {
8612 +
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
8613 +
            }
5990 8614
            setNodeSymbol(self, node, sym);
5991 8615
            set ty = Type::Nominal(t);
5992 8616
        }
8617 +
        case SymbolData::TypeParameter(param) => {
8618 +
            set *param.used = true;
8619 +
            setNodeSymbol(self, node, sym);
8620 +
            set ty = Type::Parameter(param);
8621 +
        }
8622 +
        case SymbolData::ConstParameter(param) => {
8623 +
            set *param.used = true;
8624 +
            setNodeSymbol(self, node, sym);
8625 +
            let constType = param.constType
8626 +
                else throw emitError(self, node, ErrorKind::Internal);
8627 +
            set ty = *constType;
8628 +
        }
5993 8629
        case SymbolData::Variant { index, .. } => {
5994 8630
            let ty = typeFor(self, node)
5995 8631
                else throw emitError(self, node, ErrorKind::Internal);
5996 8632
            // For unions without payload, store the variant index as a constant.
5997 8633
            if isVoidUnion(ty) {
6012 8648
        }
6013 8649
    }
6014 8650
    return setNodeType(self, node, ty);
6015 8651
}
6016 8652
8653 +
/// A uniquely selected method exposed by a generic parameter bound.
8654 +
record GenericBoundMethod {
8655 +
    traitInfo: *TraitType,
8656 +
    method: *TraitMethod,
8657 +
}
8658 +
8659 +
/// Find one bound method, rejecting ambiguous unqualified selections.
8660 +
fn findGenericBoundMethod(
8661 +
    self: *mut Resolver,
8662 +
    node: *ast::Node,
8663 +
    param: *GenericParamType,
8664 +
    name: *[u8],
8665 +
) -> GenericBoundMethod throws (ResolveError) {
8666 +
    let mut found: ?GenericBoundMethod = nil;
8667 +
    for bound in param.bounds {
8668 +
        if let method = findTraitMethod(bound, name) {
8669 +
            if found <> nil {
8670 +
                throw emitError(self, node, ErrorKind::GenericBoundAmbiguous(name));
8671 +
            }
8672 +
            set found = GenericBoundMethod { traitInfo: bound, method };
8673 +
        }
8674 +
    }
8675 +
    let result = found else throw emitError(
8676 +
        self, node, ErrorKind::RecordFieldUnknown(name)
8677 +
    );
8678 +
    return result;
8679 +
}
8680 +
6017 8681
/// Analyze a field access expression.
6018 8682
fn resolveFieldAccess(self: *mut Resolver, node: *ast::Node, access: ast::Access) -> Type
6019 8683
    throws (ResolveError)
6020 8684
{
6021 8685
    let parentTy = try infer(self, access.parent);
6022 8686
    if isUnsafePointerType(parentTy) {
6023 8687
        try requireUnsafe(self, access.parent);
6024 8688
    }
6025 8689
    let subjectTy = autoDeref(parentTy);
6026 -
    if let case Type::Slice { class, item, mutable } = subjectTy {
8690 +
    if let case Type::Slice(slice) = subjectTy {
6027 8691
        let fieldNode = access.child;
6028 8692
        let fieldName = try nodeName(self, fieldNode);
6029 8693
        if mem::eq(fieldName, PTR_FIELD) {
6030 8694
            setRecordFieldIndex(self, fieldNode, 0);
6031 8695
            return setNodeType(
6032 8696
                self,
6033 8697
                node,
6034 -
                Type::Pointer { class, target: item, mutable },
8698 +
                Type::Pointer(PointerType {
8699 +
                    class: slice.class,
8700 +
                    target: slice.item,
8701 +
                    mutable: slice.mutable,
8702 +
                }),
6035 8703
            );
6036 8704
        }
6037 8705
        if mem::eq(fieldName, LEN_FIELD) {
6038 8706
            setRecordFieldIndex(self, fieldNode, 1);
6039 8707
            return setNodeType(self, node, Type::U32);
6042 8710
            setRecordFieldIndex(self, fieldNode, 2);
6043 8711
            return setNodeType(self, node, Type::U32);
6044 8712
        }
6045 8713
        throw emitError(self, node, ErrorKind::SliceFieldUnknown(fieldName));
6046 8714
    }
6047 -
    if let case Type::TraitObject { traitInfo, .. } = subjectTy {
8715 +
    if let case Type::TraitObject(traitObject) = subjectTy {
6048 8716
        let fieldName = try nodeName(self, access.child);
6049 -
        let method = findTraitMethod(traitInfo, fieldName)
8717 +
        let method = findTraitMethod(traitObject.traitInfo, fieldName)
6050 8718
            else throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
6051 8719
        return setNodeType(self, node, Type::Fn(method.fnType));
6052 8720
    }
6053 8721
6054 8722
    match subjectTy {
8723 +
        case Type::Parameter(param) if param.bounds.len > 0 => {
8724 +
            let fieldName = try nodeName(self, access.child);
8725 +
            let selected = try findGenericBoundMethod(
8726 +
                self, access.child, param, fieldName
8727 +
            );
8728 +
            let selfParam: [*GenericParamType; 1] = [selected.method.owner.selfType];
8729 +
            let selfArg: [*Type; 1] = [allocType(self, Type::Parameter(param))];
8730 +
            let sub = Substitution {
8731 +
                params: &selfParam[..],
8732 +
                args: &selfArg[..],
8733 +
            };
8734 +
            let methodType = try substituteType(
8735 +
                self, Type::Fn(selected.method.fnType), &sub, node
8736 +
            );
8737 +
            return setNodeType(self, node, methodType);
8738 +
        }
8739 +
        case Type::GenericDataApply(application) => {
8740 +
            let template = genericTemplateFor(self, application.template)
8741 +
                else throw emitError(self, node, ErrorKind::Internal);
8742 +
            let case ast::NodeValue::RecordDecl(decl) = application.template.node.value
8743 +
                else throw emitError(self, access.parent, ErrorKind::ExpectedRecord);
8744 +
            let fieldName = try nodeName(self, access.child);
8745 +
            for fieldNode, index in decl.fields {
8746 +
                let case ast::NodeValue::RecordField { field: maybeField, .. } =
8747 +
                    fieldNode.value
8748 +
                    else throw emitError(self, node, ErrorKind::Internal);
8749 +
                let fieldNodeName = maybeField
8750 +
                    else throw emitError(self, fieldNode, ErrorKind::Internal);
8751 +
                let candidate = try nodeName(self, fieldNodeName);
8752 +
                if mem::eq(candidate, fieldName) {
8753 +
                    let sub = Substitution {
8754 +
                        params: template.params,
8755 +
                        args: application.args,
8756 +
                    };
8757 +
                    let fieldType = try substituteType(
8758 +
                        self, *template.members[index], &sub, node
8759 +
                    );
8760 +
                    setRecordFieldIndex(self, access.child, index);
8761 +
                    return setNodeType(self, node, fieldType);
8762 +
                }
8763 +
            }
8764 +
            throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
8765 +
        }
6055 8766
        case Type::Nominal(NominalType::Record(recordType)) => {
6056 8767
            let fieldNode = access.child;
6057 8768
            let fieldName = try nodeName(self, fieldNode);
6058 8769
            if let fieldIndex = findRecordField(&recordType, fieldName) {
6059 8770
                let fieldTy = recordType.fields[fieldIndex].fieldType;
6076 8787
6077 8788
                return setNodeType(self, node, Type::U32);
6078 8789
            }
6079 8790
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
6080 8791
        }
6081 -
8792 +
        case Type::GenericArray { .. } => {
8793 +
            let fieldName = try nodeName(self, access.child);
8794 +
            if mem::eq(fieldName, LEN_FIELD) {
8795 +
                return setNodeType(self, node, Type::U32);
8796 +
            }
8797 +
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
8798 +
        }
6082 8799
        else => {
6083 8800
            // Check for standalone methods on any nominal type (e.g. unions).
6084 8801
            if let case Type::Nominal(_) = subjectTy {
6085 8802
                let fieldName = try nodeName(self, access.child);
6086 8803
                if let method = findMethod(self, subjectTy, fieldName) {
6106 8823
            if mutable {
6107 8824
                return true;
6108 8825
            }
6109 8826
            // Check if the type is a mutable pointer or slice.
6110 8827
            let ty = typeFor(self, node) else return false;
6111 -
            if let case Type::Pointer { mutable, .. } = ty {
6112 -
                return mutable;
8828 +
            if let case Type::Pointer(pointer) = ty {
8829 +
                return pointer.mutable;
6113 8830
            }
6114 -
            if let case Type::Slice { mutable, .. } = ty {
6115 -
                return mutable;
8831 +
            if let case Type::Slice(slice) = ty {
8832 +
                return slice.mutable;
6116 8833
            }
6117 8834
            return false;
6118 8835
        }
6119 8836
        case ast::NodeValue::FieldAccess(access) => {
6120 8837
            let _ = try infer(self, access.parent);
6135 8852
        case ast::NodeValue::Subscript { container, .. } => {
6136 8853
            let containerTy = try infer(self, container);
6137 8854
            // Subscript auto-derefs pointers, so check the actual indexed type.
6138 8855
            let subjectTy = autoDeref(containerTy);
6139 8856
6140 -
            if let case Type::Slice { mutable, .. } = subjectTy {
6141 -
                return mutable;
8857 +
            if let case Type::Slice(slice) = subjectTy {
8858 +
                return slice.mutable;
6142 8859
            }
6143 8860
            if let case Type::Array(_) = subjectTy {
6144 8861
                return try canBorrowMutFrom(self, container);
6145 8862
            }
6146 8863
            return false;
6152 8869
        }
6153 8870
        case ast::NodeValue::Call(_) => {
6154 8871
            // A call returning `*mut T` (or `&mut [T]`) yields a
6155 8872
            // mutable place. Non-pointer returns cannot be mutably borrowed.
6156 8873
            let ty = try infer(self, node);
6157 -
            if let case Type::Pointer { mutable, .. } = ty {
6158 -
                return mutable;
8874 +
            if let case Type::Pointer(pointer) = ty {
8875 +
                return pointer.mutable;
6159 8876
            }
6160 -
            if let case Type::Slice { mutable, .. } = ty {
6161 -
                return mutable;
8877 +
            if let case Type::Slice(slice) = ty {
8878 +
                return slice.mutable;
6162 8879
            }
6163 8880
            return false;
6164 8881
        }
6165 8882
        case ast::NodeValue::Deref(inner) => {
6166 8883
            let innerTy = try infer(self, inner);
6167 8884
6168 -
            if let case Type::Pointer { mutable, .. } = innerTy {
6169 -
                return mutable;
8885 +
            if let case Type::Pointer(pointer) = innerTy {
8886 +
                return pointer.mutable;
6170 8887
            }
6171 -
            if let case Type::Slice { mutable, .. } = innerTy {
6172 -
                return mutable;
8888 +
            if let case Type::Slice(slice) = innerTy {
8889 +
                return slice.mutable;
6173 8890
            }
6174 8891
            // Record deref: mutability depends on the inner binding.
6175 8892
            if let case Type::Nominal(NominalType::Record(recInfo)) = innerTy {
6176 8893
                if not recInfo.labeled and recInfo.fields.len == 1 {
6177 8894
                    return try canBorrowMutFrom(self, inner);
6207 8924
            try checkSliceRangeIndices(self, range);
6208 8925
6209 8926
            let mut item: *Type = undefined;
6210 8927
            let mut capacity: ?u32 = nil;
6211 8928
6212 -
            if let case Type::Slice { item: sliceItem, mutable: sliceMutable, .. } = subjectTy {
6213 -
                if addr.mutable and not sliceMutable {
8929 +
            if let case Type::Slice(slice) = subjectTy {
8930 +
                if addr.mutable and not slice.mutable {
6214 8931
                    throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
6215 8932
                }
6216 -
                set item = sliceItem;
8933 +
                set item = slice.item;
6217 8934
            } else {
6218 8935
                match subjectTy {
6219 8936
                    case Type::Array(arrayInfo) => {
6220 8937
                        try validateArraySliceBounds(self, range, arrayInfo.length, node);
6221 8938
                        set item = arrayInfo.item;
6224 8941
                    else => {
6225 8942
                        throw emitError(self, container, ErrorKind::ExpectedIndexable);
6226 8943
                    }
6227 8944
                }
6228 8945
            }
6229 -
            let sliceTy = Type::Slice { class, item, mutable: addr.mutable };
8946 +
            let sliceTy = Type::Slice(SliceType {
8947 +
                class,
8948 +
                item,
8949 +
                mutable: addr.mutable,
8950 +
            });
6230 8951
            let alloc = allocType(self, sliceTy);
6231 8952
            setSliceRangeInfo(self, node, SliceRangeInfo {
6232 8953
                itemType: item,
6233 8954
                mutable: addr.mutable,
6234 8955
                capacity,
6237 8958
            return setNodeType(self, node, *alloc);
6238 8959
        }
6239 8960
    }
6240 8961
    // Derive a hint for the target type from the slice hint.
6241 8962
    let mut targetHint: Type = Type::Unknown;
6242 -
    if let case Type::Slice { item, .. } = hint {
6243 -
        set targetHint = Type::Array(ArrayType { item, length: 0 });
8963 +
    if let case Type::Slice(slice) = hint {
8964 +
        set targetHint = Type::Array(ArrayType { item: slice.item, length: 0 });
6244 8965
    }
6245 8966
    let targetTy = try visit(self, addr.target, targetHint);
6246 8967
6247 8968
    // Mark local variable symbols as address-taken so the lowerer
6248 8969
    // allocates a stack slot eagerly.
6260 8981
    if let case Type::Array(arrayInfo) = targetTy {
6261 8982
        match addr.target.value {
6262 8983
            case ast::NodeValue::ArrayLit(_),
6263 8984
                 ast::NodeValue::ArrayRepeatLit(_) =>
6264 8985
            {
6265 -
                let sliceTy = Type::Slice { class, item: arrayInfo.item, mutable: addr.mutable };
8986 +
                let sliceTy = Type::Slice(SliceType {
8987 +
                    class,
8988 +
                    item: arrayInfo.item,
8989 +
                    mutable: addr.mutable,
8990 +
                });
6266 8991
                return setNodeType(self, node, *allocType(self, sliceTy));
6267 8992
            }
6268 8993
            else => {}
6269 8994
        }
6270 8995
    }
6271 -
    let pointerTy = Type::Pointer {
6272 -
        class, target: allocType(self, targetTy), mutable: addr.mutable,
6273 -
    };
8996 +
    let pointerTy = Type::Pointer(PointerType {
8997 +
        class,
8998 +
        target: allocType(self, targetTy),
8999 +
        mutable: addr.mutable,
9000 +
    });
6274 9001
    return setNodeType(self, node, pointerTy);
6275 9002
}
6276 9003
6277 9004
/// Analyze a dereference expression.
6278 9005
fn resolveDeref(self: *mut Resolver, node: *ast::Node, targetNode: *ast::Node, hint: Type) -> Type
6279 9006
    throws (ResolveError)
6280 9007
{
6281 9008
    let operandTy = try visit(self, targetNode, hint);
6282 -
    if let case Type::Pointer { class, target, .. } = operandTy {
6283 -
        if class == types::PointerClass::Unsafe {
9009 +
    if let case Type::Pointer(pointer) = operandTy {
9010 +
        if pointer.class == types::PointerClass::Unsafe {
6284 9011
            try requireUnsafe(self, targetNode);
6285 9012
        }
6286 9013
        // Disallow dereferencing opaque pointers.
6287 -
        if *target == Type::Opaque {
9014 +
        if *pointer.target == Type::Opaque {
6288 9015
            throw emitError(self, targetNode, ErrorKind::OpaqueTypeDeref);
6289 9016
        }
6290 -
        return setNodeType(self, node, *target);
9017 +
        return setNodeType(self, node, *pointer.target);
6291 9018
    }
6292 9019
    // Auto-deref for single-field unlabeled records.
6293 9020
    if let case Type::Nominal(NominalType::Record(recInfo)) = operandTy {
6294 9021
        if not recInfo.labeled and recInfo.fields.len == 1 {
6295 9022
            let fieldTy = recInfo.fields[0].fieldType;
6300 9027
    throw emitError(self, targetNode, ErrorKind::ExpectedPointer);
6301 9028
}
6302 9029
6303 9030
/// Check if a type is a pointer to opaque.
6304 9031
fn isOpaquePointer(ty: Type) -> bool {
6305 -
    if let case Type::Pointer { target, .. } = ty {
6306 -
        return *target == Type::Opaque;
9032 +
    if let case Type::Pointer(pointer) = ty {
9033 +
        return *pointer.target == Type::Opaque;
6307 9034
    }
6308 9035
    return false;
6309 9036
}
6310 9037
6311 9038
/// Check if a type is an opaque slice.
6312 9039
fn isOpaqueSlice(ty: Type) -> bool {
6313 -
    if let case Type::Slice { item, .. } = ty {
6314 -
        return *item == Type::Opaque;
9040 +
    if let case Type::Slice(slice) = ty {
9041 +
        return *slice.item == Type::Opaque;
6315 9042
    }
6316 9043
    return false;
6317 9044
}
6318 9045
6319 9046
/// Check if an `as` cast between two types is valid.
6330 9057
    // TODO: Check that variant index fits in target type.
6331 9058
    if isVoidUnion(source) and isNumericType(target) {
6332 9059
        return true;
6333 9060
    }
6334 9061
    // Allow address to numeric.
6335 -
    if let case Type::Slice { .. } = source {
9062 +
    if let case Type::Slice(_) = source {
6336 9063
        // Disallow slice to numeric; slices are fat pointers.
6337 9064
    } else if isAddressType(source) and isNumericType(target) {
6338 9065
        return true;
6339 9066
    }
6340 9067
    // Allow pointer casts if one side is `*opaque` or target types are castable.
6341 -
    if let case Type::Pointer {
6342 -
        class: sourceClass, target: sourceTarget, mutable: sourceMutable,
6343 -
    } = source {
6344 -
        if let case Type::Pointer {
6345 -
            class: targetClass, target: targetTarget, mutable: targetMutable,
6346 -
        } = target {
6347 -
            if sourceClass <> targetClass {
9068 +
    if let case Type::Pointer(sourcePointer) = source {
9069 +
        if let case Type::Pointer(targetPointer) = target {
9070 +
            if sourcePointer.class <> targetPointer.class {
6348 9071
                return false;
6349 9072
            }
6350 -
            if targetMutable and not sourceMutable {
9073 +
            if targetPointer.mutable and not sourcePointer.mutable {
6351 9074
                return false;
6352 9075
            }
6353 9076
            if isOpaquePointer(source) or isOpaquePointer(target) {
6354 9077
                return true;
6355 9078
            }
6356 -
            return isValidCast(*sourceTarget, *targetTarget);
9079 +
            return isValidCast(*sourcePointer.target, *targetPointer.target);
6357 9080
        }
6358 9081
    }
6359 9082
    // Allow slice casts if one side is `*[opaque]`, target is `*[u8]`,
6360 9083
    // or element types are castable.
6361 -
    if let case Type::Slice {
6362 -
        class: sourceClass, item: sourceItem, mutable: sourceMutable,
6363 -
    } = source {
6364 -
        if let case Type::Slice {
6365 -
            class: targetClass, item: targetItem, mutable: targetMutable,
6366 -
        } = target {
6367 -
            if sourceClass <> targetClass {
9084 +
    if let case Type::Slice(sourceSlice) = source {
9085 +
        if let case Type::Slice(targetSlice) = target {
9086 +
            if sourceSlice.class <> targetSlice.class {
6368 9087
                return false;
6369 9088
            }
6370 -
            if targetMutable and not sourceMutable {
9089 +
            if targetSlice.mutable and not sourceSlice.mutable {
6371 9090
                return false;
6372 9091
            }
6373 9092
            if isOpaqueSlice(source) or isOpaqueSlice(target) {
6374 9093
                return true;
6375 9094
            }
6376 -
            if *targetItem == Type::U8 {
9095 +
            if *targetSlice.item == Type::U8 {
6377 9096
                return true;
6378 9097
            }
6379 -
            return isValidCast(*sourceItem, *targetItem);
9098 +
            return isValidCast(*sourceSlice.item, *targetSlice.item);
6380 9099
        }
6381 9100
    }
6382 9101
    return false;
6383 9102
}
6384 9103
6394 9113
6395 9114
    assert sourceTy <> Type::Unknown;
6396 9115
    assert targetTy <> Type::Unknown;
6397 9116
6398 9117
    let mut valid = isValidCast(sourceTy, targetTy);
6399 -
    if let case Type::Pointer {
6400 -
        class: sourceClass, target: sourceTarget, mutable: sourceMutable,
6401 -
    } = sourceTy {
6402 -
        if let case Type::Pointer {
6403 -
            class: targetClass, target: targetTarget, mutable: targetMutable,
6404 -
        } = targetTy {
6405 -
            if sourceClass == types::PointerClass::Ref and
6406 -
               targetClass == types::PointerClass::Unsafe and
6407 -
               (not targetMutable or sourceMutable) and
6408 -
               isValidCast(*sourceTarget, *targetTarget)
9118 +
    if let case Type::Pointer(sourcePointer) = sourceTy {
9119 +
        if let case Type::Pointer(targetPointer) = targetTy {
9120 +
            if sourcePointer.class == types::PointerClass::Ref and
9121 +
               targetPointer.class == types::PointerClass::Unsafe and
9122 +
               (not targetPointer.mutable or sourcePointer.mutable) and
9123 +
               isValidCast(*sourcePointer.target, *targetPointer.target)
6409 9124
            {
6410 9125
                set valid = true;
6411 9126
            }
6412 9127
        }
6413 9128
    }
6414 -
    if let case Type::Slice {
6415 -
        class: sourceClass, item: sourceItem, mutable: sourceMutable,
6416 -
    } = sourceTy {
6417 -
        if let case Type::Slice {
6418 -
            class: targetClass, item: targetItem, mutable: targetMutable,
6419 -
        } = targetTy {
6420 -
            if sourceClass == types::PointerClass::Ref and
6421 -
               targetClass == types::PointerClass::Unsafe and
6422 -
               (not targetMutable or sourceMutable) and
6423 -
               isValidCast(*sourceItem, *targetItem)
9129 +
    if let case Type::Slice(sourceSlice) = sourceTy {
9130 +
        if let case Type::Slice(targetSlice) = targetTy {
9131 +
            if sourceSlice.class == types::PointerClass::Ref and
9132 +
               targetSlice.class == types::PointerClass::Unsafe and
9133 +
               (not targetSlice.mutable or sourceSlice.mutable) and
9134 +
               isValidCast(*sourceSlice.item, *targetSlice.item)
6424 9135
            {
6425 9136
                set valid = true;
6426 9137
            }
6427 9138
        }
6428 9139
    }
6484 9195
    throws (ResolveError)
6485 9196
{
6486 9197
    let call = tryExpr.expr;
6487 9198
    let case ast::NodeValue::Call(callExpr) = call.value
6488 9199
        else throw emitError(self, call, ErrorKind::TryNonThrowing);
6489 -
    let resultTy = try resolveCall(self, call, callExpr, CallCtx::Try);
9200 +
    let resultTy = try resolveCall(
9201 +
        self, call, callExpr, CallCtx::Try, hint
9202 +
    );
6490 9203
6491 9204
    // TODO: It's annoying that we need to re-fetch the function type after
6492 9205
    // analyzing the call.
6493 9206
    let calleeTy = typeFor(self, callExpr.callee)
6494 9207
        else return setNodeType(self, node, resultTy);
6783 9496
            return ConstValue::Bool(l > r if signed else left.magnitude > right.magnitude),
6784 9497
        case ast::BinaryOp::Lte =>
6785 9498
            return ConstValue::Bool(l <= r if signed else left.magnitude <= right.magnitude),
6786 9499
        case ast::BinaryOp::Gte =>
6787 9500
            return ConstValue::Bool(l >= r if signed else left.magnitude >= right.magnitude),
6788 -
        case ast::BinaryOp::Add => return ConstValue::Int(constIntFromSigned(l + r, bits, signed)),
6789 -
        case ast::BinaryOp::Sub => return ConstValue::Int(constIntFromSigned(l - r, bits, signed)),
6790 -
        case ast::BinaryOp::Mul => return ConstValue::Int(constIntFromSigned(l * r, bits, signed)),
9501 +
        case ast::BinaryOp::Add => {
9502 +
            if not signed {
9503 +
                return ConstValue::Int(
9504 +
                    constIntFromBits(left.magnitude + right.magnitude, bits, false)
9505 +
                );
9506 +
            }
9507 +
            return ConstValue::Int(constIntFromSigned(l + r, bits, true));
9508 +
        },
9509 +
        case ast::BinaryOp::Sub => {
9510 +
            if not signed {
9511 +
                return ConstValue::Int(
9512 +
                    constIntFromBits(left.magnitude - right.magnitude, bits, false)
9513 +
                );
9514 +
            }
9515 +
            return ConstValue::Int(constIntFromSigned(l - r, bits, true));
9516 +
        },
9517 +
        case ast::BinaryOp::Mul => {
9518 +
            if not signed {
9519 +
                return ConstValue::Int(
9520 +
                    constIntFromBits(left.magnitude * right.magnitude, bits, false)
9521 +
                );
9522 +
            }
9523 +
            return ConstValue::Int(constIntFromSigned(l * r, bits, true));
9524 +
        },
6791 9525
        case ast::BinaryOp::Div => {
6792 9526
            if signed {
6793 9527
                if r == 0 {
6794 9528
                    return nil;
6795 9529
                }
9530 +
                if l == parser::I64_MIN and r == -1 {
9531 +
                    return ConstValue::Int(
9532 +
                        constIntFromBits(parser::I64_MIN as u64, bits, true)
9533 +
                    );
9534 +
                }
6796 9535
                return ConstValue::Int(constIntFromSigned(l / r, bits, true));
6797 9536
            }
6798 9537
            if right.magnitude == 0 {
6799 9538
                return nil;
6800 9539
            }
6803 9542
        case ast::BinaryOp::Mod => {
6804 9543
            if signed {
6805 9544
                if r == 0 {
6806 9545
                    return nil;
6807 9546
                }
9547 +
                if l == parser::I64_MIN and r == -1 {
9548 +
                    return ConstValue::Int(
9549 +
                        constIntFromBits(0, bits, true)
9550 +
                    );
9551 +
                }
6808 9552
                return ConstValue::Int(constIntFromSigned(l % r, bits, true));
6809 9553
            }
6810 9554
            if right.magnitude == 0 {
6811 9555
                return nil;
6812 9556
            }
6813 9557
            return constInt(left.magnitude % right.magnitude, bits, false, false);
6814 9558
        },
6815 -
        case ast::BinaryOp::BitAnd => return ConstValue::Int(constIntFromSigned(l & r, bits, signed)),
6816 -
        case ast::BinaryOp::BitOr  => return ConstValue::Int(constIntFromSigned(l | r, bits, signed)),
6817 -
        case ast::BinaryOp::BitXor => return ConstValue::Int(constIntFromSigned(l ^ r, bits, signed)),
9559 +
        case ast::BinaryOp::BitAnd => return ConstValue::Int(
9560 +
            constIntFromBits(constIntToBits(left) & constIntToBits(right), bits, signed)
9561 +
        ),
9562 +
        case ast::BinaryOp::BitOr => return ConstValue::Int(
9563 +
            constIntFromBits(constIntToBits(left) | constIntToBits(right), bits, signed)
9564 +
        ),
9565 +
        case ast::BinaryOp::BitXor => return ConstValue::Int(
9566 +
            constIntFromBits(constIntToBits(left) ^ constIntToBits(right), bits, signed)
9567 +
        ),
6818 9568
        else => return nil,
6819 9569
    }
6820 9570
}
6821 9571
6822 9572
/// Try to constant-fold a binary operation on two resolved operands.
6905 9655
                let leftTy = try infer(self, binop.left);
6906 9656
                let rightTy = try visit(self, binop.right, leftTy);
6907 9657
6908 9658
                // Allow arithmetic on owning pointers and unsafe pointers, but
6909 9659
                // never on references.
6910 -
                if let case Type::Pointer { class: leftClass, target: leftTarget, .. } = leftTy {
6911 -
                    if *leftTarget == Type::Opaque {
9660 +
                if let case Type::Pointer(leftPointer) = leftTy {
9661 +
                    if *leftPointer.target == Type::Opaque {
6912 9662
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
6913 9663
                    }
6914 -
                    if leftClass <> types::PointerClass::Ref
9664 +
                    if leftPointer.class <> types::PointerClass::Ref
6915 9665
                        and isNumericType(rightTy)
6916 9666
                    {
6917 -
                        if leftClass == types::PointerClass::Unsafe {
9667 +
                        if leftPointer.class == types::PointerClass::Unsafe {
6918 9668
                            try requireUnsafe(self, node);
6919 9669
                        }
6920 9670
                        return setNodeType(self, node, leftTy);
6921 9671
                    }
6922 9672
                }
6923 -
                if let case Type::Pointer { class: rightClass, target: rightTarget, .. } = rightTy {
6924 -
                    if *rightTarget == Type::Opaque {
9673 +
                if let case Type::Pointer(rightPointer) = rightTy {
9674 +
                    if *rightPointer.target == Type::Opaque {
6925 9675
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
6926 9676
                    }
6927 9677
                    if binop.op == ast::BinaryOp::Add
6928 -
                        and rightClass <> types::PointerClass::Ref
9678 +
                        and rightPointer.class <> types::PointerClass::Ref
6929 9679
                        and isNumericType(leftTy)
6930 9680
                    {
6931 -
                        if rightClass == types::PointerClass::Unsafe {
9681 +
                        if rightPointer.class == types::PointerClass::Unsafe {
6932 9682
                            try requireUnsafe(self, node);
6933 9683
                        }
6934 9684
                        return setNodeType(self, node, rightTy);
6935 9685
                    }
6936 9686
                }
7011 9761
    };
7012 9762
    return setNodeType(self, node, resultTy);
7013 9763
}
7014 9764
7015 9765
9766 +
7016 9767
/// Resolve a type signature node and set its type.
7017 9768
fn inferTypeSig(self: *mut Resolver, node: *ast::Node, sig: ast::TypeSig) -> Type
7018 9769
    throws (ResolveError)
7019 9770
{
7020 9771
    let resolved = try resolveTypeSig(self, node, sig);
7054 9805
7055 9806
            return Type::Array(ArrayType { item: allocType(self, item), length });
7056 9807
        }
7057 9808
        case ast::TypeSig::Slice { class, itemType, mutable } => {
7058 9809
            let item = try infer(self, itemType);
7059 -
            return Type::Slice {
9810 +
            return Type::Slice(SliceType {
7060 9811
                class,
7061 9812
                item: allocType(self, item),
7062 9813
                mutable,
7063 -
            };
9814 +
            });
7064 9815
        }
7065 9816
        case ast::TypeSig::Pointer { class, valueType, mutable } => {
7066 9817
            let target = try infer(self, valueType);
7067 -
            return Type::Pointer {
9818 +
            return Type::Pointer(PointerType {
7068 9819
                class,
7069 9820
                target: allocType(self, target),
7070 9821
                mutable,
7071 -
            };
9822 +
            });
7072 9823
        }
7073 9824
        case ast::TypeSig::Optional { valueType } => {
7074 9825
            let payload = try infer(self, valueType);
7075 9826
            return Type::Optional(allocType(self, payload));
7076 9827
        }
7077 9828
        case ast::TypeSig::Nominal(name) => {
9829 +
            if let case ast::NodeValue::Ident(paramName) = name.value {
9830 +
                if mem::eq(paramName, "Self") {
9831 +
                    let selfType = self.currentTraitSelf else {
9832 +
                        throw emitError(
9833 +
                            self, name, ErrorKind::UnresolvedSymbol(paramName)
9834 +
                        );
9835 +
                    };
9836 +
                    set *selfType.used = true;
9837 +
                    return Type::Parameter(selfType);
9838 +
                }
9839 +
                let sym = findTypeSymbol(self.scope, paramName) else {
9840 +
                    throw emitError(self, name, ErrorKind::UnresolvedSymbol(paramName));
9841 +
                };
9842 +
                match sym.data {
9843 +
                    case SymbolData::Type(ty) => {
9844 +
                        if isGenericDeclaration(sym.node) {
9845 +
                            throw emitError(self, name, ErrorKind::GenericArgumentsRequired);
9846 +
                        }
9847 +
                        setNodeSymbol(self, name, sym);
9848 +
                        return Type::Nominal(ty);
9849 +
                    }
9850 +
                    case SymbolData::TypeParameter(param) => {
9851 +
                        set *param.used = true;
9852 +
                        setNodeSymbol(self, name, sym);
9853 +
                        return Type::Parameter(param);
9854 +
                    }
9855 +
                    else => throw emitError(self, name, ErrorKind::Internal),
9856 +
                }
9857 +
            }
7078 9858
            let ty = try resolveTypeName(self, name);
7079 9859
            return Type::Nominal(ty);
7080 9860
        }
7081 9861
        case ast::TypeSig::Record { fields, labeled } => {
7082 9862
            let recordType = try resolveRecordFields(self, node, fields, labeled);
7128 9908
        // Resolve an opaque trait object signature.
7129 9909
        case ast::TypeSig::TraitObject { class, traitName, mutable } => {
7130 9910
            let sym = try resolveNamePath(self, traitName);
7131 9911
            let case SymbolData::Trait(traitInfo) = sym.data
7132 9912
                else throw emitError(self, traitName, ErrorKind::Internal);
9913 +
            if traitInfo.state == TraitState::Queued {
9914 +
                let case ast::NodeValue::TraitDecl { supertraits, methods, .. } = sym.node.value
9915 +
                    else throw emitError(self, traitName, ErrorKind::Internal);
9916 +
                try resolveTraitBody(self, sym.node, supertraits, methods);
9917 +
            }
9918 +
            if not traitInfo.objectSafe {
9919 +
                throw emitError(self, traitName, ErrorKind::TraitNotObjectSafe);
9920 +
            }
7133 9921
            setNodeSymbol(self, traitName, sym);
7134 -
            return Type::TraitObject { class, traitInfo, mutable };
9922 +
            return Type::TraitObject(TraitObjectType { class, traitInfo, mutable });
7135 9923
        }
7136 9924
    }
7137 9925
}
7138 9926
7139 9927
/// Check if a type can be used for inferrence.
7140 9928
fn isTypeInferrable(type: Type) -> bool {
7141 -
    if let case Type::Pointer { target, .. } = type {
7142 -
        return isTypeInferrable(*target);
9929 +
    if let case Type::Pointer(pointer) = type {
9930 +
        return isTypeInferrable(*pointer.target);
7143 9931
    }
7144 9932
    match type {
7145 9933
        case Type::Unknown, Type::Nil, Type::Undefined, Type::Int => return false,
7146 9934
        case Type::Array(ary) => return isTypeInferrable(*ary.item),
7147 9935
        case Type::Optional(opt) => return isTypeInferrable(*opt),
7185 9973
        return Diagnostics { errors: self.errors };
7186 9974
    };
7187 9975
    exitScope(self);
7188 9976
    setNodeType(self, root, Type::Void);
7189 9977
9978 +
    try closeGenericFnSpecializations(self) catch {
9979 +
        return Diagnostics { errors: self.errors };
9980 +
    };
9981 +
    try validateGenericDataRoots(self) catch {
9982 +
        return Diagnostics { errors: self.errors };
9983 +
    };
7190 9984
    return Diagnostics { errors: self.errors };
7191 9985
}
7192 9986
7193 9987
/// Analyze the module graph. This pass processes `mod` statements, creating symbols
7194 9988
/// and scopes for them, and also binds type names in each module so that cross-module
7231 10025
/// Resolve all type bodies in a module.
7232 10026
fn resolveTypeBodies(self: *mut Resolver, block: *ast::Block) throws (ResolveError) {
7233 10027
    for node in block.statements {
7234 10028
        match node.value {
7235 10029
            case ast::NodeValue::RecordDecl(decl) => {
7236 -
                try resolveRecordBody(self, node, decl) catch {
7237 -
                    // Continue resolving other types even if one fails.
7238 -
                };
10030 +
                if decl.params.len > 0 {
10031 +
                    try resolveGenericDataTemplate(
10032 +
                        self, node, decl.params, decl.fields, decl.derives, true,
10033 +
                    ) catch {};
10034 +
                } else {
10035 +
                    try resolveRecordBody(self, node, decl) catch {
10036 +
                        // Continue resolving other types even if one fails.
10037 +
                    };
10038 +
                }
7239 10039
            }
7240 10040
            case ast::NodeValue::UnionDecl(decl) => {
7241 -
                try resolveUnionBody(self, node, decl) catch {
7242 -
                    // Continue resolving other types even if one fails.
7243 -
                };
10041 +
                if decl.params.len > 0 {
10042 +
                    try resolveGenericDataTemplate(
10043 +
                        self, node, decl.params, decl.variants, decl.derives, false,
10044 +
                    ) catch {};
10045 +
                } else {
10046 +
                    try resolveUnionBody(self, node, decl) catch {
10047 +
                        // Continue resolving other types even if one fails.
10048 +
                    };
10049 +
                }
7244 10050
            }
7245 10051
            case ast::NodeValue::TraitDecl { supertraits, methods, .. } => {
7246 10052
                try resolveTraitBody(self, node, supertraits, methods) catch {
7247 10053
                    // Continue resolving other types even if one fails.
7248 10054
                };
7476 10282
        case ast::NodeValue::AddressOf(addr) => return linearRootSymbol(self, addr.target),
7477 10283
        case ast::NodeValue::FieldAccess(access) =>
7478 10284
            return linearRootSymbol(self, access.parent),
7479 10285
        case ast::NodeValue::Subscript { container, .. } =>
7480 10286
            return linearRootSymbol(self, container),
10287 +
        case ast::NodeValue::GenericApply(_) => return nil,
7481 10288
        case ast::NodeValue::Deref(target) => return linearRootSymbol(self, target),
7482 10289
        else => return nil,
7483 10290
    }
7484 10291
}
7485 10292
7725 10532
                let method = &traitInfo.methods[methodIndex];
7726 10533
                set receiverClass = method.receiverClass;
7727 10534
                set receiverMutable = method.mutable;
7728 10535
                set haveReceiver = true;
7729 10536
            }
10537 +
            case NodeExtra::GenericBoundMethodCall {
10538 +
                traitInfo, methodIndex, explicitReceiver, ..
10539 +
            } => {
10540 +
                if not explicitReceiver {
10541 +
                    let method = &traitInfo.methods[methodIndex];
10542 +
                    set receiverClass = method.receiverClass;
10543 +
                    set receiverMutable = method.mutable;
10544 +
                    set haveReceiver = true;
10545 +
                }
10546 +
            }
7730 10547
            case NodeExtra::MethodCall { method } => {
7731 10548
                set receiverClass = method.receiverClass;
7732 10549
                set receiverMutable = method.mutable;
7733 10550
                set haveReceiver = true;
7734 10551
            }
7754 10571
7755 10572
    for arg, i in call.args {
7756 10573
        let expected = *info.paramTypes[i];
7757 10574
        let root = linearRootSymbol(checker.resolver, arg);
7758 10575
        let mut argExclusive = isLinear(expected);
7759 -
        if let case Type::Pointer { class: types::PointerClass::Ref, mutable, .. } = expected {
10576 +
        if let case Type::Pointer(PointerType { class: types::PointerClass::Ref, mutable, .. }) = expected {
7760 10577
            set argExclusive = mutable;
7761 -
        } else if let case Type::Slice { class: types::PointerClass::Ref, mutable, .. } = expected {
10578 +
        } else if let case Type::Slice(SliceType {
10579 +
            class: types::PointerClass::Ref, mutable, ..
10580 +
        }) = expected {
7762 10581
            set argExclusive = mutable;
7763 -
        } else if let case Type::TraitObject {
10582 +
        } else if let case Type::TraitObject(TraitObjectType {
7764 10583
            class: types::PointerClass::Ref, mutable, ..
7765 -
        } = expected {
10584 +
        }) = expected {
7766 10585
            set argExclusive = mutable;
7767 10586
        }
7768 10587
        if not isUnsafePointerType(expected) {
7769 10588
            if let rootSym = root {
7770 10589
                for j in 0..rootsLen {
7928 10747
                }
7929 10748
            }
7930 10749
            try checkLinearNode(checker, env, container, LinearUse::Observe);
7931 10750
            try checkLinearNode(checker, env, index, LinearUse::Consume);
7932 10751
        }
10752 +
        case ast::NodeValue::GenericApply(_) => {
10753 +
            let extra = checker.resolver.nodeData.entries[node.id].extra;
10754 +
            if let case NodeExtra::GenericFnCall(_) = extra {
10755 +
                return;
10756 +
            }
10757 +
            if let case NodeExtra::GenericFnDependency(_) = extra {
10758 +
                return;
10759 +
            }
10760 +
            throw emitError(checker.resolver, node, ErrorKind::Internal);
10761 +
        }
7933 10762
        case ast::NodeValue::RecordLit(lit) => {
7934 10763
            for fieldNode in lit.fields {
7935 10764
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
7936 10765
                    else panic "checkLinearNode: expected field";
7937 10766
                try checkLinearNode(checker, env, field.value, LinearUse::Consume);
8290 11119
        let pkg = &packages[i];
8291 11120
        let diags = try resolvePackage(self, pkg.rootEntry, pkg.rootAst);
8292 11121
        if not success(&diags) {
8293 11122
            return diags;
8294 11123
        }
11124 +
        try closeGenericFnSpecializations(self) catch {
11125 +
            return Diagnostics { errors: self.errors };
11126 +
        };
8295 11127
    }
11128 +
    // Data roots are validated after every package has had a chance to provide
11129 +
    // an explicit root for a shared specialization.
11130 +
    try validateGenericDataRoots(self) catch {
11131 +
        return Diagnostics { errors: self.errors };
11132 +
    };
8296 11133
    return Diagnostics { errors: self.errors };
8297 11134
}
8298 11135
8299 11136
/// Resolve a package.
8300 11137
fn resolvePackage(self: *mut Resolver, rootEntry: *module::ModuleEntry, node: *ast::Node) -> Diagnostics throws (ResolveError) {
8303 11140
        else panic "resolvePackage: module scope not found";
8304 11141
8305 11142
    // Set up the module scope for this package.
8306 11143
    set self.scope = scope;
8307 11144
    set self.currentMod = rootId;
11145 +
    set self.genericRoots = 0;
11146 +
    set self.genericSpecializationCount = 0;
8308 11147
8309 11148
    let case ast::NodeValue::Block(block) = node.value
8310 11149
        else panic "resolvePackage: expected block for module root";
8311 11150
8312 11151
    // 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 +949 -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
    {
5697 5746
    let mut a = testResolver();
5698 5747
    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(); }";
5699 5748
    let result = try resolveProgramStr(&mut a, program);
5700 5749
    try expectErrorKind(&result, super::ErrorKind::UnsafeCall);
5701 5750
}
5751 +
5752 +
/// Generic declarations retain rigid parameter identities and resolved bounds.
5753 +
@test fn testGenericTemplateMetadata() throws (testing::TestError) {
5754 +
    let mut a = testResolver();
5755 +
    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; }";
5756 +
    let result = try resolveProgramStr(&mut a, program);
5757 +
    try expectNoErrors(&result);
5758 +
    let case ast::NodeValue::Block(block) = result.root.value
5759 +
        else throw testing::TestError::Failed;
5760 +
5761 +
    let boxSym = super::symbolFor(&a, block.statements[1])
5762 +
        else throw testing::TestError::Failed;
5763 +
    let boxTemplate = super::genericTemplateFor(&a, boxSym)
5764 +
        else throw testing::TestError::Failed;
5765 +
    assert boxTemplate.params.len == 1;
5766 +
    assert boxTemplate.params[0].bounds.len == 1;
5767 +
    assert boxTemplate.members.len == 1;
5768 +
    let case super::Type::Parameter(boxField) = *boxTemplate.members[0]
5769 +
        else throw testing::TestError::Failed;
5770 +
    assert boxField == boxTemplate.params[0];
5771 +
5772 +
    let maybeSym = super::symbolFor(&a, block.statements[2])
5773 +
        else throw testing::TestError::Failed;
5774 +
    let maybeTemplate = super::genericTemplateFor(&a, maybeSym)
5775 +
        else throw testing::TestError::Failed;
5776 +
    assert maybeTemplate.members.len == 3;
5777 +
    assert *maybeTemplate.members[0] == super::Type::Void;
5778 +
    let case super::Type::GenericRecord(payload) = *maybeTemplate.members[1]
5779 +
        else throw testing::TestError::Failed;
5780 +
    assert payload.fields.len == 1;
5781 +
    let case super::Type::Parameter(someType) = payload.fields[0].fieldType
5782 +
        else throw testing::TestError::Failed;
5783 +
    assert someType == maybeTemplate.params[0];
5784 +
    let concrete = super::allocType(&mut a, super::Type::U8);
5785 +
    let args: [*super::Type; 1] = [concrete];
5786 +
    let sub = super::Substitution { params: maybeTemplate.params, args: &args[..] };
5787 +
    let codeType = try super::substituteType(
5788 +
        &mut a, *maybeTemplate.members[2], &sub, block.statements[2]
5789 +
    ) catch {
5790 +
        throw testing::TestError::Failed;
5791 +
    };
5792 +
    let case super::Type::Nominal(super::NominalType::Record(codeRecord)) = codeType
5793 +
        else throw testing::TestError::Failed;
5794 +
    assert codeRecord.layout.size == 4;
5795 +
5796 +
    let fnSym = super::symbolFor(&a, block.statements[3])
5797 +
        else throw testing::TestError::Failed;
5798 +
    let fnTemplate = super::genericTemplateFor(&a, fnSym)
5799 +
        else throw testing::TestError::Failed;
5800 +
    let signature = fnTemplate.signature else throw testing::TestError::Failed;
5801 +
    let case super::Type::Parameter(argType) = *signature.paramTypes[0]
5802 +
        else throw testing::TestError::Failed;
5803 +
    let case super::Type::Parameter(returnType) = *signature.returnType
5804 +
        else throw testing::TestError::Failed;
5805 +
    assert argType == fnTemplate.params[0];
5806 +
    assert returnType == fnTemplate.params[0];
5807 +
}
5808 +
5809 +
/// Symbolic aggregate members retain rigid types through nested wrappers.
5810 +
@test fn testGenericNestedMemberTypes() throws (testing::TestError) {
5811 +
    let mut a = testResolver();
5812 +
    let result = try resolveProgramStr(
5813 +
        &mut a,
5814 +
        "union Wrapped⟨T⟩ { List([T; 2]), Maybe(?T), Apply(fn(T) -> T) }",
5815 +
    );
5816 +
    try expectNoErrors(&result);
5817 +
    let case ast::NodeValue::Block(block) = result.root.value
5818 +
        else throw testing::TestError::Failed;
5819 +
    let sym = super::symbolFor(&a, block.statements[0])
5820 +
        else throw testing::TestError::Failed;
5821 +
    let template = super::genericTemplateFor(&a, sym)
5822 +
        else throw testing::TestError::Failed;
5823 +
    assert template.members.len == 3;
5824 +
    for member in template.members {
5825 +
        assert super::containsGenericParameter(*member);
5826 +
    }
5827 +
    let concrete = super::allocType(&mut a, super::Type::U16);
5828 +
    let args: [*super::Type; 1] = [concrete];
5829 +
    let sub = super::Substitution { params: template.params, args: &args[..] };
5830 +
    for member in template.members {
5831 +
        let specialized = try super::substituteType(
5832 +
            &mut a, *member, &sub, block.statements[0]
5833 +
        ) catch {
5834 +
            throw testing::TestError::Failed;
5835 +
        };
5836 +
        let case super::Type::Nominal(super::NominalType::Record(_)) = specialized
5837 +
            else throw testing::TestError::Failed;
5838 +
    }
5839 +
}
5840 +
5841 +
/// Generic function signatures preserve rigid types inside compound types.
5842 +
@test fn testGenericNestedFunctionSignatureTypes() throws (testing::TestError) {
5843 +
    let mut a = testResolver();
5844 +
    let result = try resolveProgramStr(
5845 +
        &mut a,
5846 +
        "fn transform⟨T⟩(values: [T; 2], callback: fn(T) -> T) -> ?T { return nil; }",
5847 +
    );
5848 +
    try expectNoErrors(&result);
5849 +
    let case ast::NodeValue::Block(block) = result.root.value
5850 +
        else throw testing::TestError::Failed;
5851 +
    let sym = super::symbolFor(&a, block.statements[0])
5852 +
        else throw testing::TestError::Failed;
5853 +
    let template = super::genericTemplateFor(&a, sym)
5854 +
        else throw testing::TestError::Failed;
5855 +
    let signature = template.signature else throw testing::TestError::Failed;
5856 +
    assert signature.paramTypes.len == 2;
5857 +
    assert super::containsGenericParameter(*signature.paramTypes[0]);
5858 +
    assert super::containsGenericParameter(*signature.paramTypes[1]);
5859 +
    assert super::containsGenericParameter(*signature.returnType);
5860 +
}
5861 +
5862 +
/// Rigid parameters from separate declarations never compare as the same type.
5863 +
@test fn testGenericParameterIdentityIsDeclarationScoped() throws (testing::TestError) {
5864 +
    let mut a = testResolver();
5865 +
    let result = try resolveProgramStr(
5866 +
        &mut a,
5867 +
        "fn first⟨T⟩(value: T) -> T { return value; } fn second⟨T⟩(value: T) -> T { return value; }",
5868 +
    );
5869 +
    try expectNoErrors(&result);
5870 +
    let case ast::NodeValue::Block(block) = result.root.value
5871 +
        else throw testing::TestError::Failed;
5872 +
    let first = super::symbolFor(&a, block.statements[0])
5873 +
        else throw testing::TestError::Failed;
5874 +
    let second = super::symbolFor(&a, block.statements[1])
5875 +
        else throw testing::TestError::Failed;
5876 +
    let firstTemplate = super::genericTemplateFor(&a, first)
5877 +
        else throw testing::TestError::Failed;
5878 +
    let secondTemplate = super::genericTemplateFor(&a, second)
5879 +
        else throw testing::TestError::Failed;
5880 +
    assert firstTemplate.params[0] <> secondTemplate.params[0];
5881 +
    assert not super::typesEqual(
5882 +
        super::Type::Parameter(firstTemplate.params[0]),
5883 +
        super::Type::Parameter(secondTemplate.params[0]),
5884 +
    );
5885 +
}
5886 +
5887 +
/// Substitution recursively rewrites rigid parameters through composed types.
5888 +
@test fn testGenericTypeSubstitution() throws (testing::TestError) {
5889 +
    let mut a = testResolver();
5890 +
    let result = try resolveProgramStr(&mut a, "fn id⟨T⟩(value: T) -> T { return value; }");
5891 +
    try expectNoErrors(&result);
5892 +
    let case ast::NodeValue::Block(block) = result.root.value
5893 +
        else throw testing::TestError::Failed;
5894 +
    let sym = super::symbolFor(&a, block.statements[0])
5895 +
        else throw testing::TestError::Failed;
5896 +
    let template = super::genericTemplateFor(&a, sym)
5897 +
        else throw testing::TestError::Failed;
5898 +
    let rigid = super::Type::Parameter(template.params[0]);
5899 +
    let pointer = super::Type::Pointer(super::PointerType {
5900 +
        class: types::PointerClass::Owned,
5901 +
        target: super::allocType(&mut a, rigid),
5902 +
        mutable: true,
5903 +
    });
5904 +
    let symbolic = super::Type::Optional(super::allocType(&mut a, pointer));
5905 +
    let concrete = super::allocType(&mut a, super::Type::U32);
5906 +
    let args: [*super::Type; 1] = [concrete];
5907 +
    let sub = super::Substitution { params: template.params, args: &args[..] };
5908 +
    let replaced = try super::substituteType(
5909 +
        &mut a, symbolic, &sub, block.statements[0]
5910 +
    ) catch {
5911 +
        throw testing::TestError::Failed;
5912 +
    };
5913 +
    let case super::Type::Optional(inner) = replaced
5914 +
        else throw testing::TestError::Failed;
5915 +
    let case super::Type::Pointer(super::PointerType {
5916 +
        class: types::PointerClass::Owned, target, mutable
5917 +
    }) = *inner
5918 +
        else throw testing::TestError::Failed;
5919 +
    assert mutable;
5920 +
    assert *target == super::Type::U32;
5921 +
}
5922 +
5923 +
/// Duplicate generic parameter names are rejected in their declaration scope.
5924 +
@test fn testDuplicateGenericParameterRejected() throws (testing::TestError) {
5925 +
    let mut a = testResolver();
5926 +
    let result = try resolveProgramStr(&mut a, "fn duplicate⟨T, T⟩(value: T) {}");
5927 +
    let err = try expectError(&result);
5928 +
    let case super::ErrorKind::DuplicateBinding(name) = err.kind
5929 +
        else throw testing::TestError::Failed;
5930 +
    assert mem::eq(name, "T");
5931 +
}
5932 +
5933 +
/// Generic bounds must resolve to trait declarations.
5934 +
@test fn testGenericBoundMustBeTrait() throws (testing::TestError) {
5935 +
    let mut a = testResolver();
5936 +
    let result = try resolveProgramStr(
5937 +
        &mut a,
5938 +
        "record Value {} fn invalid⟨T: Value⟩(value: T) {}",
5939 +
    );
5940 +
    try expectErrorKind(&result, super::ErrorKind::GenericBoundNotTrait);
5941 +
}
5942 +
5943 +
/// Integer constant parameters specialize array layouts.
5944 +
@test fn testGenericConstParameterArrayLayout() throws (testing::TestError) {
5945 +
    let mut a = testResolver();
5946 +
    let result = try resolveProgramStr(
5947 +
        &mut a,
5948 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } instantiate Buffer⟨4⟩;",
5949 +
    );
5950 +
    try expectNoErrors(&result);
5951 +
    let case ast::NodeValue::Block(block) = result.root.value
5952 +
        else throw testing::TestError::Failed;
5953 +
    let case ast::NodeValue::Instantiate(applications) = block.statements[1].value
5954 +
        else throw testing::TestError::Failed;
5955 +
    let resolved = super::typeFor(&a, applications[0])
5956 +
        else throw testing::TestError::Failed;
5957 +
    let case super::Type::Nominal(nominal) = resolved
5958 +
        else throw testing::TestError::Failed;
5959 +
    let case super::NominalType::Record(recordType) = *nominal
5960 +
        else throw testing::TestError::Failed;
5961 +
    let case super::Type::Array(arrayType) = recordType.fields[0].fieldType
5962 +
        else throw testing::TestError::Failed;
5963 +
    assert arrayType.length == 4;
5964 +
    assert recordType.layout.size == 4;
5965 +
}
5966 +
5967 +
/// Equivalent integer expressions share a canonical specialization.
5968 +
@test fn testGenericConstParameterCanonical() throws (testing::TestError) {
5969 +
    let mut a = testResolver();
5970 +
    let result = try resolveProgramStr(
5971 +
        &mut a,
5972 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } instantiate Buffer⟨4⟩; instantiate Buffer⟨2 + 2⟩; instantiate Buffer⟨5⟩;",
5973 +
    );
5974 +
    try expectNoErrors(&result);
5975 +
    let case ast::NodeValue::Block(block) = result.root.value
5976 +
        else throw testing::TestError::Failed;
5977 +
    let case ast::NodeValue::Instantiate(firstApplications) = block.statements[1].value
5978 +
        else throw testing::TestError::Failed;
5979 +
    let case ast::NodeValue::Instantiate(equalApplications) = block.statements[2].value
5980 +
        else throw testing::TestError::Failed;
5981 +
    let case ast::NodeValue::Instantiate(otherApplications) = block.statements[3].value
5982 +
        else throw testing::TestError::Failed;
5983 +
    let firstType = super::typeFor(&a, firstApplications[0])
5984 +
        else throw testing::TestError::Failed;
5985 +
    let equalType = super::typeFor(&a, equalApplications[0])
5986 +
        else throw testing::TestError::Failed;
5987 +
    let otherType = super::typeFor(&a, otherApplications[0])
5988 +
        else throw testing::TestError::Failed;
5989 +
    let case super::Type::Nominal(first) = firstType
5990 +
        else throw testing::TestError::Failed;
5991 +
    let case super::Type::Nominal(equal) = equalType
5992 +
        else throw testing::TestError::Failed;
5993 +
    let case super::Type::Nominal(other) = otherType
5994 +
        else throw testing::TestError::Failed;
5995 +
    assert first == equal;
5996 +
    assert first <> other;
5997 +
}
5998 +
5999 +
/// Constant parameter declarations accept only concrete integer types.
6000 +
@test fn testGenericConstParameterTypeRejected() throws (testing::TestError) {
6001 +
    let mut a = testResolver();
6002 +
    let result = try resolveProgramStr(&mut a, "record Buffer⟨constant N: bool⟩ {}");
6003 +
    try expectErrorKind(&result, super::ErrorKind::GenericConstUnsupported);
6004 +
}
6005 +
6006 +
/// Constant arguments must be side-effect-free compile-time expressions.
6007 +
@test fn testGenericConstArgumentRequired() throws (testing::TestError) {
6008 +
    let mut a = testResolver();
6009 +
    let result = try resolveProgramStr(
6010 +
        &mut a,
6011 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } fn size() -> u32 { return 4; } instantiate Buffer⟨size()⟩;",
6012 +
    );
6013 +
    try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
6014 +
}
6015 +
6016 +
/// Constant arguments are checked against their declared integer width.
6017 +
@test fn testGenericConstArgumentOverflow() throws (testing::TestError) {
6018 +
    let mut a = testResolver();
6019 +
    let result = try resolveProgramStr(
6020 +
        &mut a,
6021 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } instantiate Buffer⟨4294967296⟩;",
6022 +
    );
6023 +
    try expectErrorKind(&result, super::ErrorKind::NumericLiteralOverflow);
6024 +
}
6025 +
6026 +
/// Constant parameters reject type-valued arguments.
6027 +
@test fn testGenericConstArgumentKindRejected() throws (testing::TestError) {
6028 +
    let mut a = testResolver();
6029 +
    let result = try resolveProgramStr(
6030 +
        &mut a,
6031 +
        "record Buffer⟨constant N: u32⟩ { data: [u8; N] } instantiate Buffer⟨u32⟩;",
6032 +
    );
6033 +
    try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
6034 +
}
6035 +
6036 +
/// Type parameters reject expression arguments.
6037 +
@test fn testGenericTypeArgumentKindRejected() throws (testing::TestError) {
6038 +
    let mut a = testResolver();
6039 +
    let result = try resolveProgramStr(
6040 +
        &mut a, "record Box⟨T⟩ { value: T } instantiate Box⟨4⟩;"
6041 +
    );
6042 +
    try expectErrorKind(&result, super::ErrorKind::GenericUnsupported);
6043 +
}
6044 +
6045 +
/// Generic declarations reject parameter lists beyond the implementation limit.
6046 +
@test fn testGenericParameterLimit() throws (testing::TestError) {
6047 +
    let mut a = testResolver();
6048 +
    let result = try resolveProgramStr(
6049 +
        &mut a,
6050 +
        "record TooMany⟨A, B, C, D, E, F, G, H, I⟩ {}",
6051 +
    );
6052 +
    try expectErrorKind(&result, super::ErrorKind::GenericParameterLimit);
6053 +
}
6054 +
6055 +
/// Rigid parameters cannot escape the declaration that introduces them.
6056 +
@test fn testGenericParameterOutsideTemplateUnresolved() throws (testing::TestError) {
6057 +
    let mut a = testResolver();
6058 +
    let result = try resolveProgramStr(&mut a, "fn invalid(value: T) {}");
6059 +
    let err = try expectError(&result);
6060 +
    let case super::ErrorKind::UnresolvedSymbol(name) = err.kind
6061 +
        else throw testing::TestError::Failed;
6062 +
    assert mem::eq(name, "T");
6063 +
}
6064 +
6065 +
/// Layout-dependent builtins reject symbolic generic types.
6066 +
@test fn testGenericParameterLayoutRejected() throws (testing::TestError) {
6067 +
    let mut a = testResolver();
6068 +
    let result = try resolveProgramStr(
6069 +
        &mut a,
6070 +
        "record Sized⟨T⟩ { bytes: u32 = @sizeOf(T) }",
6071 +
    );
6072 +
    try expectErrorKind(&result, super::ErrorKind::GenericLayoutRequired);
6073 +
}
6074 +
6075 +
/// Generic data declarations cannot be used without specialization arguments.
6076 +
@test fn testGenericArgumentsRequired() throws (testing::TestError) {
6077 +
    let mut a = testResolver();
6078 +
    let result = try resolveProgramStr(
6079 +
        &mut a,
6080 +
        "record Box⟨T⟩ { value: T } fn invalid(value: Box) {}",
6081 +
    );
6082 +
    try expectErrorKind(&result, super::ErrorKind::GenericArgumentsRequired);
6083 +
}
6084 +
6085 +
/// Repeated concrete data applications share one canonical nominal type.
6086 +
@test fn testGenericDataSpecializationCanonical() throws (testing::TestError) {
6087 +
    let mut a = testResolver();
6088 +
    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⟩;";
6089 +
    let result = try resolveProgramStr(&mut a, program);
6090 +
    try expectNoErrors(&result);
6091 +
    let case ast::NodeValue::Block(block) = result.root.value
6092 +
        else throw testing::TestError::Failed;
6093 +
    let case ast::NodeValue::Instantiate(firstApplications) = block.statements[3].value
6094 +
        else throw testing::TestError::Failed;
6095 +
    let case ast::NodeValue::Instantiate(secondApplications) = block.statements[4].value
6096 +
        else throw testing::TestError::Failed;
6097 +
    let case ast::NodeValue::Instantiate(reversedApplications) = block.statements[5].value
6098 +
        else throw testing::TestError::Failed;
6099 +
    let firstType = super::typeFor(&a, firstApplications[0])
6100 +
        else throw testing::TestError::Failed;
6101 +
    let secondType = super::typeFor(&a, secondApplications[0])
6102 +
        else throw testing::TestError::Failed;
6103 +
    let reversedType = super::typeFor(&a, reversedApplications[0])
6104 +
        else throw testing::TestError::Failed;
6105 +
    let case super::Type::Nominal(first) = firstType
6106 +
        else throw testing::TestError::Failed;
6107 +
    let case super::Type::Nominal(second) = secondType
6108 +
        else throw testing::TestError::Failed;
6109 +
    let case super::Type::Nominal(reversed) = reversedType
6110 +
        else throw testing::TestError::Failed;
6111 +
    assert first == second;
6112 +
    assert first <> reversed;
6113 +
    let case super::NominalType::Record(recordType) = *first
6114 +
        else throw testing::TestError::Failed;
6115 +
    assert recordType.fields.len == 2;
6116 +
    assert recordType.layout.size == 8;
6117 +
    let pairSym = super::symbolFor(&a, block.statements[0])
6118 +
        else throw testing::TestError::Failed;
6119 +
    let args: [*super::Type; 2] = [
6120 +
        super::allocType(&mut a, super::Type::I32),
6121 +
        super::allocType(&mut a, super::Type::Bool),
6122 +
    ];
6123 +
    let cached = super::findGenericDataSpecialization(&a, pairSym, &args[..])
6124 +
        else throw testing::TestError::Failed;
6125 +
    assert *cached.rooted;
6126 +
}
6127 +
6128 +
/// Recursive applications reuse the in-progress canonical specialization.
6129 +
@test fn testGenericDataRecursiveSpecialization() throws (testing::TestError) {
6130 +
    let mut a = testResolver();
6131 +
    let result = try resolveProgramStr(
6132 +
        &mut a,
6133 +
        "record List⟨T⟩ { value: T, next: ?*List⟨T⟩ } instantiate List⟨i32⟩;",
6134 +
    );
6135 +
    try expectNoErrors(&result);
6136 +
    let case ast::NodeValue::Block(block) = result.root.value
6137 +
        else throw testing::TestError::Failed;
6138 +
    let case ast::NodeValue::Instantiate(applications) = block.statements[1].value
6139 +
        else throw testing::TestError::Failed;
6140 +
    let resolved = super::typeFor(&a, applications[0])
6141 +
        else throw testing::TestError::Failed;
6142 +
    let case super::Type::Nominal(listType) = resolved
6143 +
        else throw testing::TestError::Failed;
6144 +
    let case super::NominalType::Record(recordType) = *listType
6145 +
        else throw testing::TestError::Failed;
6146 +
    let case super::Type::Optional(optionalTarget) = recordType.fields[1].fieldType
6147 +
        else throw testing::TestError::Failed;
6148 +
    let case super::Type::Pointer(super::PointerType {
6149 +
        class: types::PointerClass::Owned, target, ..
6150 +
    }) = *optionalTarget
6151 +
        else throw testing::TestError::Failed;
6152 +
    let case super::Type::Nominal(nextType) = *target
6153 +
        else throw testing::TestError::Failed;
6154 +
    assert nextType == listType;
6155 +
}
6156 +
6157 +
/// Generic data applications diagnose arity before specialization.
6158 +
@test fn testGenericDataSpecializationArity() throws (testing::TestError) {
6159 +
    let mut a = testResolver();
6160 +
    let result = try resolveProgramStr(
6161 +
        &mut a,
6162 +
        "record Pair⟨T, U⟩ { first: T, second: U } instantiate Pair⟨i32⟩;",
6163 +
    );
6164 +
    let err = try expectError(&result);
6165 +
    let case super::ErrorKind::GenericArgumentCount(mismatch) = err.kind
6166 +
        else throw testing::TestError::Failed;
6167 +
    assert mismatch.expected == 2;
6168 +
    assert mismatch.actual == 1;
6169 +
}
6170 +
6171 +
/// By-value recursive specializations are rejected instead of recursing.
6172 +
@test fn testGenericDataRecursiveLayoutRejected() throws (testing::TestError) {
6173 +
    let mut a = testResolver();
6174 +
    let result = try resolveProgramStr(
6175 +
        &mut a,
6176 +
        "record Loop⟨T⟩ { next: Loop⟨T⟩ } instantiate Loop⟨i32⟩;",
6177 +
    );
6178 +
    try expectErrorKind(&result, super::ErrorKind::GenericRecursiveLayout);
6179 +
}
6180 +
6181 +
/// Concrete applications outside templates require an explicit root.
6182 +
@test fn testGenericDataInstantiationRequired() throws (testing::TestError) {
6183 +
    let mut a = testResolver();
6184 +
    let result = try resolveProgramStr(
6185 +
        &mut a,
6186 +
        "record Box⟨T⟩ { value: T } fn read(value: Box⟨i32⟩) -> i32 { return value.value; }",
6187 +
    );
6188 +
    try expectErrorKind(&result, super::ErrorKind::GenericInstantiationRequired);
6189 +
}
6190 +
6191 +
/// Substitution cannot introduce a stored reference into a generic record.
6192 +
@test fn testGenericRecordReferenceArgumentRejected() throws (testing::TestError) {
6193 +
    let mut a = testResolver();
6194 +
    let result = try resolveProgramStr(
6195 +
        &mut a,
6196 +
        "record Box⟨T⟩ { value: T } instantiate Box⟨&i32⟩;",
6197 +
    );
6198 +
    try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
6199 +
}
6200 +
6201 +
/// Substitution cannot introduce a stored reference into a generic union.
6202 +
@test fn testGenericUnionReferenceArgumentRejected() throws (testing::TestError) {
6203 +
    let mut a = testResolver();
6204 +
    let result = try resolveProgramStr(
6205 +
        &mut a,
6206 +
        "union Maybe⟨T⟩ { None, Some(T) } instantiate Maybe⟨&i32⟩;",
6207 +
    );
6208 +
    try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition);
6209 +
}
6210 +
6211 +
/// Roots traverse ordinary nominal containers to reach generic dependencies.
6212 +
@test fn testGenericDataRootThroughOrdinaryNominal() throws (testing::TestError) {
6213 +
    let mut a = testResolver();
6214 +
    let result = try resolveProgramStr(
6215 +
        &mut a,
6216 +
        "record Box⟨T⟩ { value: T } record Holder { value: Box⟨i32⟩ } record Root⟨T⟩ { value: T } instantiate Root⟨Holder⟩;",
6217 +
    );
6218 +
    try expectNoErrors(&result);
6219 +
}
6220 +
6221 +
/// Function instantiation roots create a concrete specialization.
6222 +
@test fn testGenericFunctionSpecializationRoot() throws (testing::TestError) {
6223 +
    let mut a = testResolver();
6224 +
    let result = try resolveProgramStr(
6225 +
        &mut a,
6226 +
        "fn id⟨T⟩(value: T) -> T { return value; } instantiate id⟨i32⟩;",
6227 +
    );
6228 +
    try expectNoErrors(&result);
6229 +
    let node = super::genericFnSpecializations(&a)
6230 +
        else throw testing::TestError::Failed;
6231 +
    assert node.specialization.args.len == 1;
6232 +
    assert *node.specialization.args[0] == super::Type::I32;
6233 +
}
6234 +
6235 +
/// Grouped instantiation declarations resolve every specialization root.
6236 +
@test fn testGroupedGenericSpecializationRoots() throws (testing::TestError) {
6237 +
    let mut a = testResolver();
6238 +
    let result = try resolveProgramStr(
6239 +
        &mut a,
6240 +
        "record Box⟨T⟩ { value: T } fn id⟨T⟩(value: T) -> T { return value; } instantiate Box⟨i32⟩, id⟨i32⟩, id⟨u64⟩;",
6241 +
    );
6242 +
    try expectNoErrors(&result);
6243 +
    let case ast::NodeValue::Block(block) = result.root.value
6244 +
        else throw testing::TestError::Failed;
6245 +
    let case ast::NodeValue::Instantiate(applications) = block.statements[2].value
6246 +
        else throw testing::TestError::Failed;
6247 +
    assert applications.len == 3;
6248 +
    assert super::typeFor(&a, applications[0]) <> nil;
6249 +
    let functions = super::genericFnSpecializations(&a)
6250 +
        else throw testing::TestError::Failed;
6251 +
    assert functions.next <> nil;
6252 +
}
6253 +
6254 +
/// Generic free-function bodies are checked with their rigid signature.
6255 +
@test fn testGenericFunctionBodyChecked() throws (testing::TestError) {
6256 +
    let mut a = testResolver();
6257 +
    let result = try resolveProgramStr(
6258 +
        &mut a,
6259 +
        "fn id⟨T⟩(value: T) -> T { return value; }",
6260 +
    );
6261 +
    try expectNoErrors(&result);
6262 +
    let case ast::NodeValue::Block(block) = result.root.value
6263 +
        else throw testing::TestError::Failed;
6264 +
    let sym = super::symbolFor(&a, block.statements[0])
6265 +
        else throw testing::TestError::Failed;
6266 +
    let template = super::genericTemplateFor(&a, sym)
6267 +
        else throw testing::TestError::Failed;
6268 +
    assert template.bodyResolved;
6269 +
    assert *template.params[0].used;
6270 +
    assert template.moduleId == sym.moduleId;
6271 +
}
6272 +
6273 +
/// Re-entering definition analysis does not check a generic body twice.
6274 +
@test fn testGenericFunctionBodyCheckedOnce() throws (testing::TestError) {
6275 +
    let mut a = testResolver();
6276 +
    let result = try resolveProgramStr(
6277 +
        &mut a,
6278 +
        "fn id⟨T⟩(value: T) -> T { return value; }",
6279 +
    );
6280 +
    try expectNoErrors(&result);
6281 +
    let case ast::NodeValue::Block(block) = result.root.value
6282 +
        else throw testing::TestError::Failed;
6283 +
    let sym = super::symbolFor(&a, block.statements[0])
6284 +
        else throw testing::TestError::Failed;
6285 +
    let template = super::genericTemplateFor(&a, sym)
6286 +
        else throw testing::TestError::Failed;
6287 +
    assert template.bodyChecks == 1;
6288 +
}
6289 +
6290 +
/// Rigid parameters compose through pointers, optionals, and throws signatures.
6291 +
@test fn testGenericFunctionCompoundSignature() throws (testing::TestError) {
6292 +
    let mut a = testResolver();
6293 +
    let result = try resolveProgramStr(
6294 +
        &mut a,
6295 +
        "union Fault { Bad } fn pass⟨T⟩(value: *?T) -> *?T throws (Fault) { return value; }",
6296 +
    );
6297 +
    try expectNoErrors(&result);
6298 +
}
6299 +
6300 +
/// Concrete-only arithmetic is rejected while checking the template body.
6301 +
@test fn testGenericFunctionConcreteOperationRejected() throws (testing::TestError) {
6302 +
    let mut a = testResolver();
6303 +
    let result = try resolveProgramStr(
6304 +
        &mut a,
6305 +
        "fn add⟨T⟩(left: T, right: T) -> T { return left + right; }",
6306 +
    );
6307 +
    try expectErrorKind(&result, super::ErrorKind::ExpectedNumeric);
6308 +
}
6309 +
6310 +
/// Type parameters used only by a body annotation still affect the template.
6311 +
@test fn testGenericFunctionBodyOnlyParameter() throws (testing::TestError) {
6312 +
    let mut a = testResolver();
6313 +
    let result = try resolveProgramStr(
6314 +
        &mut a,
6315 +
        "fn local⟨T⟩() { let value: ?T = nil; }",
6316 +
    );
6317 +
    try expectNoErrors(&result);
6318 +
}
6319 +
6320 +
/// Parameters that affect neither signature nor body are rejected.
6321 +
@test fn testGenericFunctionUnusedParameterRejected() throws (testing::TestError) {
6322 +
    let mut a = testResolver();
6323 +
    let result = try resolveProgramStr(
6324 +
        &mut a,
6325 +
        "fn unused⟨T⟩() {}",
6326 +
    );
6327 +
    let err = try expectError(&result);
6328 +
    let case super::ErrorKind::GenericFnUnusedParameter(name) = err.kind
6329 +
        else throw testing::TestError::Failed;
6330 +
    assert mem::eq(name, "T");
6331 +
}
6332 +
6333 +
/// Linkage and entry-point attributes are not valid on templates.
6334 +
@test fn testGenericFunctionAttributeRejected() throws (testing::TestError) {
6335 +
    let mut a = testResolver();
6336 +
    let result = try resolveProgramStr(
6337 +
        &mut a,
6338 +
        "fn external⟨T⟩(value: T) -> T;",
6339 +
    );
6340 +
    try expectErrorKind(&result, super::ErrorKind::GenericFnAttribute);
6341 +
    let mut b = testResolver();
6342 +
    let defaultResult = try resolveProgramStr(
6343 +
        &mut b,
6344 +
        "@default fn entry⟨T⟩(value: T) -> T { return value; }",
6345 +
    );
6346 +
    try expectErrorKind(&defaultResult, super::ErrorKind::GenericFnAttribute);
6347 +
}
6348 +
6349 +
/// Generic functions cannot introduce nested template scopes.
6350 +
@test fn testNestedGenericFunctionRejected() throws (testing::TestError) {
6351 +
    let mut a = testResolver();
6352 +
    let result = try resolveProgramStr(
6353 +
        &mut a,
6354 +
        "fn outer() { fn inner⟨T⟩(value: T) -> T { return value; } }",
6355 +
    );
6356 +
    try expectErrorKind(&result, super::ErrorKind::GenericFnNested);
6357 +
}
6358 +
6359 +
/// Bound method operations resolve through their declared trait.
6360 +
@test fn testGenericBoundMethodResolved() throws (testing::TestError) {
6361 +
    let mut a = testResolver();
6362 +
    let result = try resolveProgramStr(
6363 +
        &mut a,
6364 +
        "trait Copy { fn (&Copy) copy() -> Self; } fn duplicate⟨T: Copy⟩(value: T) -> T { return value.copy(); }",
6365 +
    );
6366 +
    try expectNoErrors(&result);
6367 +
}
6368 +
6369 +
/// Unqualified methods shared by multiple bounds are ambiguous.
6370 +
@test fn testGenericBoundMethodAmbiguous() throws (testing::TestError) {
6371 +
    let mut a = testResolver();
6372 +
    let result = try resolveProgramStr(
6373 +
        &mut a,
6374 +
        "trait A { fn (&A) run(); } trait B { fn (&B) run(); } fn invoke⟨T: A + B⟩(value: T) { value.run(); }",
6375 +
    );
6376 +
    try expectErrorKind(&result, super::ErrorKind::GenericBoundAmbiguous("run"));
6377 +
}
6378 +
6379 +
/// Qualified bound calls disambiguate methods shared by several traits.
6380 +
@test fn testGenericBoundMethodQualified() throws (testing::TestError) {
6381 +
    let mut a = testResolver();
6382 +
    let result = try resolveProgramStr(
6383 +
        &mut a,
6384 +
        "trait A { fn (&A) run() -> u32; } trait B { fn (&B) run() -> u32; } fn invoke⟨T: A + B⟩(value: T) -> u32 { return B::run(&value); }",
6385 +
    );
6386 +
    try expectNoErrors(&result);
6387 +
}
6388 +
6389 +
/// Qualified bound dispatch enforces unsafe receiver operations.
6390 +
@test fn testGenericBoundQualifiedUnsafeReceiverRejected() throws (testing::TestError) {
6391 +
    let mut a = testResolver();
6392 +
    let result = try resolveProgramStr(
6393 +
        &mut a,
6394 +
        "trait Read { fn (*Read) read(); } fn invoke⟨T: Read⟩(value: *unsafe T) { Read::read(value); }",
6395 +
    );
6396 +
    try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
6397 +
}
6398 +
6399 +
/// Qualified bound calls accept module-qualified trait paths.
6400 +
@test fn testGenericBoundQualifiedAcrossModule() throws (testing::TestError) {
6401 +
    let mut a = testResolver();
6402 +
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6403 +
    let rootId = try registerModule(
6404 +
        &mut MODULE_GRAPH, nil, "root", "export mod defs; mod app;", &mut arena
6405 +
    );
6406 +
    let _ = try registerModule(
6407 +
        &mut MODULE_GRAPH,
6408 +
        rootId,
6409 +
        "defs",
6410 +
        "export trait Read { fn (&Read) read() -> u32; }",
6411 +
        &mut arena,
6412 +
    );
6413 +
    let _ = try registerModule(
6414 +
        &mut MODULE_GRAPH,
6415 +
        rootId,
6416 +
        "app",
6417 +
        "use root::defs; fn invoke⟨T: defs::Read⟩(value: T) -> u32 { return defs::Read::read(&value); }",
6418 +
        &mut arena,
6419 +
    );
6420 +
    let result = try resolveModuleTree(&mut a, rootId);
6421 +
    try expectNoErrors(&result);
6422 +
}
6423 +
6424 +
/// Imported generic roots share their defining module's specialization.
6425 +
@test fn testGenericSpecializationAcrossModule() throws (testing::TestError) {
6426 +
    let mut a = testResolver();
6427 +
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
6428 +
    let rootId = try registerModule(
6429 +
        &mut MODULE_GRAPH,
6430 +
        nil,
6431 +
        "root",
6432 +
        "export mod base; use base::*; instantiate base::identity⟨u32⟩; instantiate Box⟨u32⟩;",
6433 +
        &mut arena,
6434 +
    );
6435 +
    let baseId = try registerModule(
6436 +
        &mut MODULE_GRAPH,
6437 +
        rootId,
6438 +
        "base",
6439 +
        "export record Box⟨T⟩ { value: T } export fn identity⟨T⟩(value: T) -> T { return value; } instantiate identity⟨u32⟩; instantiate Box⟨u32⟩;",
6440 +
        &mut arena,
6441 +
    );
6442 +
    let result = try resolveModuleTree(&mut a, rootId);
6443 +
    try expectNoErrors(&result);
6444 +
6445 +
    let node = super::genericFnSpecializations(&a)
6446 +
        else throw testing::TestError::Failed;
6447 +
    assert node.next == nil;
6448 +
    assert node.specialization.template.moduleId == baseId;
6449 +
}
6450 +
6451 +
/// Qualified bound dispatch accepts computed receiver expressions.
6452 +
@test fn testGenericBoundQualifiedExpressionReceiver() throws (testing::TestError) {
6453 +
    let mut a = testResolver();
6454 +
    let result = try resolveProgramStr(
6455 +
        &mut a,
6456 +
        "trait Read { fn (*Read) read(); } fn borrow⟨T⟩(value: *T) -> *T { return value; } fn invoke⟨T: Read⟩(value: T) { Read::read(borrow(&value)); }",
6457 +
    );
6458 +
    try expectNoErrors(&result);
6459 +
}
6460 +
6461 +
/// Bound receivers participate in call-scoped loan conflict checks.
6462 +
@test fn testGenericBoundReceiverBorrowConflict() throws (testing::TestError) {
6463 +
    let mut a = testResolver();
6464 +
    let result = try resolveProgramStr(
6465 +
        &mut a,
6466 +
        "record Marker: Linear {} trait View { fn (&mut View) inspect(other: &Self); } fn inspectTwice⟨T: View⟩(value: T) { let mut local = value; local.inspect(&local); }",
6467 +
    );
6468 +
    try expectErrorKind(
6469 +
        &result, super::ErrorKind::BorrowConflict("local")
6470 +
    );
6471 +
}
6472 +
6473 +
/// Calls select a previously rooted concrete specialization.
6474 +
@test fn testGenericFunctionRootedCall() throws (testing::TestError) {
6475 +
    let mut a = testResolver();
6476 +
    let result = try resolveProgramStr(
6477 +
        &mut a,
6478 +
        "fn id⟨T⟩(value: T) -> T { return value; } instantiate id⟨i32⟩; fn run() -> i32 { return id⟨i32⟩(7); }",
6479 +
    );
6480 +
    try expectNoErrors(&result);
6481 +
}
6482 +
6483 +
/// Calls cannot implicitly create specialization roots.
6484 +
@test fn testGenericFunctionUnrootedCallRejected() throws (testing::TestError) {
6485 +
    let mut a = testResolver();
6486 +
    let result = try resolveProgramStr(
6487 +
        &mut a,
6488 +
        "fn id⟨T⟩(value: T) -> T { return value; } fn run() -> i32 { return id⟨i32⟩(7); }",
6489 +
    );
6490 +
    try expectErrorKind(
6491 +
        &result, super::ErrorKind::GenericFunctionInstantiationRequired
6492 +
    );
6493 +
}
6494 +
6495 +
/// A rooted template pulls symbolic callees into the specialization closure.
6496 +
@test fn testGenericFunctionDependencyClosure() throws (testing::TestError) {
6497 +
    let mut a = testResolver();
6498 +
    let result = try resolveProgramStr(
6499 +
        &mut a,
6500 +
        "fn id⟨T⟩(value: T) -> T { return value; } fn wrap⟨T⟩(value: T) -> T { return id⟨T⟩(value); } instantiate wrap⟨i32⟩;",
6501 +
    );
6502 +
    try expectNoErrors(&result);
6503 +
6504 +
    let mut count: u32 = 0;
6505 +
    let mut cursor = super::genericFnSpecializations(&a);
6506 +
    while let node = cursor {
6507 +
        set count += 1;
6508 +
        set cursor = node.next;
6509 +
    }
6510 +
    assert count == 2;
6511 +
}
6512 +
6513 +
/// Inference cannot create a specialization without an explicit root.
6514 +
@test fn testGenericFunctionInferredUnrootedCallRejected() throws (testing::TestError) {
6515 +
    let mut a = testResolver();
6516 +
    let result = try resolveProgramStr(
6517 +
        &mut a,
6518 +
        "fn id⟨T⟩(value: T) -> T { return value; } fn run(value: i32) -> i32 { return id(value); }",
6519 +
    );
6520 +
    try expectErrorKind(
6521 +
        &result, super::ErrorKind::GenericFunctionInstantiationRequired
6522 +
    );
6523 +
}
6524 +
6525 +
/// Exact argument evidence can select an already rooted specialization.
6526 +
@test fn testGenericFunctionCallInference() throws (testing::TestError) {
6527 +
    let mut a = testResolver();
6528 +
    let result = try resolveProgramStr(
6529 +
        &mut a,
6530 +
        "fn id⟨T⟩(value: T) -> T { return value; } instantiate id⟨i32⟩; instantiate id⟨i64⟩; fn run(value: i32) -> i32 { id(1); return id(value); }",
6531 +
    );
6532 +
    try expectNoErrors(&result);
6533 +
}
6534 +
6535 +
/// Inference requires evidence for every generic parameter.
6536 +
@test fn testGenericFunctionInferenceIncomplete() throws (testing::TestError) {
6537 +
    let mut a = testResolver();
6538 +
    let result = try resolveProgramStr(
6539 +
        &mut a,
6540 +
        "fn absent⟨T⟩() -> ?T { return nil; } fn run() { let value = absent(); }",
6541 +
    );
6542 +
    try expectErrorKind(&result, super::ErrorKind::GenericInferenceIncomplete);
6543 +
}
6544 +
6545 +
/// An already known result type can complete local inference.
6546 +
@test fn testGenericFunctionResultInference() throws (testing::TestError) {
6547 +
    let mut a = testResolver();
6548 +
    let result = try resolveProgramStr(
6549 +
        &mut a,
6550 +
        "fn absent⟨T⟩() -> ?T { return nil; } instantiate absent⟨i32⟩; fn run() { let value: ?i32 = absent(); }",
6551 +
    );
6552 +
    try expectNoErrors(&result);
6553 +
}
6554 +
6555 +
/// Multiple arguments cannot infer different types for one parameter.
6556 +
@test fn testGenericFunctionInferenceConflict() throws (testing::TestError) {
6557 +
    let mut a = testResolver();
6558 +
    let result = try resolveProgramStr(
6559 +
        &mut a,
6560 +
        "fn first⟨T⟩(left: T, right: T) -> T { return left; } fn run(left: i32, right: u32) { let value = first(left, right); }",
6561 +
    );
6562 +
    try expectErrorKind(&result, super::ErrorKind::GenericInferenceConflict);
6563 +
}
6564 +
6565 +
/// Structurally expanding recursion is rejected at the closure bound.
6566 +
@test fn testGenericFunctionExpandingRecursion() throws (testing::TestError) {
6567 +
    let mut a = testResolver();
6568 +
    let result = try resolveProgramStr(
6569 +
        &mut a,
6570 +
        "fn expand⟨T⟩() { let marker: ?T = nil; expand⟨*T⟩(); } instantiate expand⟨i32⟩;",
6571 +
    );
6572 +
    try expectErrorKind(&result, super::ErrorKind::GenericSpecializationChain);
6573 +
}
6574 +
6575 +
/// Trait `Self` is rigid in the declaration and concrete in an instance.
6576 +
@test fn testTraitSelfSubstitution() throws (testing::TestError) {
6577 +
    let mut a = testResolver();
6578 +
    let result = try resolveProgramStr(
6579 +
        &mut a,
6580 +
        "trait Select { fn (&Select) select(other: Self) -> Self; } instance Select for u32 { fn (value: &u32) select(other: u32) -> u32 { return other; } }",
6581 +
    );
6582 +
    try expectNoErrors(&result);
6583 +
}
6584 +
6585 +
/// Specialized nominal types are valid concrete instance targets.
6586 +
@test fn testGenericDataInstanceTarget() throws (testing::TestError) {
6587 +
    let mut a = testResolver();
6588 +
    let result = try resolveProgramStr(
6589 +
        &mut a,
6590 +
        "record Box⟨T⟩ { value: T } instantiate Box⟨u32⟩; trait Read { fn (&Read) read(); } instance Read for Box⟨u32⟩ { fn (value: &Box⟨u32⟩) read() {} }",
6591 +
    );
6592 +
    try expectNoErrors(&result);
6593 +
}
6594 +
6595 +
/// `Self` outside a trait declaration has no implicit binding.
6596 +
@test fn testTraitSelfOutsideTraitRejected() throws (testing::TestError) {
6597 +
    let mut a = testResolver();
6598 +
    let result = try resolveProgramStr(&mut a, "fn invalid(value: Self) {}");
6599 +
    try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("Self"));
6600 +
}
6601 +
6602 +
/// A trait exposing `Self` cannot be erased behind an opaque object.
6603 +
@test fn testTraitSelfObjectSafety() throws (testing::TestError) {
6604 +
    let mut a = testResolver();
6605 +
    let result = try resolveProgramStr(
6606 +
        &mut a,
6607 +
        "trait Clone { fn (&Clone) clone() -> Self; } fn inspect(value: &opaque Clone) {}",
6608 +
    );
6609 +
    try expectErrorKind(&result, super::ErrorKind::TraitNotObjectSafe);
6610 +
}
6611 +
6612 +
/// Resolving a nested trait object preserves the enclosing trait's `Self`.
6613 +
@test fn testTraitSelfNestedTraitResolution() throws (testing::TestError) {
6614 +
    let mut a = testResolver();
6615 +
    let result = try resolveProgramStr(
6616 +
        &mut a,
6617 +
        "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; } }",
6618 +
    );
6619 +
    try expectNoErrors(&result);
6620 +
}
6621 +
6622 +
/// Cyclic supertraits cannot expose partially constructed method tables.
6623 +
@test fn testTraitInheritanceCycleRejected() throws (testing::TestError) {
6624 +
    let mut a = testResolver();
6625 +
    let result = try resolveProgramStr(
6626 +
        &mut a,
6627 +
        "trait First: Second { fn (&First) first(); } trait Second: First { fn (&Second) second(); }",
6628 +
    );
6629 +
    try expectErrorKind(&result, super::ErrorKind::TraitInheritanceCycle);
6630 +
}
6631 +
6632 +
/// A subtrait instance inherits implementations from its supertrait instance.
6633 +
@test fn testInheritedTraitMethodOverrideRejected() throws (testing::TestError) {
6634 +
    let mut a = testResolver();
6635 +
    let result = try resolveProgramStr(
6636 +
        &mut a,
6637 +
        "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; } }",
6638 +
    );
6639 +
    try expectErrorKind(&result, super::ErrorKind::InheritedTraitMethod("value"));
6640 +
}
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 +
}
test/runner.rad +13 -1
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");
266 278
        return false;
267 279
    }
268 280
269 281
    // Lower to IL.
270 282
    let mut ilArena = alloc::new(&mut IL_ARENA_STORAGE[..]);
271 -
    let program = try lower::lower(&res, root, "test", &mut ilArena) catch err {
283 +
    let program = try lower::lower(&mut res, root, "test", &mut ilArena) catch err {
272 284
        io::print("error: lowering failed: ");
273 285
        lower::printError(err);
274 286
        io::printLn("");
275 287
        return false;
276 288
    };
test/tests/coercion.implicit.ril +10 -6
4 4
    store w8 1 %0 0;
5 5
    store w32 42 %0 4;
6 6
    reserve %1 8 4;
7 7
    blit %1 %0 8;
8 8
    load w8 %2 %1 0;
9 -
    br.ne w32 %2 0 @merge1 @else2;
10 -
  @merge1
9 +
    br.ne w32 %2 0 @success1 @else2;
10 +
  @success1
11 11
    sload w32 %3 %1 4;
12 -
    ret %3;
12 +
    jmp @merge3;
13 13
  @else2
14 14
    ret 0;
15 +
  @merge3
16 +
    ret %3;
15 17
}
16 18
17 19
fn w32 $optionalLiftVar(w32 %0) {
18 20
  @entry0
19 21
    reserve %1 8 4;
22 24
    reserve %2 8 4;
23 25
    blit %2 %1 8;
24 26
    reserve %3 8 4;
25 27
    blit %3 %2 8;
26 28
    load w8 %4 %3 0;
27 -
    br.ne w32 %4 0 @merge1 @else2;
28 -
  @merge1
29 +
    br.ne w32 %4 0 @success1 @else2;
30 +
  @success1
29 31
    sload w32 %5 %3 4;
30 -
    ret %5;
32 +
    jmp @merge3;
31 33
  @else2
32 34
    ret 0;
35 +
  @merge3
36 +
    ret %5;
33 37
}
34 38
35 39
fn w64 $optionalLiftReturn(w64 %0, w32 %1) {
36 40
  @entry0
37 41
    reserve %2 8 4;
test/tests/cond.letelse.case.ril +5 -3
1 1
fn w32 $letElseCase(w32 %0) {
2 2
  @entry0
3 -
    br.eq w32 %0 1 @merge1 @else2;
4 -
  @merge1
5 -
    ret 1;
3 +
    br.eq w32 %0 1 @success1 @else2;
4 +
  @success1
5 +
    jmp @merge3;
6 6
  @else2
7 7
    ret 0;
8 +
  @merge3
9 +
    ret 1;
8 10
}
test/tests/cond.letelse.guard.ril +4 -2
2 2
  @entry0
3 3
    br.eq w32 %0 1 @guard2 @else1;
4 4
  @else1
5 5
    ret 0;
6 6
  @guard2
7 -
    br.slt w32 0 %0 @merge3 @else1;
8 -
  @merge3
7 +
    br.slt w32 0 %0 @success3 @else1;
8 +
  @success3
9 +
    jmp @merge4;
10 +
  @merge4
9 11
    ret 1;
10 12
}
test/tests/cond.letelse.mut.ril +6 -4
1 1
fn w32 $letMutElse(w64 %0) {
2 2
  @entry0
3 3
    reserve %1 8 4;
4 4
    blit %1 %0 8;
5 5
    load w8 %2 %1 0;
6 -
    br.ne w32 %2 0 @merge1 @else2;
7 -
  @merge1
6 +
    br.ne w32 %2 0 @success1 @else2;
7 +
  @success1
8 8
    sload w32 %3 %1 4;
9 -
    add w32 %4 %3 1;
10 -
    ret %4;
9 +
    jmp @merge3;
11 10
  @else2
12 11
    ret 0;
12 +
  @merge3
13 +
    add w32 %4 %3 1;
14 +
    ret %4;
13 15
}
test/tests/cond.letelse.optional.ril +5 -3
1 1
fn w32 $letElseOptional(w64 %0) {
2 2
  @entry0
3 -
    br.ne w32 %0 0 @merge1 @else2;
4 -
  @merge1
5 -
    ret 1;
3 +
    br.ne w32 %0 0 @success1 @else2;
4 +
  @success1
5 +
    jmp @merge3;
6 6
  @else2
7 7
    ret 0;
8 +
  @merge3
9 +
    ret 1;
8 10
}
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 +29 -0
1 +
//! returns: 0
2 +
3 +
/// Inline storage with a generic capacity.
4 +
record InlineVec⟨T, constant N: u32{
5 +
    data: [T; N],
6 +
    len: u32,
7 +
}
8 +
9 +
/// Nested storage with a derived generic capacity.
10 +
record Nested⟨constant N: u32{
11 +
    inner: InlineVec⟨u8, N + 1⟩,
12 +
}
13 +
14 +
/// Return an array's capacity and first element.
15 +
fn capacity⟨constant N: u32(items: [u8; N]) -> u32 {
16 +
    return items.len + items[0] as u32;
17 +
}
18 +
19 +
instantiate InlineVec⟨u8, 4⟩;
20 +
instantiate Nested⟨3⟩;
21 +
instantiate capacity⟨4⟩;
22 +
23 +
/// Exercise constant generic records and functions.
24 +
@default fn main() -> i32 {
25 +
    let vector = InlineVec⟨u8, 4{ data: [4, 3, 2, 1], len: 4 };
26 +
    let nested = Nested⟨3{ inner: vector };
27 +
    let result = capacity⟨4(nested.inner.data);
28 +
    return result as i32 - 8;
29 +
}
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 +14 -0
1 +
//! returns: 0
2 +
3 +
/// Union whose discriminant depends on a constant argument.
4 +
union Code⟨constant N: u32{
5 +
    First = N,
6 +
    Second,
7 +
}
8 +
9 +
instantiate Code⟨4⟩;
10 +
11 +
/// Exercise a constant generic union.
12 +
@default fn main() -> i32 {
13 +
    return Code⟨4::First as i32 - 4;
14 +
}
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 +40 -0
1 +
//! returns: 67
2 +
3 +
/// Two-word aggregate.
4 +
record Pair { first: i32, second: i32 }
5 +
6 +
/// Five-word aggregate.
7 +
record Large { a: i32, b: i32, c: i32, d: i32, e: i32 }
8 +
9 +
/// Generic value wrapper.
10 +
record Box⟨T⟩ { value: T }
11 +
12 +
/// Return a value unchanged.
13 +
fn identity⟨T⟩(value: T) -> T { return value; }
14 +
15 +
/// Return a pointer unchanged.
16 +
fn pointer⟨T⟩(value: *T) -> *T { return value; }
17 +
18 +
/// Pass a value through a generic call.
19 +
fn passt⟨T⟩(value: T) -> T { return value; }
20 +
21 +
instantiate Box⟨i32⟩,
22 +
            identity⟨i32⟩,
23 +
            pointer⟨i32⟩,
24 +
            passt⟨Pair⟩,
25 +
            passt⟨Large⟩,
26 +
            passt⟨Box⟨i32⟩⟩;
27 +
28 +
/// Exercise generic calls for scalar and aggregate values.
29 +
@default fn main() -> i32 {
30 +
    let number: i32 = 11;
31 +
    let pair = Pair { first: 5, second: 13 };
32 +
    let large = Large { a: 3, b: 5, c: 7, d: 11, e: 19 };
33 +
    let boxed = Box⟨i32{ value: 17 };
34 +
    let identify = identity⟨i32⟩;
35 +
    return identify(7)
36 +
        + passt⟨Pair⟩(pair).second
37 +
        + passt⟨Large⟩(large).e
38 +
        + *pointer⟨i32(&number)
39 +
        + passt⟨Box⟨i32⟩⟩(boxed).value;
40 +
}
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 +68 -0
1 +
/// Two-word aggregate used by generic tests.
2 +
record Pair { first: i32, second: i32 }
3 +
4 +
/// Error used by generic throwing functions.
5 +
union Fault { Bad }
6 +
7 +
/// Generic value wrapper.
8 +
record Box⟨T⟩ { value: T }
9 +
10 +
/// Marker trait used by generic trait-object tests.
11 +
trait Marker {}
12 +
13 +
/// Return a value unchanged.
14 +
fn identity⟨T⟩(value: T) -> T {
15 +
    return value;
16 +
}
17 +
18 +
/// Return a pointer unchanged.
19 +
fn pointer⟨T⟩(value: *T) -> *T {
20 +
    return value;
21 +
}
22 +
23 +
/// Return an optional value unchanged.
24 +
fn optional⟨T⟩(value: ?T) -> ?T {
25 +
    return value;
26 +
}
27 +
28 +
/// Return a value through a throwing generic function.
29 +
fn fallible⟨T⟩(value: T) -> T throws (Fault) {
30 +
    return value;
31 +
}
32 +
33 +
/// Lift a value into an optional.
34 +
fn some⟨T⟩(value: T) -> ?T {
35 +
    return value;
36 +
}
37 +
38 +
/// Return a generic slice.
39 +
fn reslice⟨T⟩(items: *[T]) -> *[T] {
40 +
    return &items[..];
41 +
}
42 +
43 +
/// Return the last item or a fallback.
44 +
fn last⟨T⟩(items: *[T], fallback: T) -> T {
45 +
    let mut result = fallback;
46 +
    for item in items {
47 +
        set result = item;
48 +
    }
49 +
    return result;
50 +
}
51 +
52 +
instantiate Box⟨i32⟩;
53 +
instantiate identity⟨i32⟩;
54 +
instantiate identity⟨u64⟩;
55 +
instantiate pointer⟨i32⟩;
56 +
instantiate identity⟨Box⟨i32⟩⟩;
57 +
instantiate identity⟨*opaque Marker⟩;
58 +
instantiate optional⟨i32⟩;
59 +
instantiate optional⟨Pair⟩;
60 +
61 +
instantiate fallible⟨i32⟩;
62 +
instantiate some⟨i32⟩;
63 +
instantiate some⟨Pair⟩;
64 +
instantiate reslice⟨i32⟩;
65 +
instantiate reslice⟨Pair⟩;
66 +
instantiate last⟨i32⟩;
67 +
instantiate last⟨Pair⟩;
68 +
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 +20 -0
1 +
//! returns: 0
2 +
3 +
/// Generic pair.
4 +
record Pair⟨T, U⟩ { first: T, second: U }
5 +
6 +
/// Generic value wrapper.
7 +
record Box⟨T⟩ { value: T }
8 +
9 +
instantiate Box⟨Pair⟨i32, bool⟩⟩;
10 +
11 +
/// Exercise nested generic applications.
12 +
@default fn main() -> i32 {
13 +
    let pair: Pair⟨i32, bool= Pair⟨i32, bool{ first: 42, second: true };
14 +
    let mut boxed: Box⟨Pair⟨i32, bool⟩⟩ = Box⟨Pair⟨i32, bool⟩⟩ { value: pair };
15 +
    set boxed.value.first = 43;
16 +
    if boxed.value.second {
17 +
        return boxed.value.first - 43;
18 +
    }
19 +
    return 1;
20 +
}
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 +33 -0
1 +
//! returns: 0
2 +
//! Generic function templates are checked but not emitted.
3 +
4 +
/// Error used by a generic template.
5 +
union Fault { Bad }
6 +
7 +
/// Generic value wrapper.
8 +
record Box⟨T⟩ { value: T }
9 +
10 +
/// Return a value unchanged.
11 +
fn identity⟨T⟩(value: T) -> T {
12 +
    return value;
13 +
}
14 +
15 +
/// Return a pointer through a throwing generic function.
16 +
fn passPointer⟨T⟩(value: *?T) -> *?T throws (Fault) {
17 +
    return value;
18 +
}
19 +
20 +
/// Type-check a generic local declaration.
21 +
fn bodyType⟨T⟩() {
22 +
    let empty: ?T = nil;
23 +
}
24 +
25 +
/// Return a nested generic application.
26 +
fn nestedType⟨T⟩(value: Box⟨T⟩) -> Box⟨T⟩ {
27 +
    return value;
28 +
}
29 +
30 +
/// Exercise generic template checking.
31 +
@default fn main() -> i32 {
32 +
    return 0;
33 +
}
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 +15 -0
1 +
//! returns: 0
2 +
3 +
/// Generic optional value.
4 +
union Maybe⟨T⟩ { None, Some(T) }
5 +
6 +
instantiate Maybe⟨i32⟩;
7 +
8 +
/// Exercise generic union specialization.
9 +
@default fn main() -> i32 {
10 +
    let value: Maybe⟨i32= Maybe⟨i32::Some(42);
11 +
    match value {
12 +
        case Maybe⟨i32::Some(inner) => { return inner - 42; }
13 +
        case Maybe⟨i32::None => { return 1; }
14 +
    }
15 +
}
test/tests/opt.slice.npo.ril +8 -7
135 135
    reserve %2 16 8;
136 136
    blit %2 %1 16;
137 137
    reserve %3 16 8;
138 138
    blit %3 %2 16;
139 139
    load w64 %4 %3 0;
140 -
    br.ne w32 %4 0 @merge1 @else2;
141 -
  @merge1
142 -
    load w32 %5 %3 8;
143 -
    br.eq w32 %5 3 @assert.ok4 @assert.fail3;
140 +
    br.ne w32 %4 0 @success1 @else2;
141 +
  @success1
142 +
    jmp @merge3;
144 143
  @else2
145 144
    ret 40;
146 -
  @assert.fail3
145 +
  @merge3
146 +
    load w32 %5 %3 8;
147 +
    br.eq w32 %5 3 @assert.ok5 @assert.fail4;
148 +
  @assert.fail4
147 149
    unreachable;
148 -
  @assert.ok4
150 +
  @assert.ok5
149 151
    ret 0;
150 152
}
151 153
152 154
fn w64 $returnNil(w64 %0) {
153 155
  @entry0
358 360
  @then15
359 361
    ret %7;
360 362
  @merge16
361 363
    ret 0;
362 364
}
363 -
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 -13
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;
179 179
  @assert.fail13
180 180
    unreachable;
181 181
  @assert.ok14
182 182
    ret 0;
183 183
}
184 -