Remove `throws` from non-fallible functions

0f9c16bcf6dedf46c9f8a7823025de31164f8446154da0730662f20a0247efc7
Alexis Sellier committed ago 1 parent 4bb2cff3
compiler/radiance.rad +3 -5
339 339
        debug: debugEnabled,
340 340
    };
341 341
    // Initialize and parse all packages.
342 342
    let mut sourceArena = alloc::new(&mut MODULE_SOURCES[..]);
343 343
    for i in 0..pkgCount {
344 -
        try! package::init(&mut ctx.packages[i], i as u16, pkgNames[i], &mut STRING_POOL);
344 +
        package::init(&mut ctx.packages[i], i as u16, pkgNames[i], &mut STRING_POOL);
345 345
346 346
        for j in 0..moduleCounts[i] {
347 347
            let path = modulePaths[i][j];
348 348
            try processModule(&mut ctx.packages[i], &mut ctx.graph, path, arena, &mut sourceArena);
349 349
        }
376 376
    };
377 377
    return RootModule { entry: rootEntry, ast: rootAst };
378 378
}
379 379
380 380
/// Dump the module graph.
381 -
fn dumpGraph(ctx: *CompileContext) throws (Error) {
381 +
fn dumpGraph(ctx: *CompileContext) {
382 382
    let mut arena = alloc::new(&mut MAIN_ARENA[..]);
383 383
    module::printer::printGraph(&ctx.graph, &mut arena);
384 384
}
385 385
386 386
/// Dump the parsed AST.
840 840
                return 1;
841 841
            };
842 842
            return 0;
843 843
        }
844 844
        case Dump::Graph => {
845 -
            try dumpGraph(&ctx) catch {
846 -
                return 1;
847 -
            };
845 +
            dumpGraph(&ctx);
848 846
            return 0;
849 847
        }
850 848
        else => {}
851 849
    }
852 850
    // Generate test runner if in test mode.
lib/std/lang/lower.rad +75 -75
756 756
            case ast::NodeValue::FnDecl(decl) => {
757 757
                if let f = try lowerFnDecl(low, node, decl) {
758 758
                    if isRoot and checkAttr(decl.attrs, ast::Attribute::Default) {
759 759
                        defaultFnIdx = low.fns.len;
760 760
                    }
761 -
                    try pushFn(low, f);
761 +
                    pushFn(low, f);
762 762
                }
763 763
            }
764 764
            case ast::NodeValue::ConstDecl(decl) => {
765 765
                try lowerDataDecl(low, node, decl.value, true);
766 766
            }
1053 1053
        };
1054 1054
        if fnType.throwList.len > 0 {
1055 1055
            func.returnType = il::Type::W64;
1056 1056
        }
1057 1057
        func.blocks = try lowerFnBody(&mut fnLow, body);
1058 -
        try pushFn(self, func);
1058 +
        pushFn(self, func);
1059 1059
1060 1060
        let method = resolver::findTraitMethod(traitInfo, mName)
1061 1061
            else panic "lowerInstanceDecl: method not found in trait";
1062 1062
1063 1063
        methodNames[method.index] = qualName;
1084 1084
        values[i] = il::DataValue {
1085 1085
            item: il::DataItem::Fn(methodNames[i]),
1086 1086
            count: 1,
1087 1087
        };
1088 1088
    }
1089 -
    try pushData(self, il::Data {
1089 +
    pushData(self, il::Data {
1090 1090
        name: vName,
1091 1091
        size: traitInfo.methods.len as u32 * resolver::PTR_SIZE,
1092 1092
        alignment: resolver::PTR_SIZE,
1093 1093
        readOnly: true,
1094 1094
        isUndefined: false,
1197 1197
    let qualName = qualifyName(self, nil, sym.name);
1198 1198
    let mut b = dataBuilder(self.allocator);
1199 1199
    try lowerConstDataInto(self, value, data.ty, layout.size, qualName, &mut b);
1200 1200
    let result = dataBuilderFinish(&b);
1201 1201
1202 -
    try pushData(self, il::Data {
1202 +
    pushData(self, il::Data {
1203 1203
        name: qualName,
1204 1204
        size: layout.size,
1205 1205
        alignment: layout.alignment,
1206 1206
        readOnly,
1207 1207
        isUndefined: result.isUndefined,
1531 1531
    }
1532 1532
}
1533 1533
1534 1534
/// Add a data item to the lowerer's data list.
1535 1535
// XXX: Inline this.
1536 -
fn pushData(self: *mut Lowerer, data: il::Data) throws (LowerError) {
1536 +
fn pushData(self: *mut Lowerer, data: il::Data) {
1537 1537
    self.data.append(data, self.allocator);
1538 1538
}
1539 1539
1540 1540
/// Add a function to the lowerer's function list.
1541 1541
// XXX: Inline this.
1542 -
fn pushFn(self: *mut Lowerer, f: *il::Fn) throws (LowerError) {
1542 +
fn pushFn(self: *mut Lowerer, f: *il::Fn) {
1543 1543
    self.fns.append(f, self.allocator);
1544 1544
}
1545 1545
1546 1546
/// Find an existing string data entry with matching content.
1547 1547
// TODO: Optimize with hash table or remove?
1581 1581
    readOnly: bool,
1582 1582
    values: *[il::DataValue],
1583 1583
    dataPrefix: *[u8]
1584 1584
) -> *[u8] throws (LowerError) {
1585 1585
    let name = nextDeclDataName(self, dataPrefix, self.data.len);
1586 -
    try pushData(self, il::Data { name, size, alignment, readOnly, isUndefined: false, values });
1586 +
    pushData(self, il::Data { name, size, alignment, readOnly, isUndefined: false, values });
1587 1587
1588 1588
    return name;
1589 1589
}
1590 1590
1591 1591
/// Find or create read-only string data and return its symbol name.
1702 1702
    if readOnly {
1703 1703
        if let found = findConstData(self.low, values, alignment) {
1704 1704
            dataName = found;
1705 1705
        } else {
1706 1706
            dataName = try nextDataName(self);
1707 -
            try pushData(self.low, il::Data { name: dataName, size, alignment, readOnly, isUndefined: false, values });
1707 +
            pushData(self.low, il::Data { name: dataName, size, alignment, readOnly, isUndefined: false, values });
1708 1708
        }
1709 1709
    } else {
1710 1710
        dataName = try nextDataName(self);
1711 -
        try pushData(self.low, il::Data { name: dataName, size, alignment, readOnly, isUndefined: false, values });
1711 +
        pushData(self.low, il::Data { name: dataName, size, alignment, readOnly, isUndefined: false, values });
1712 1712
    }
1713 1713
1714 1714
    // Get data address.
1715 1715
    let ptrReg = nextReg(self);
1716 1716
    emit(self, il::Instr::Copy { dst: ptrReg, val: il::Val::DataSym(dataName) });
1912 1912
}
1913 1913
1914 1914
/// Emit an unconditional jump to `target`.
1915 1915
fn emitJmp(self: *mut FnLowerer, target: BlockId) throws (LowerError) {
1916 1916
    emit(self, il::Instr::Jmp { target: target.n, args: &mut [] });
1917 -
    try addPredecessor(self, target, currentBlock(self));
1917 +
    addPredecessor(self, target, currentBlock(self));
1918 1918
}
1919 1919
1920 1920
/// Emit an unconditional jump to `target` with a single argument.
1921 1921
fn emitJmpWithArg(self: *mut FnLowerer, target: BlockId, arg: il::Val) throws (LowerError) {
1922 1922
    let args = try allocVal(self, arg);
1923 1923
    emit(self, il::Instr::Jmp { target: target.n, args });
1924 -
    try addPredecessor(self, target, currentBlock(self));
1924 +
    addPredecessor(self, target, currentBlock(self));
1925 1925
}
1926 1926
1927 1927
/// Emit an unconditional jump to `target` and switch to it.
1928 1928
fn switchAndJumpTo(self: *mut FnLowerer, target: BlockId) throws (LowerError) {
1929 1929
    try emitJmp(self, target);
1941 1941
        thenTarget: thenBlock.n,
1942 1942
        thenArgs: &mut [],
1943 1943
        elseTarget: elseBlock.n,
1944 1944
        elseArgs: &mut [],
1945 1945
    });
1946 -
    try addPredecessor(self, thenBlock, currentBlock(self));
1947 -
    try addPredecessor(self, elseBlock, currentBlock(self));
1946 +
    addPredecessor(self, thenBlock, currentBlock(self));
1947 +
    addPredecessor(self, elseBlock, currentBlock(self));
1948 1948
}
1949 1949
1950 1950
/// Emit a compare-and-branch instruction with the given comparison op.
1951 1951
fn emitBrCmp(
1952 1952
    self: *mut FnLowerer,
1961 1961
    emit(self, il::Instr::Br {
1962 1962
        op, typ, a, b,
1963 1963
        thenTarget: thenBlock.n, thenArgs: &mut [],
1964 1964
        elseTarget: elseBlock.n, elseArgs: &mut [],
1965 1965
    });
1966 -
    try addPredecessor(self, thenBlock, currentBlock(self));
1967 -
    try addPredecessor(self, elseBlock, currentBlock(self));
1966 +
    addPredecessor(self, thenBlock, currentBlock(self));
1967 +
    addPredecessor(self, elseBlock, currentBlock(self));
1968 1968
}
1969 1969
1970 1970
/// Emit a guard that traps with `ebreak` when a comparison is false.
1971 1971
fn emitTrapUnlessCmp(
1972 1972
    self: *mut FnLowerer,
2025 2025
            }
2026 2026
        }
2027 2027
    }
2028 2028
    // Fallback: evaluate condition and emit boolean branch.
2029 2029
    let condVal = try lowerExpr(self, cond);
2030 -
    let condReg = try emitValToReg(self, condVal);
2030 +
    let condReg = emitValToReg(self, condVal);
2031 2031
2032 2032
    try emitBr(self, condReg, thenBlock, elseBlock);
2033 2033
}
2034 2034
2035 2035
/// Emit a 32-bit store instruction at the given offset.
2186 2186
            // Null pointer optimization: branch on the data pointer being null.
2187 2187
            let nilReg = try optionalNilReg(self, subject.val, subject.type);
2188 2188
            try emitBrCmp(self, il::CmpOp::Eq, il::Type::W64, il::Val::Reg(nilReg), il::Val::Imm(0), matchBlock, fallthrough);
2189 2189
        }
2190 2190
        case MatchSubjectKind::OptionalAggregate => {
2191 -
            let base = try emitValToReg(self, subject.val);
2191 +
            let base = emitValToReg(self, subject.val);
2192 2192
2193 2193
            if isNil { // Optional aggregate: `nil` means tag is zero.
2194 2194
                let tagReg = tvalTagReg(self, base);
2195 2195
                try emitBr(self, tagReg, fallthrough, matchBlock);
2196 2196
            } else {
2197 2197
                if isAggregateType(subject.bindType) {
2198 2198
                    // TODO: Why?
2199 2199
                    throw LowerError::Unsupported;
2200 2200
                }
2201 2201
                let pattVal = try lowerExpr(self, pattern);
2202 -
                let pattReg = try emitValToReg(self, pattVal);
2202 +
                let pattReg = emitValToReg(self, pattVal);
2203 2203
                let eq = try lowerOptionalEq(self, subject.bindType, base, pattReg, 0);
2204 -
                let eqReg = try emitValToReg(self, eq);
2204 +
                let eqReg = emitValToReg(self, eq);
2205 2205
2206 2206
                try emitBr(self, eqReg, matchBlock, fallthrough);
2207 2207
            }
2208 2208
        }
2209 2209
        case MatchSubjectKind::Union(unionInfo) => {
2219 2219
            // When matching by reference, always load from the pointer.
2220 2220
            if unionInfo.isAllVoid {
2221 2221
                let mut tagVal = subject.val;
2222 2222
                match subject.by {
2223 2223
                    case resolver::MatchBy::Ref, resolver::MatchBy::MutRef => {
2224 -
                        let base = try emitValToReg(self, subject.val);
2224 +
                        let base = emitValToReg(self, subject.val);
2225 2225
                        tagVal = loadTag(self, base, 0, il::Type::W8);
2226 2226
                    }
2227 2227
                    case resolver::MatchBy::Value => {}
2228 2228
                }
2229 2229
                try emitBrCmp(self, il::CmpOp::Eq, il::Type::W8, tagVal, il::Val::Imm(variantTag as i64), matchBlock, fallthrough);
2230 2230
            } else {
2231 -
                let base = try emitValToReg(self, subject.val);
2231 +
                let base = emitValToReg(self, subject.val);
2232 2232
                let tagReg = tvalTagReg(self, base);
2233 2233
2234 2234
                try emitBrCmp(self, il::CmpOp::Eq, il::Type::W8, il::Val::Reg(tagReg), il::Val::Imm(variantTag as i64), matchBlock, fallthrough);
2235 2235
            }
2236 2236
        }
2347 2347
// Control Flow Edge Management //
2348 2348
//////////////////////////////////
2349 2349
2350 2350
/// Add a predecessor edge from `pred` to `target`.
2351 2351
/// Must be called before the target block is sealed. Duplicates are ignored.
2352 -
fn addPredecessor(self: *mut FnLowerer, target: BlockId, pred: BlockId) throws (LowerError) {
2352 +
fn addPredecessor(self: *mut FnLowerer, target: BlockId, pred: BlockId) {
2353 2353
    let blk = getBlockMut(self, target);
2354 2354
    if blk.sealState == Sealed::Yes {
2355 2355
        panic "addPredecessor: adding predecessor to sealed block";
2356 2356
    }
2357 2357
    let preds = &mut blk.preds;
2966 2966
2967 2967
/// Get the register to compare against `0` for optional `nil` checking.
2968 2968
/// For null-ptr-optimized types, loads the data pointer, or returns it
2969 2969
/// directly for scalar pointers. For aggregates, returns the tag register.
2970 2970
fn optionalNilReg(self: *mut FnLowerer, val: il::Val, typ: resolver::Type) -> il::Reg throws (LowerError) {
2971 -
    let reg = try emitValToReg(self, val);
2971 +
    let reg = emitValToReg(self, val);
2972 2972
    let case resolver::Type::Optional(inner) = typ else return reg;
2973 2973
2974 2974
    if let case resolver::Type::Slice { .. } = *inner {
2975 2975
        let ptrReg = nextReg(self);
2976 2976
        emitLoadW64At(self, ptrReg, reg, SLICE_PTR_OFFSET);
3022 3022
    subjectVal: il::Val,
3023 3023
    bindType: resolver::Type,
3024 3024
    matchBy: resolver::MatchBy,
3025 3025
    valOffset: i32
3026 3026
) -> Var throws (LowerError) {
3027 -
    let base = try emitValToReg(self, subjectVal);
3027 +
    let base = emitValToReg(self, subjectVal);
3028 3028
    let mut payload: il::Val = undefined;
3029 3029
3030 3030
    match matchBy {
3031 3031
        case resolver::MatchBy::Value =>
3032 3032
            payload = tvalPayloadVal(self, base, bindType, valOffset),
3106 3106
    let payloadType = unionInfo.variants[variantOrdinal].valueType;
3107 3107
    let recInfo = resolver::getRecord(payloadType)
3108 3108
        else throw LowerError::ExpectedRecord;
3109 3109
3110 3110
    // Get the payload base pointer which points to the record within the tagged union.
3111 -
    let base = try emitValToReg(self, subject.val);
3111 +
    let base = emitValToReg(self, subject.val);
3112 3112
    let valOffset = unionInfo.valOffset as i32;
3113 3113
    let payloadBase = emitPtrOffset(self, base, valOffset);
3114 3114
3115 3115
    // Bind each field.
3116 3116
    for fieldNode in lit.fields {
3122 3122
        if fieldIdx >= recInfo.fields.len {
3123 3123
            throw LowerError::MissingMetadata;
3124 3124
        }
3125 3125
        let fieldInfo = recInfo.fields[fieldIdx];
3126 3126
3127 -
        try bindFieldVariable(self, field.value, payloadBase, fieldInfo, subject.by);
3127 +
        bindFieldVariable(self, field.value, payloadBase, fieldInfo, subject.by);
3128 3128
    }
3129 3129
}
3130 3130
3131 3131
/// Bind a single record field to a pattern variable.
3132 3132
fn bindFieldVariable(
3133 3133
    self: *mut FnLowerer,
3134 3134
    binding: *ast::Node,
3135 3135
    base: il::Reg,
3136 3136
    fieldInfo: resolver::RecordField,
3137 3137
    matchBy: resolver::MatchBy
3138 -
) throws (LowerError) {
3138 +
) {
3139 3139
    let case ast::NodeValue::Ident(name) = binding.value else {
3140 3140
        return; // Not an identifier binding.
3141 3141
    };
3142 3142
    let mut val: il::Val = undefined;
3143 3143
    match matchBy {
3213 3213
                        args: &mut []
3214 3214
                    }, self.allocator);
3215 3215
                }
3216 3216
            }
3217 3217
        }
3218 -
        try addPredecessor(self, blocks[i], entry);
3218 +
        addPredecessor(self, blocks[i], entry);
3219 3219
    }
3220 3220
    emit(self, il::Instr::Switch {
3221 3221
        val: subject.val,
3222 3222
        defaultTarget: blocks[defaultIdx].n,
3223 3223
        defaultArgs: &mut [],
3750 3750
}
3751 3751
3752 3752
/// Reserve stack storage for a value of the given type.
3753 3753
fn emitReserve(self: *mut FnLowerer, typ: resolver::Type) -> il::Reg throws (LowerError) {
3754 3754
    let layout = resolver::getTypeLayout(typ);
3755 -
    return try emitReserveLayout(self, layout);
3755 +
    return emitReserveLayout(self, layout);
3756 3756
}
3757 3757
3758 3758
/// Reserve stack storage with an explicit layout.
3759 -
fn emitReserveLayout(self: *mut FnLowerer, layout: resolver::Layout) -> il::Reg throws (LowerError) {
3759 +
fn emitReserveLayout(self: *mut FnLowerer, layout: resolver::Layout) -> il::Reg {
3760 3760
    let dst = nextReg(self);
3761 3761
3762 3762
    emit(self, il::Instr::Reserve {
3763 3763
        dst,
3764 3764
        size: il::Val::Imm(layout.size as i64),
3773 3773
    if let case il::Val::Undef = src {
3774 3774
        return;
3775 3775
    }
3776 3776
    if isAggregateType(typ) {
3777 3777
        let dst = emitPtrOffset(self, base, offset);
3778 -
        let src = try emitValToReg(self, src);
3778 +
        let src = emitValToReg(self, src);
3779 3779
        let layout = resolver::getTypeLayout(typ);
3780 3780
3781 3781
        emit(self, il::Instr::Blit { dst, src, size: il::Val::Imm(layout.size as i64) });
3782 3782
    } else {
3783 3783
        emit(self, il::Instr::Store {
3907 3907
    inst: *resolver::InstanceEntry
3908 3908
) -> il::Val throws (LowerError) {
3909 3909
    let vName = vtableName(self.low, inst.moduleId, inst.concreteTypeName, traitInfo.name);
3910 3910
3911 3911
    // Reserve space for the trait object on the stack.
3912 -
    let slot = try emitReserveLayout(self, resolver::Layout {
3912 +
    let slot = emitReserveLayout(self, resolver::Layout {
3913 3913
        size: resolver::PTR_SIZE * 2,
3914 3914
        alignment: resolver::PTR_SIZE,
3915 3915
    });
3916 3916
3917 3917
    // Store data pointer.
3986 3986
3987 3987
/// Emit a tag comparison for void variant equality/inequality.
3988 3988
fn emitTagCmp(self: *mut FnLowerer, op: ast::BinaryOp, val: il::Val, tagIdx: i64, valType: resolver::Type) -> il::Val
3989 3989
    throws (LowerError)
3990 3990
{
3991 -
    let reg = try emitValToReg(self, val);
3991 +
    let reg = emitValToReg(self, val);
3992 3992
3993 3993
    // For all-void unions, the value *is* the tag, not a pointer.
3994 3994
    let mut tag: il::Val = undefined;
3995 3995
    if resolver::isVoidUnion(valType) {
3996 3996
        tag = il::Val::Reg(reg);
4135 4135
    emit(self, il::Instr::Br {
4136 4136
        op: il::CmpOp::Eq, typ: il::Type::W8, a: tagA, b: tagB,
4137 4137
        thenTarget: nilCheck.n, thenArgs: &mut [],
4138 4138
        elseTarget: mergeBlock.n, elseArgs: falseArgs,
4139 4139
    });
4140 -
    try addPredecessor(self, nilCheck, currentBlock(self));
4141 -
    try addPredecessor(self, mergeBlock, currentBlock(self));
4140 +
    addPredecessor(self, nilCheck, currentBlock(self));
4141 +
    addPredecessor(self, mergeBlock, currentBlock(self));
4142 4142
4143 4143
    // Check if both are `nil`.
4144 4144
    try switchToAndSeal(self, nilCheck);
4145 4145
    emit(self, il::Instr::Br {
4146 4146
        op: il::CmpOp::Ne, typ: il::Type::W8, a: tagA, b: il::Val::Imm(0),
4147 4147
        thenTarget: payloadCmp.n, thenArgs: &mut [],
4148 4148
        elseTarget: mergeBlock.n, elseArgs: trueArgs,
4149 4149
    });
4150 -
    try addPredecessor(self, payloadCmp, currentBlock(self));
4151 -
    try addPredecessor(self, mergeBlock, currentBlock(self));
4150 +
    addPredecessor(self, payloadCmp, currentBlock(self));
4151 +
    addPredecessor(self, mergeBlock, currentBlock(self));
4152 4152
4153 4153
    // Both are non-`nil`, compare payloads.
4154 4154
    try switchToAndSeal(self, payloadCmp);
4155 4155
    let payloadEq = try emitEqAtOffset(self, a, b, offset + valOffset, inner);
4156 4156
    try emitJmpWithArg(self, mergeBlock, payloadEq);
4216 4216
    emit(self, il::Instr::Br {
4217 4217
        op: il::CmpOp::Eq, typ: il::Type::W8, a: tagA, b: tagB,
4218 4218
        thenTarget: tagBlock.n, thenArgs: &mut [],
4219 4219
        elseTarget: mergeBlock.n, elseArgs: falseArgs,
4220 4220
    });
4221 -
    try addPredecessor(self, tagBlock, currentBlock(self));
4222 -
    try addPredecessor(self, mergeBlock, currentBlock(self));
4221 +
    addPredecessor(self, tagBlock, currentBlock(self));
4222 +
    addPredecessor(self, mergeBlock, currentBlock(self));
4223 4223
4224 4224
    // Create comparison blocks for each non-void variant and build switch cases.
4225 4225
    // Void variants jump directly to merge with `true`.
4226 4226
    let trueArgs = try allocVal(self, il::Val::Imm(1));
4227 4227
    let cases = try! alloc::allocSlice(
4257 4257
        defaultArgs: &mut [],
4258 4258
        cases
4259 4259
    });
4260 4260
4261 4261
    // Add predecessor edges for switch targets.
4262 -
    try addPredecessor(self, unreachableBlock, tagBlock);
4262 +
    addPredecessor(self, unreachableBlock, tagBlock);
4263 4263
    for i in 0..unionInfo.variants.len {
4264 4264
        if let caseBlock = caseBlocks[i] {
4265 -
            try addPredecessor(self, caseBlock, tagBlock);
4265 +
            addPredecessor(self, caseBlock, tagBlock);
4266 4266
        } else {
4267 -
            try addPredecessor(self, mergeBlock, tagBlock);
4267 +
            addPredecessor(self, mergeBlock, tagBlock);
4268 4268
        }
4269 4269
    }
4270 4270
    let valOffset = unionInfo.valOffset as i32;
4271 4271
4272 4272
    // Emit payload comparison blocks for non-void variants.
4539 4539
    };
4540 4540
    let fieldInfo = resolver::getRecordField(subjectTy, fieldIdx) else {
4541 4541
        throw LowerError::FieldNotFound;
4542 4542
    };
4543 4543
    let baseVal = try lowerExpr(self, access.parent);
4544 -
    let baseReg = try emitValToReg(self, baseVal);
4544 +
    let baseReg = emitValToReg(self, baseVal);
4545 4545
4546 4546
    return FieldRef {
4547 4547
        base: baseReg,
4548 4548
        offset: fieldInfo.offset,
4549 4549
        fieldType: fieldInfo.fieldType,
4565 4565
) -> il::Val throws (LowerError) {
4566 4566
    let info = resolver::sliceRangeInfoFor(self.low.resolver, sliceNode) else {
4567 4567
        throw LowerError::MissingMetadata;
4568 4568
    };
4569 4569
    let baseVal = try lowerExpr(self, container);
4570 -
    let baseReg = try emitValToReg(self, baseVal);
4570 +
    let baseReg = emitValToReg(self, baseVal);
4571 4571
4572 4572
    // Extract data pointer and container length.
4573 4573
    let mut dataReg = baseReg;
4574 4574
    let mut containerLen: il::Val = undefined;
4575 4575
    if let cap = info.capacity { // Slice from array.
4651 4651
                return val;
4652 4652
            }
4653 4653
            // Materialize a stack slot using the declaration's resolved
4654 4654
            // layout so `align(N)` on locals is honored.
4655 4655
            let layout = resolver::getLayout(self.low.resolver, addr.target, typ);
4656 -
            let slot = try emitReserveLayout(self, layout);
4656 +
            let slot = emitReserveLayout(self, layout);
4657 4657
            try emitStore(self, slot, 0, typ, val);
4658 4658
            let stackVal = il::Val::Reg(slot);
4659 4659
4660 4660
            self.vars[v.id].addressTaken = true;
4661 4661
            defVar(self, v, stackVal);
4767 4767
        throw LowerError::MissingType(container);
4768 4768
    };
4769 4769
    let subjectTy = resolver::autoDeref(containerTy);
4770 4770
    let indexVal = try lowerExpr(self, index);
4771 4771
    let baseVal = try lowerExpr(self, container);
4772 -
    let baseReg = try emitValToReg(self, baseVal);
4772 +
    let baseReg = emitValToReg(self, baseVal);
4773 4773
4774 4774
    let mut dataReg = baseReg;
4775 4775
    let mut elemType: resolver::Type = undefined;
4776 4776
4777 4777
    match subjectTy {
4805 4805
fn lowerDeref(self: *mut FnLowerer, node: *ast::Node, target: *ast::Node) -> il::Val throws (LowerError) {
4806 4806
    let type = resolver::typeFor(self.low.resolver, node) else {
4807 4807
        throw LowerError::MissingType(node);
4808 4808
    };
4809 4809
    let ptrVal = try lowerExpr(self, target);
4810 -
    let ptrReg = try emitValToReg(self, ptrVal);
4810 +
    let ptrReg = emitValToReg(self, ptrVal);
4811 4811
4812 4812
    return emitRead(self, ptrReg, 0, type);
4813 4813
}
4814 4814
4815 4815
/// Lower a subscript expression.
4857 4857
    // values in loop phis when `&var` or `&mut var` appears inside a loop.
4858 4858
    if not isAggregateType(typ) {
4859 4859
        if let sym = resolver::nodeData(self.low.resolver, node).sym {
4860 4860
            if let case resolver::SymbolData::Value { addressTaken, .. } = sym.data; addressTaken {
4861 4861
                let layout = resolver::getLayout(self.low.resolver, node, typ);
4862 -
                let slot = try emitReserveLayout(self, layout);
4862 +
                let slot = emitReserveLayout(self, layout);
4863 4863
                try emitStore(self, slot, 0, typ, varVal);
4864 4864
4865 4865
                let v = newVar(self, name, ilType, l.mutable, il::Val::Reg(slot));
4866 4866
                self.vars[v.id].addressTaken = true;
4867 4867
4964 4964
                };
4965 4965
                if isAggregateType(leftTy) or getVar(self, v).addressTaken {
4966 4966
                    // Aggregates and address-taken scalars are represented as
4967 4967
                    // pointers to stack memory. Store through the pointer.
4968 4968
                    let val = try useVar(self, v);
4969 -
                    let dst = try emitValToReg(self, val);
4969 +
                    let dst = emitValToReg(self, val);
4970 4970
4971 4971
                    try emitStore(self, dst, 0, leftTy, rhs);
4972 4972
                } else {
4973 4973
                    // Scalars are tracked directly in SSA. Each assignment
4974 4974
                    // records a new SSA value.
4984 4984
            try emitStore(self, fieldRef.base, fieldRef.offset, fieldRef.fieldType, rhs);
4985 4985
        }
4986 4986
        case ast::NodeValue::Deref(target) => {
4987 4987
            // Assignment through pointer dereference: `*ptr = value`.
4988 4988
            let ptrVal = try lowerExpr(self, target);
4989 -
            let ptrReg = try emitValToReg(self, ptrVal);
4989 +
            let ptrReg = emitValToReg(self, ptrVal);
4990 4990
            let targetTy = resolver::typeFor(self.low.resolver, a.left) else {
4991 4991
                throw LowerError::MissingType(a.left);
4992 4992
            };
4993 4993
            try emitStore(self, ptrReg, 0, targetTy, rhs);
4994 4994
        }
5184 5184
5185 5185
            try lowerForLoop(self, &iter, f.body);
5186 5186
        }
5187 5187
        case resolver::ForLoopInfo::Collection { elemType, length, bindingName, indexName } => {
5188 5188
            let containerVal = try lowerExpr(self, f.iterable);
5189 -
            let containerReg = try emitValToReg(self, containerVal);
5189 +
            let containerReg = emitValToReg(self, containerVal);
5190 5190
5191 5191
            let mut dataReg = containerReg;
5192 5192
            let mut lengthVal: il::Val = undefined;
5193 5193
            if let len = length { // Array (length is known).
5194 5194
                lengthVal = il::Val::Imm(len as i64);
5237 5237
/// When the function has a return buffer parameter, the value is blitted
5238 5238
/// into the buffer and the buffer pointer is returned. Otherwise, the value is
5239 5239
/// returned directly.
5240 5240
fn emitRetVal(self: *mut FnLowerer, val: il::Val) throws (LowerError) {
5241 5241
    if let retReg = self.returnReg {
5242 -
        let src = try emitValToReg(self, val);
5242 +
        let src = emitValToReg(self, val);
5243 5243
        let size = retBufSize(self);
5244 5244
5245 5245
        emit(self, il::Instr::Blit { dst: retReg, src, size: il::Val::Imm(size as i64) });
5246 5246
        emit(self, il::Instr::Ret { val: il::Val::Reg(retReg) });
5247 5247
    } else if isSmallAggregate(*self.fnType.returnType) {
5248 -
        let src = try emitValToReg(self, val);
5248 +
        let src = emitValToReg(self, val);
5249 5249
        let dst = nextReg(self);
5250 5250
5251 5251
        emit(self, il::Instr::Load { typ: il::Type::W64, dst, src, offset: 0 });
5252 5252
        emit(self, il::Instr::Ret { val: il::Val::Reg(dst) });
5253 5253
    } else {
5288 5288
5289 5289
    try emitRetVal(self, resultVal);
5290 5290
}
5291 5291
5292 5292
/// Ensure a value is in a register (eg. for branch conditions).
5293 -
fn emitValToReg(self: *mut FnLowerer, val: il::Val) -> il::Reg throws (LowerError) {
5293 +
fn emitValToReg(self: *mut FnLowerer, val: il::Val) -> il::Reg {
5294 5294
    match val {
5295 5295
        case il::Val::Reg(r) => return r,
5296 5296
        case il::Val::Imm(_), il::Val::DataSym(_), il::Val::FnAddr(_) => {
5297 5297
            let dst = nextReg(self);
5298 5298
            emit(self, il::Instr::Copy { dst, val });
5407 5407
        try emitCondBranch(self, cond.condition, thenBlock, elseBlock);
5408 5408
5409 5409
        let mergeBlock = try createBlock(self, "cond#merge");
5410 5410
        try switchToAndSeal(self, thenBlock);
5411 5411
5412 -
        let thenVal = try emitValToReg(self, try lowerExpr(self, cond.thenExpr));
5412 +
        let thenVal = emitValToReg(self, try lowerExpr(self, cond.thenExpr));
5413 5413
        emit(self, il::Instr::Blit { dst, src: thenVal, size: il::Val::Imm(layout.size as i64) });
5414 5414
5415 5415
        try emitJmp(self, mergeBlock);
5416 5416
        try switchToAndSeal(self, elseBlock);
5417 5417
5418 -
        let elseVal = try emitValToReg(self, try lowerExpr(self, cond.elseExpr));
5418 +
        let elseVal = emitValToReg(self, try lowerExpr(self, cond.elseExpr));
5419 5419
        emit(self, il::Instr::Blit { dst, src: elseVal, size: il::Val::Imm(layout.size as i64) });
5420 5420
5421 5421
        try emitJmp(self, mergeBlock);
5422 5422
        try switchToAndSeal(self, mergeBlock);
5423 5423
5522 5522
    op: ast::BinaryOp,
5523 5523
    typ: resolver::Type,
5524 5524
    a: il::Val,
5525 5525
    b: il::Val
5526 5526
) -> il::Val throws (LowerError) {
5527 -
    let regA = try emitValToReg(self, a);
5528 -
    let regB = try emitValToReg(self, b);
5527 +
    let regA = emitValToReg(self, a);
5528 +
    let regB = emitValToReg(self, b);
5529 5529
    let result = try lowerAggregateEq(self, typ, regA, regB, 0);
5530 5530
5531 5531
    if op == ast::BinaryOp::Ne {
5532 5532
        return emitTypedBinOp(self, il::BinOp::Eq, il::Type::W32, result, il::Val::Imm(0));
5533 5533
    }
5666 5666
        throw LowerError::MissingType(node);
5667 5667
    };
5668 5668
    if resolver::typesEqual(srcType, dstType) {
5669 5669
        return val;
5670 5670
    }
5671 -
    return try lowerNumericCast(self, val, srcType, dstType);
5671 +
    return lowerNumericCast(self, val, srcType, dstType);
5672 5672
}
5673 5673
5674 5674
/// Check whether a resolver type is a signed integer type.
5675 5675
fn isSignedType(t: resolver::Type) -> bool {
5676 5676
    match t {
5767 5767
    } = resolver::nodeData(self.low.resolver, t.expr).extra {
5768 5768
        resVal = try lowerTraitMethodCall(self, t.expr, callExpr, traitInfo, methodIndex);
5769 5769
    } else {
5770 5770
        resVal = try lowerCall(self, t.expr, callExpr);
5771 5771
    }
5772 -
    let base = try emitValToReg(self, resVal); // The result value.
5772 +
    let base = emitValToReg(self, resVal); // The result value.
5773 5773
    let tagReg = resultTagReg(self, base); // The result tag.
5774 5774
5775 5775
    let okBlock = try createBlock(self, "ok"); // Block if success.
5776 5776
    let errBlock = try createBlock(self, "err"); // Block if failure.
5777 5777
5852 5852
        // Forward the callee's global error tag and payload directly.
5853 5853
        let callerLayout = resolver::getResultLayout(
5854 5854
            *self.fnType.returnType, self.fnType.throwList
5855 5855
        );
5856 5856
        let calleeErrSize = maxErrSize(calleeInfo.throwList);
5857 -
        let dst = try emitReserveLayout(self, callerLayout);
5857 +
        let dst = emitReserveLayout(self, callerLayout);
5858 5858
5859 5859
        emitStoreW64At(self, il::Val::Reg(tagReg), dst, TVAL_TAG_OFFSET);
5860 5860
        let srcPayload = emitPtrOffset(self, base, RESULT_VAL_OFFSET);
5861 5861
        let dstPayload = emitPtrOffset(self, dst, RESULT_VAL_OFFSET);
5862 5862
        emit(self, il::Instr::Blit { dst: dstPayload, src: srcPayload, size: il::Val::Imm(calleeErrSize as i64) });
5908 5908
        let clauseNode = catches[i];
5909 5909
        let case ast::NodeValue::CatchClause(clause) = clauseNode.value
5910 5910
            else panic "lowerMultiCatch: expected CatchClause";
5911 5911
5912 5912
        blocks[i] = try createBlock(self, "catch");
5913 -
        try addPredecessor(self, blocks[i], entry);
5913 +
        addPredecessor(self, blocks[i], entry);
5914 5914
5915 5915
        if let typeNode = clause.typeNode {
5916 5916
            let errTy = resolver::typeFor(self.low.resolver, typeNode) else {
5917 5917
                throw LowerError::MissingType(typeNode);
5918 5918
            };
5933 5933
    let mut defaultTarget: BlockId = undefined;
5934 5934
    if let idx = defaultIdx {
5935 5935
        defaultTarget = blocks[idx];
5936 5936
    } else {
5937 5937
        defaultTarget = try createBlock(self, "unreachable");
5938 -
        try addPredecessor(self, defaultTarget, entry);
5938 +
        addPredecessor(self, defaultTarget, entry);
5939 5939
    }
5940 5940
    emit(self, il::Instr::Switch {
5941 5941
        val: il::Val::Reg(tagReg),
5942 5942
        defaultTarget: defaultTarget.n,
5943 5943
        defaultArgs: &mut [],
6043 6043
    let case ast::NodeValue::FieldAccess(access) = call.callee.value
6044 6044
        else throw LowerError::MissingMetadata;
6045 6045
6046 6046
    // Get the address of the slice header.
6047 6047
    let sliceVal = try lowerExpr(self, access.parent);
6048 -
    let sliceReg = try emitValToReg(self, sliceVal);
6048 +
    let sliceReg = emitValToReg(self, sliceVal);
6049 6049
6050 6050
    // Lower the value to append and the allocator.
6051 6051
    let elemVal = try lowerExpr(self, call.args[0]);
6052 6052
    let allocVal = try lowerExpr(self, call.args[1]);
6053 -
    let allocReg = try emitValToReg(self, allocVal);
6053 +
    let allocReg = emitValToReg(self, allocVal);
6054 6054
6055 6055
    let elemLayout = resolver::getTypeLayout(*elemType);
6056 6056
    let stride = elemLayout.size;
6057 6057
    let alignment = elemLayout.alignment;
6058 6058
6130 6130
    let elemLayout = resolver::getTypeLayout(*elemType);
6131 6131
    let stride = elemLayout.size;
6132 6132
6133 6133
    // Get slice header address.
6134 6134
    let sliceVal = try lowerExpr(self, access.parent);
6135 -
    let sliceReg = try emitValToReg(self, sliceVal);
6135 +
    let sliceReg = emitValToReg(self, sliceVal);
6136 6136
6137 6137
    // Lower the index argument.
6138 6138
    let indexVal = try lowerExpr(self, call.args[0]);
6139 6139
6140 6140
    // Load len and bounds-check: index must be smaller than length.
6213 6213
    let case ast::NodeValue::FieldAccess(access) = call.callee.value
6214 6214
        else throw LowerError::MissingMetadata;
6215 6215
6216 6216
    // Lower the trait object expression.
6217 6217
    let traitObjVal = try lowerExpr(self, access.parent);
6218 -
    let traitObjReg = try emitValToReg(self, traitObjVal);
6218 +
    let traitObjReg = emitValToReg(self, traitObjVal);
6219 6219
6220 6220
    // Load data pointer from trait object.
6221 6221
    let dataReg = nextReg(self);
6222 6222
    emit(self, il::Instr::Load {
6223 6223
        typ: il::Type::W64,
6268 6268
        if methodFnType.throwList.len > 0 {
6269 6269
            let successType = *methodFnType.returnType;
6270 6270
            let layout = resolver::getResultLayout(
6271 6271
                successType, methodFnType.throwList);
6272 6272
6273 -
            args[0] = il::Val::Reg(try emitReserveLayout(self, layout));
6273 +
            args[0] = il::Val::Reg(emitReserveLayout(self, layout));
6274 6274
        } else {
6275 6275
            args[0] = il::Val::Reg(try emitReserve(self, retTy));
6276 6276
        }
6277 6277
        let dst = nextReg(self);
6278 6278
6297 6297
        args,
6298 6298
    });
6299 6299
6300 6300
    if let d = dst {
6301 6301
        if isSmallAggregate(retTy) {
6302 -
            let slot = try emitReserveLayout(
6302 +
            let slot = emitReserveLayout(
6303 6303
                self,
6304 6304
                resolver::Layout {
6305 6305
                    size: resolver::PTR_SIZE,
6306 6306
                    alignment: resolver::PTR_SIZE
6307 6307
                });
6419 6419
    if returnParam {
6420 6420
        if fnInfo.throwList.len > 0 {
6421 6421
            let successType = *fnInfo.returnType;
6422 6422
            let layout = resolver::getResultLayout(successType, fnInfo.throwList);
6423 6423
6424 -
            args[0] = il::Val::Reg(try emitReserveLayout(self, layout));
6424 +
            args[0] = il::Val::Reg(emitReserveLayout(self, layout));
6425 6425
        } else {
6426 6426
            args[0] = il::Val::Reg(try emitReserve(self, retTy));
6427 6427
        }
6428 6428
        let dst = nextReg(self);
6429 6429
        emit(self, il::Instr::Call {
6449 6449
6450 6450
    // Non-void functions produce a value in a register, while void functions
6451 6451
    // return an undefined value that shouldn't be used.
6452 6452
    if let d = dst {
6453 6453
        if isSmallAggregate(retTy) {
6454 -
            let slot = try emitReserveLayout(
6454 +
            let slot = emitReserveLayout(
6455 6455
                self,
6456 6456
                resolver::Layout {
6457 6457
                    size: resolver::PTR_SIZE,
6458 6458
                    alignment: resolver::PTR_SIZE
6459 6459
                });
6481 6481
                return try buildNilOptional(self, optType);
6482 6482
            }
6483 6483
            return try wrapInOptional(self, val, optType);
6484 6484
        }
6485 6485
        case resolver::Coercion::NumericCast { from, to } => {
6486 -
            return try lowerNumericCast(self, val, from, to);
6486 +
            return lowerNumericCast(self, val, from, to);
6487 6487
        }
6488 6488
        case resolver::Coercion::ResultWrap => {
6489 6489
            let payloadType = *self.fnType.returnType;
6490 6490
            return try buildResult(self, 0, val, payloadType);
6491 6491
        }
6498 6498
6499 6499
/// Lower an implicit numeric cast coercion.
6500 6500
///
6501 6501
/// Handles widening conversions between integer types. Uses sign-extension
6502 6502
/// for signed source types and zero-extension for unsigned source types.
6503 -
fn lowerNumericCast(self: *mut FnLowerer, val: il::Val, srcType: resolver::Type, dstType: resolver::Type) -> il::Val throws (LowerError) {
6503 +
fn lowerNumericCast(self: *mut FnLowerer, val: il::Val, srcType: resolver::Type, dstType: resolver::Type) -> il::Val {
6504 6504
    let srcLayout = resolver::getTypeLayout(srcType);
6505 6505
    let dstLayout = resolver::getTypeLayout(dstType);
6506 6506
6507 6507
    if srcLayout.size < dstLayout.size {
6508 6508
        // Widening conversion: sign/zero-extend based on source signedness.
6615 6615
            // Aggregate constants live in read-only memory.  Return a
6616 6616
            // mutable copy so that callers that assign through the
6617 6617
            // resulting pointer do not fault.
6618 6618
            if isAggregateType(type) {
6619 6619
                let layout = resolver::getTypeLayout(type);
6620 -
                let dst = try emitReserveLayout(self, layout);
6620 +
                let dst = emitReserveLayout(self, layout);
6621 6621
                emit(self, il::Instr::Blit { dst, src, size: il::Val::Imm(layout.size as i64) });
6622 6622
6623 6623
                return il::Val::Reg(dst);
6624 6624
            }
6625 6625
            return emitRead(self, src, 0, type);
6651 6651
                val = try useVar(self, v);
6652 6652
                if self.vars[v.id].addressTaken {
6653 6653
                    let typ = resolver::typeFor(self.low.resolver, node) else {
6654 6654
                        throw LowerError::MissingType(node);
6655 6655
                    };
6656 -
                    let ptr = try emitValToReg(self, val);
6656 +
                    let ptr = emitValToReg(self, val);
6657 6657
                    val = emitRead(self, ptr, 0, typ);
6658 6658
                }
6659 6659
            } else {
6660 6660
                val = try lowerGlobalSymbol(self, node);
6661 6661
            }
lib/std/lang/package.rad +1 -1
31 31
pub fn init(
32 32
    pkg: *mut Package,
33 33
    id: u16,
34 34
    name: *[u8],
35 35
    pool: *mut strings::Pool
36 -
) -> *mut Package throws (PackageError) {
36 +
) -> *mut Package {
37 37
    pkg.id = id;
38 38
    pkg.name = strings::intern(pool, name);
39 39
    pkg.rootModuleId = nil;
40 40
41 41
    return pkg;
lib/std/lang/resolver.rad +150 -164
1048 1048
        case ast::NodeValue::Placeholder, ast::NodeValue::Ident(_) => {
1049 1049
            let _ = try bindValueIdent(self, pattern, pattern, ty, mutable, 0, 0);
1050 1050
        }
1051 1051
        else => {
1052 1052
            let actualTy = try checkAssignable(self, pattern, ty);
1053 -
            try setNodeType(self, pattern, actualTy);
1053 +
            setNodeType(self, pattern, actualTy);
1054 1054
        }
1055 1055
    }
1056 1056
}
1057 1057
1058 1058
/// Set the expected return type for a new function body.
1083 1083
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
1084 1084
    return name;
1085 1085
}
1086 1086
1087 1087
/// Associate a resolved symbol with an AST node.
1088 -
fn setNodeSymbol(self: *mut Resolver, node: *ast::Node, symbol: *mut Symbol) throws (ResolveError) {
1088 +
fn setNodeSymbol(self: *mut Resolver, node: *ast::Node, symbol: *mut Symbol) {
1089 1089
    if let existingSym = self.nodeData.entries[node.id].sym {
1090 1090
        panic "setNodeSymbol: a symbol is already associated with this node";
1091 1091
    }
1092 1092
    self.nodeData.entries[node.id].sym = symbol;
1093 1093
}
1094 1094
1095 1095
/// Associate a resolved type with an AST node and return it.
1096 -
fn setNodeType(self: *mut Resolver, node: *ast::Node, ty: Type) -> Type
1097 -
    throws (ResolveError)
1098 -
{
1096 +
fn setNodeType(self: *mut Resolver, node: *ast::Node, ty: Type) -> Type {
1099 1097
    if ty == Type::Unknown {
1100 1098
        // In this case, we simply don't associate a type.
1101 1099
        return ty;
1102 1100
    }
1103 1101
    self.nodeData.entries[node.id].ty = ty;
1116 1114
    }
1117 1115
    return Type::Void;
1118 1116
}
1119 1117
1120 1118
/// Associate a coercion plan with an AST node.
1121 -
fn setNodeCoercion(self: *mut Resolver, node: *ast::Node, coercion: Coercion) -> Coercion
1122 -
    throws (ResolveError)
1123 -
{
1119 +
fn setNodeCoercion(self: *mut Resolver, node: *ast::Node, coercion: Coercion) -> Coercion {
1124 1120
    if coercion == Coercion::Identity {
1125 1121
        return coercion;
1126 1122
    }
1127 1123
    self.nodeData.entries[node.id].coercion = coercion;
1128 1124
1129 1125
    return coercion;
1130 1126
}
1131 1127
1132 1128
/// Associate a constant value with an AST node.
1133 -
fn setNodeConstValue(self: *mut Resolver, node: *ast::Node, value: ConstValue) throws (ResolveError) {
1129 +
fn setNodeConstValue(self: *mut Resolver, node: *ast::Node, value: ConstValue) {
1134 1130
    self.nodeData.entries[node.id].constValue = value;
1135 1131
}
1136 1132
1137 1133
/// Associate a record field index with a record literal field node.
1138 -
fn setRecordFieldIndex(self: *mut Resolver, node: *ast::Node, index: u32)
1139 -
    throws (ResolveError)
1140 -
{
1134 +
fn setRecordFieldIndex(self: *mut Resolver, node: *ast::Node, index: u32) {
1141 1135
    self.nodeData.entries[node.id].extra = NodeExtra::RecordField { index };
1142 1136
}
1143 1137
1144 1138
/// Associate slice range metadata with a subscript expression.
1145 -
fn setSliceRangeInfo(self: *mut Resolver, node: *ast::Node, info: SliceRangeInfo)
1146 -
    throws (ResolveError)
1147 -
{
1139 +
fn setSliceRangeInfo(self: *mut Resolver, node: *ast::Node, info: SliceRangeInfo) {
1148 1140
    self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info);
1149 1141
}
1150 1142
1151 1143
/// Associate union variant metadata with a pattern or constructor node.
1152 1144
fn setVariantInfo(self: *mut Resolver, node: *ast::Node, ordinal: u32, tag: u32) {
1157 1149
fn setTraitMethodCall(self: *mut Resolver, node: *ast::Node, traitInfo: *TraitType, methodIndex: u32) {
1158 1150
    self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex };
1159 1151
}
1160 1152
1161 1153
/// Associate for-loop metadata with a for-loop node.
1162 -
fn setForLoopInfo(self: *mut Resolver, node: *ast::Node, info: ForLoopInfo)
1163 -
    throws (ResolveError)
1164 -
{
1154 +
fn setForLoopInfo(self: *mut Resolver, node: *ast::Node, info: ForLoopInfo) {
1165 1155
    self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info);
1166 1156
}
1167 1157
1168 1158
/// Retrieve the constant value associated with a node, if any.
1169 1159
pub fn constValueEntry(self: *Resolver, node: *ast::Node) -> ?ConstValue {
1199 1189
    }
1200 1190
    return nil;
1201 1191
}
1202 1192
1203 1193
/// Associate match prong metadata with a match prong node.
1204 -
fn setProngCatchAll(self: *mut Resolver, node: *ast::Node, catchAll: bool)
1205 -
    throws (ResolveError)
1206 -
{
1194 +
fn setProngCatchAll(self: *mut Resolver, node: *ast::Node, catchAll: bool) {
1207 1195
    self.nodeData.entries[node.id].extra = NodeExtra::MatchProng { catchAll };
1208 1196
}
1209 1197
1210 1198
/// Check if a prong is catch-all.
1211 1199
pub fn isProngCatchAll(self: *Resolver, node: *ast::Node) -> bool {
1964 1952
/// coercion plan if so, or throw an error if not.
1965 1953
fn expectAssignable(self: *mut Resolver, to: Type, from: Type, site: *ast::Node) -> Coercion throws (ResolveError) {
1966 1954
    // Ensure any nested nominal types are resolved before checking assignability.
1967 1955
    try ensureTypeResolved(self, to, site);
1968 1956
    if let coercion = isAssignable(self, to, from, site) {
1969 -
        return try setNodeCoercion(self, site, coercion);
1957 +
        return setNodeCoercion(self, site, coercion);
1970 1958
    }
1971 1959
    throw emitTypeMismatch(self, site, TypeMismatch {
1972 1960
        expected: to,
1973 1961
        actual: from,
1974 1962
    });
2004 1992
    attrs: u32,
2005 1993
    scope: *mut Scope
2006 1994
) -> *mut Symbol throws (ResolveError) {
2007 1995
    let sym = allocSymbol(self, data, name, owner, attrs);
2008 1996
    try addSymbolToScope(self, sym, scope, owner);
2009 -
    try setNodeSymbol(self, owner, sym);
1997 +
    setNodeSymbol(self, owner, sym);
2010 1998
2011 1999
    return sym;
2012 2000
}
2013 2001
2014 2002
/// Add a symbol to the given scope.
2039 2027
    mutable: bool,
2040 2028
    alignment: u32,
2041 2029
    attrs: u32
2042 2030
) -> ?*mut Symbol throws (ResolveError) {
2043 2031
    if let case ast::NodeValue::Placeholder = ident.value {
2044 -
        try setNodeType(self, owner, type);
2032 +
        setNodeType(self, owner, type);
2045 2033
        return nil;
2046 2034
    }
2047 2035
    let name = try nodeName(self, ident);
2048 2036
    let data = SymbolData::Value { mutable, alignment, type, addressTaken: false };
2049 2037
    let sym = try bindIdent(self, name, owner, data, attrs, self.scope);
2050 -
    try setNodeType(self, owner, type);
2051 -
    try setNodeType(self, ident, type);
2038 +
    setNodeType(self, owner, type);
2039 +
    setNodeType(self, ident, type);
2052 2040
2053 2041
    // Track number of local bindings for lowering stage.
2054 2042
    // TODO: Support `if let mut`.
2055 2043
    if let fnType = self.currentFn {
2056 2044
        let mut ty = fnType;
2069 2057
    attrs: u32
2070 2058
) -> *mut Symbol throws (ResolveError) {
2071 2059
    let name = try nodeName(self, ident);
2072 2060
    let data = SymbolData::Constant { type, value: val };
2073 2061
    let sym = try bindIdent(self, name, owner, data, attrs, self.scope);
2074 -
    try setNodeType(self, owner, type);
2075 -
    try setNodeType(self, ident, type);
2062 +
    setNodeType(self, owner, type);
2063 +
    setNodeType(self, ident, type);
2076 2064
2077 2065
    return sym;
2078 2066
}
2079 2067
2080 2068
/// Bind a module identifier in the given scope.
2360 2348
                let variantName = suffix[0];
2361 2349
                let variantSym = try resolveUnionVariantAccess(
2362 2350
                    self, node, access, unionType, variantName
2363 2351
                );
2364 2352
                // TODO: This shouldn't be here.
2365 -
                try setNodeType(self, node, Type::Nominal(ty));
2353 +
                setNodeType(self, node, Type::Nominal(ty));
2366 2354
                return variantSym;
2367 2355
            }
2368 2356
        }
2369 2357
        else => {} // Fallthrough.
2370 2358
    }
2438 2426
            let sym = findTypeSymbol(self.scope, name)
2439 2427
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
2440 2428
            let case SymbolData::Type(ty) = sym.data
2441 2429
                else throw emitError(self, node, ErrorKind::Internal);
2442 2430
2443 -
            try setNodeSymbol(self, node, sym);
2431 +
            setNodeSymbol(self, node, sym);
2444 2432
2445 2433
            return ty;
2446 2434
        }
2447 2435
        case ast::NodeValue::ScopeAccess(access) => {
2448 2436
            let sym = try resolveAccess(self, node, access, self.scope);
2449 2437
            let case SymbolData::Type(ty) = sym.data
2450 2438
                else throw emitError(self, node, ErrorKind::Internal);
2451 2439
2452 -
            try setNodeSymbol(self, node, sym);
2440 +
            setNodeSymbol(self, node, sym);
2453 2441
2454 2442
            return ty;
2455 2443
        }
2456 2444
        else => panic "resolveTypeName: unsupported node value",
2457 2445
    }
2581 2569
        case ast::NodeValue::While(loopNode) => return try resolveWhile(self, node, loopNode),
2582 2570
        case ast::NodeValue::WhileLet(loopNode) => return try resolveWhileLet(self, node, loopNode),
2583 2571
        case ast::NodeValue::For(loopNode) => return try resolveFor(self, node, loopNode),
2584 2572
        case ast::NodeValue::Loop { body } => {
2585 2573
            let loopType = try visitLoop(self, body);
2586 -
            return try setNodeType(self, node, loopType);
2574 +
            return setNodeType(self, node, loopType);
2587 2575
        },
2588 2576
        case ast::NodeValue::Break => {
2589 2577
            try ensureInsideLoop(self, node);
2590 2578
            // Mark that the current loop has a reachable break.
2591 2579
            self.loopStack[self.loopDepth - 1].hasBreak = true;
2592 2580
2593 -
            return try setNodeType(self, node, Type::Never);
2581 +
            return setNodeType(self, node, Type::Never);
2594 2582
        },
2595 2583
        case ast::NodeValue::Continue => {
2596 2584
            try ensureInsideLoop(self, node);
2597 -
            return try setNodeType(self, node, Type::Never);
2585 +
            return setNodeType(self, node, Type::Never);
2598 2586
        },
2599 2587
        case ast::NodeValue::Match(sw) => return try resolveMatch(self, node, sw),
2600 2588
        case ast::NodeValue::MatchProng(_) => panic "visit: `MatchProng` not handled here",
2601 2589
        case ast::NodeValue::LetElse(letElse) => return try resolveLetElse(self, node, letElse),
2602 2590
        case ast::NodeValue::Call(call) => return try resolveCall(self, node, call, CallCtx::Normal),
2618 2606
        case ast::NodeValue::Panic { message } => {
2619 2607
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
2620 2608
                item: allocType(self, Type::U8),
2621 2609
                mutable: false
2622 2610
            });
2623 -
            return try setNodeType(self, node, Type::Never);
2611 +
            return setNodeType(self, node, Type::Never);
2624 2612
        },
2625 2613
        case ast::NodeValue::Assert { condition, message } => {
2626 2614
            try visit(self, condition, Type::Bool);
2627 2615
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
2628 2616
                item: allocType(self, Type::U8),
2629 2617
                mutable: false
2630 2618
            });
2631 -
            return try setNodeType(self, node, Type::Void);
2619 +
            return setNodeType(self, node, Type::Void);
2632 2620
        },
2633 2621
        case ast::NodeValue::BinOp(binop) => return try resolveBinOp(self, node, binop),
2634 2622
        case ast::NodeValue::UnOp(unop) => return try resolveUnOp(self, node, unop),
2635 2623
        case ast::NodeValue::ExprStmt(expr) => {
2636 2624
            // Pass `Void` as expected type to indicate value is discarded.
2637 2625
            let exprTy = try visit(self, expr, Type::Void);
2638 -
            return try setNodeType(self, node, unifyBranches(exprTy, Type::Void));
2626 +
            return setNodeType(self, node, unifyBranches(exprTy, Type::Void));
2639 2627
        },
2640 2628
        case ast::NodeValue::TypeSig(sig) => return try inferTypeSig(self, node, sig),
2641 2629
        case ast::NodeValue::Ident(name) => {
2642 2630
            let sym = findAnySymbol(self.scope, name)
2643 2631
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
2644 -
            try setNodeSymbol(self, node, sym);
2632 +
            setNodeSymbol(self, node, sym);
2645 2633
2646 2634
            // TODO: See if we can unify this with `resolvePath`, ie. scope access.
2647 2635
            match sym.data {
2648 2636
                case SymbolData::Value { type, .. } => {
2649 -
                    return try setNodeType(self, node, type);
2637 +
                    return setNodeType(self, node, type);
2650 2638
                },
2651 2639
                case SymbolData::Constant { type, value } => {
2652 2640
                    // Propagate constant value.
2653 2641
                    if let val = value {
2654 -
                        try setNodeConstValue(self, node, val);
2642 +
                        setNodeConstValue(self, node, val);
2655 2643
                    }
2656 -
                    return try setNodeType(self, node, type);
2644 +
                    return setNodeType(self, node, type);
2657 2645
                },
2658 2646
                case SymbolData::Type(t) => {
2659 -
                    return try setNodeType(self, node, Type::Nominal(t));
2647 +
                    return setNodeType(self, node, Type::Nominal(t));
2660 2648
                },
2661 2649
                case SymbolData::Variant { .. } => {
2662 2650
                    return Type::Void;
2663 2651
                },
2664 2652
                case SymbolData::Module { .. } => {
2675 2663
            throw emitError(self, node, ErrorKind::InvalidModulePath);
2676 2664
        },
2677 2665
        case ast::NodeValue::Nil => {
2678 2666
            // Use the hint type if it's an optional, otherwise fall back to `Nil`.
2679 2667
            if let case Type::Optional(_) = hint {
2680 -
                return try setNodeType(self, node, hint);
2668 +
                return setNodeType(self, node, hint);
2681 2669
            }
2682 -
            return try setNodeType(self, node, Type::Nil);
2670 +
            return setNodeType(self, node, Type::Nil);
2683 2671
        },
2684 2672
        case ast::NodeValue::Undef => {
2685 -
            return try setNodeType(self, node, Type::Undefined);
2673 +
            return setNodeType(self, node, Type::Undefined);
2686 2674
        },
2687 2675
        case ast::NodeValue::Bool(value) => {
2688 -
            try setNodeConstValue(self, node, ConstValue::Bool(value));
2689 -
            return try setNodeType(self, node, Type::Bool);
2676 +
            setNodeConstValue(self, node, ConstValue::Bool(value));
2677 +
            return setNodeType(self, node, Type::Bool);
2690 2678
        }
2691 2679
        case ast::NodeValue::Char(value) => {
2692 -
            try setNodeConstValue(self, node, ConstValue::Char(value));
2693 -
            return try setNodeType(self, node, Type::U8);
2680 +
            setNodeConstValue(self, node, ConstValue::Char(value));
2681 +
            return setNodeType(self, node, Type::U8);
2694 2682
        }
2695 2683
        case ast::NodeValue::String(text) => {
2696 -
            try setNodeConstValue(self, node, ConstValue::String(text));
2684 +
            setNodeConstValue(self, node, ConstValue::String(text));
2697 2685
            let byteTy = allocType(self, Type::U8);
2698 2686
            let sliceTy = allocType(self, Type::Slice {
2699 2687
                item: byteTy,
2700 2688
                mutable: false,
2701 2689
            });
2702 -
            return try setNodeType(self, node, *sliceTy);
2690 +
            return setNodeType(self, node, *sliceTy);
2703 2691
        },
2704 2692
        case ast::NodeValue::Number(lit) => {
2705 -
            try setNodeConstValue(self, node, ConstValue::Int(ConstInt {
2693 +
            setNodeConstValue(self, node, ConstValue::Int(ConstInt {
2706 2694
                magnitude: lit.magnitude,
2707 2695
                bits: 32,
2708 2696
                signed: lit.signed,
2709 2697
                negative: lit.negative,
2710 2698
            }));
2711 -
            return try setNodeType(self, node, Type::Int);
2699 +
            return setNodeType(self, node, Type::Int);
2712 2700
        },
2713 2701
        case ast::NodeValue::Placeholder => {
2714 -
            return try setNodeType(self, node, hint);
2702 +
            return setNodeType(self, node, hint);
2715 2703
        },
2716 2704
        else => {
2717 2705
            throw emitError(self, node, ErrorKind::UnexpectedNode(node));
2718 2706
        }
2719 2707
    }
2744 2732
    }
2745 2733
    return Type::Void;
2746 2734
}
2747 2735
2748 2736
/// Collect attribute flags applied to a declaration.
2749 -
fn resolveAttributes(self: *mut Resolver, attrs: ?ast::Attributes) -> u32
2750 -
    throws (ResolveError)
2751 -
{
2737 +
fn resolveAttributes(self: *mut Resolver, attrs: ?ast::Attributes) -> u32 {
2752 2738
    let list = attrs else return 0;
2753 2739
    let attrNodes = list.list;
2754 2740
    let mut mask: u32 = 0;
2755 2741
2756 2742
    for node in attrNodes {
2779 2765
    let blockTy = try visitList(self, block.statements) catch {
2780 2766
        // One of the statements in the block failed analysis. We simply proceed
2781 2767
        // without checking the rest of the block statements. Return `Never` to
2782 2768
        // avoid spurious `FnMissingReturn` errors.
2783 2769
        exitScope(self);
2784 -
        return try setNodeType(self, node, Type::Never);
2770 +
        return setNodeType(self, node, Type::Never);
2785 2771
    };
2786 2772
    exitScope(self);
2787 2773
2788 -
    return try setNodeType(self, node, blockTy);
2774 +
    return setNodeType(self, node, blockTy);
2789 2775
}
2790 2776
2791 2777
/// Analyze a `let` declaration and bind its identifier.
2792 2778
fn resolveLet(self: *mut Resolver, node: *ast::Node, decl: ast::Let) -> Type
2793 2779
    throws (ResolveError)
2825 2811
    // Alignment must be zero or a power of two.
2826 2812
    if alignment != 0 and (alignment & (alignment - 1)) != 0 {
2827 2813
        throw emitError(self, decl.value, ErrorKind::InvalidAlignmentValue(alignment));
2828 2814
    }
2829 2815
    let _ = try bindValueIdent(self, decl.ident, node, bindingTy, decl.mutable, alignment, 0);
2830 -
    try setNodeType(self, decl.value, bindingTy);
2816 +
    setNodeType(self, decl.value, bindingTy);
2831 2817
2832 2818
    return Type::Void;
2833 2819
}
2834 2820
2835 2821
/// Determine whether a node represents a compile-time constant expression.
2979 2965
    // Validate it fits within u32 range.
2980 2966
    if not validateConstIntRange(value, Type::U32) {
2981 2967
        throw emitError(self, node, ErrorKind::NumericLiteralOverflow);
2982 2968
    }
2983 2969
    assert not int.negative;
2984 -
    try setNodeType(self, node, Type::U32);
2970 +
    setNodeType(self, node, Type::U32);
2985 2971
2986 2972
    return int.magnitude as u32;
2987 2973
}
2988 2974
2989 2975
/// Check that constructor arguments match record fields.
3019 3005
    typeNode: *ast::Node,
3020 3006
    valueNode: *ast::Node,
3021 3007
    attrList: ?ast::Attributes,
3022 3008
    isConst: bool
3023 3009
) -> Type throws (ResolveError) {
3024 -
    let attrs = try resolveAttributes(self, attrList);
3010 +
    let attrs = resolveAttributes(self, attrList);
3025 3011
    let bindingTy = try infer(self, typeNode);
3026 3012
    let valueTy = try checkAssignable(self, valueNode, bindingTy);
3027 3013
3028 3014
    if isConst {
3029 3015
        let constVal = constValueEntry(self, valueNode);
3035 3021
        if not isConstExpr(self, valueNode) {
3036 3022
            throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
3037 3023
        }
3038 3024
        try bindValueIdent(self, ident, node, bindingTy, true, 0, attrs);
3039 3025
    }
3040 -
    try setNodeType(self, valueNode, bindingTy);
3026 +
    setNodeType(self, valueNode, bindingTy);
3041 3027
3042 3028
    return Type::Void;
3043 3029
}
3044 3030
3045 3031
/// Analyze a function declaration signature and bind the function name.
3046 3032
fn resolveFnDecl(self: *mut Resolver, node: *ast::Node, decl: ast::FnDecl) -> Type
3047 3033
    throws (ResolveError)
3048 3034
{
3049 -
    let attrMask = try resolveAttributes(self, decl.attrs);
3035 +
    let attrMask = resolveAttributes(self, decl.attrs);
3050 3036
    let mut retTy = Type::Void;
3051 3037
    if let retNode = decl.sig.returnType {
3052 3038
        retTy = try infer(self, retNode);
3053 3039
    }
3054 3040
    let a = alloc::arenaAllocator(&mut self.arena);
3235 3221
3236 3222
/// Bind a type name.
3237 3223
fn bindTypeName(self: *mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol
3238 3224
    throws (ResolveError)
3239 3225
{
3240 -
    let attrMask = try resolveAttributes(self, attrs);
3226 +
    let attrMask = resolveAttributes(self, attrs);
3241 3227
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
3242 3228
3243 3229
    // Create a placeholder nominal type that will be replaced in
3244 3230
    // the next phase.
3245 3231
    let nominalTy = allocNominalType(self, NominalType::Placeholder(node));
3258 3244
3259 3245
/// Bind a trait name in the current scope.
3260 3246
fn bindTraitName(self: *mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol
3261 3247
    throws (ResolveError)
3262 3248
{
3263 -
    let attrMask = try resolveAttributes(self, attrs);
3249 +
    let attrMask = resolveAttributes(self, attrs);
3264 3250
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
3265 3251
3266 3252
    let traitName = try nodeName(self, name);
3267 3253
    let traitType = allocTraitType(self, traitName);
3268 3254
    let data = SymbolData::Trait(traitType);
3269 3255
    let sym = try bindIdent(self, traitName, node, data, attrMask, self.scope);
3270 3256
3271 -
    try setNodeType(self, node, Type::Void);
3272 -
    try setNodeType(self, name, Type::Void);
3257 +
    setNodeType(self, node, Type::Void);
3258 +
    setNodeType(self, name, Type::Void);
3273 3259
3274 3260
    return sym;
3275 3261
}
3276 3262
3277 3263
/// Find a trait method by name.
3296 3282
    // Resolve supertrait bounds and copy their methods into this trait.
3297 3283
    for superNode in supertraits {
3298 3284
        let superSym = try resolveNamePath(self, superNode);
3299 3285
        let case SymbolData::Trait(superTrait) = superSym.data
3300 3286
            else throw emitError(self, superNode, ErrorKind::Internal);
3301 -
        try setNodeSymbol(self, superNode, superSym);
3287 +
        setNodeSymbol(self, superNode, superSym);
3302 3288
3303 3289
        let a = alloc::arenaAllocator(&mut self.arena);
3304 3290
        if traitType.methods.len + superTrait.methods.len > ast::MAX_TRAIT_METHODS {
3305 3291
            throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
3306 3292
                expected: ast::MAX_TRAIT_METHODS,
3395 3381
            fnType: allocFnType(self, fnType),
3396 3382
            mutable,
3397 3383
            index: traitType.methods.len as u32,
3398 3384
        }, a);
3399 3385
3400 -
        try setNodeType(self, methodNode, Type::Void);
3386 +
        setNodeType(self, methodNode, Type::Void);
3401 3387
    }
3402 3388
}
3403 3389
3404 3390
/// Resolve a name path node to a symbol.
3405 3391
/// Used for trait and type references in instance declarations and trait objects.
3434 3420
    // Look up the trait.
3435 3421
    let traitSym = try resolveNamePath(self, traitName);
3436 3422
    let case SymbolData::Trait(traitInfo) = traitSym.data
3437 3423
        else throw emitError(self, traitName, ErrorKind::Internal);
3438 3424
3439 -
    try setNodeSymbol(self, traitName, traitSym);
3425 +
    setNodeSymbol(self, traitName, traitSym);
3440 3426
3441 3427
    // Look up the target type.
3442 3428
    let typeSym = try resolveNamePath(self, targetType);
3443 3429
    let case SymbolData::Type(nominalTy) = typeSym.data
3444 3430
        else throw emitError(self, targetType, ErrorKind::Internal);
3445 -
    try setNodeSymbol(self, targetType, typeSym);
3431 +
    setNodeSymbol(self, targetType, typeSym);
3446 3432
    // Ensure the concrete type body is resolved.
3447 3433
    try ensureNominalResolved(self, nominalTy, targetType);
3448 3434
3449 3435
    // Reject duplicate instance for the same (trait, type) pair.
3450 3436
    let concreteType = Type::Nominal(nominalTy);
3582 3568
        let mName = try nodeName(self, name);
3583 3569
        let sym = allocSymbol(self, SymbolData::Value {
3584 3570
            mutable: false, alignment: 0, type: fnTy, addressTaken: false,
3585 3571
        }, mName, methodNode, 0);
3586 3572
3587 -
        try setNodeSymbol(self, methodNode, sym);
3588 -
        try setNodeType(self, methodNode, fnTy);
3589 -
        try setNodeType(self, name, fnTy);
3573 +
        setNodeSymbol(self, methodNode, sym);
3574 +
        setNodeType(self, methodNode, fnTy);
3575 +
        setNodeType(self, name, fnTy);
3590 3576
3591 3577
        // Store in instance entry at the matching v-table slot.
3592 3578
        entry.methods[tm.index] = sym;
3593 3579
        covered[tm.index] = true;
3594 3580
    }
3614 3600
        }
3615 3601
    }
3616 3602
    self.instances[self.instancesLen] = entry;
3617 3603
    self.instancesLen += 1;
3618 3604
3619 -
    try setNodeType(self, node, Type::Void);
3605 +
    setNodeType(self, node, Type::Void);
3620 3606
}
3621 3607
3622 3608
/// Resolve instance method bodies.
3623 3609
fn resolveInstanceMethodBodies(self: *mut Resolver, methods: *mut [*ast::Node])
3624 3610
    throws (ResolveError)
3765 3751
{
3766 3752
    if not shouldAnalyzeModule(self, decl.attrs) {
3767 3753
        return;
3768 3754
    }
3769 3755
    let modName = try nodeName(self, decl.name);
3770 -
    let attrMask = try resolveAttributes(self, decl.attrs);
3756 +
    let attrMask = resolveAttributes(self, decl.attrs);
3771 3757
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
3772 3758
    let submod = try enterSubModule(self, modName, node);
3773 3759
3774 3760
    // Bind the module symbol in the outer scope, ie. where the `mod` statement is.
3775 3761
    try bindModuleIdent(self, submod.entry, submod.newScope, submod.root, attrMask, submod.prevScope);
3800 3786
/// Analyze a `use` statement and create a symbol for the imported module.
3801 3787
fn resolveUse(self: *mut Resolver, node: *ast::Node, decl: ast::Use) -> Type
3802 3788
    throws (ResolveError)
3803 3789
{
3804 3790
    let resolved = try resolveModulePath(self, decl.path);
3805 -
    let attrMask = try resolveAttributes(self, decl.attrs);
3791 +
    let attrMask = resolveAttributes(self, decl.attrs);
3806 3792
3807 3793
    if decl.wildcard {
3808 3794
        // Import all public symbols from the target module.
3809 3795
        for i in 0..resolved.scope.symbolsLen {
3810 3796
            let sym = resolved.scope.symbols[i];
3825 3811
{
3826 3812
    try checkBoolean(self, cond.condition);
3827 3813
    let thenTy = try visit(self, cond.thenBranch, Type::Void);
3828 3814
    let elseTy = try visitOptional(self, cond.elseBranch, Type::Void);
3829 3815
3830 -
    return try setNodeType(self, node, unifyBranches(thenTy, elseTy));
3816 +
    return setNodeType(self, node, unifyBranches(thenTy, elseTy));
3831 3817
}
3832 3818
3833 3819
/// Analyze a conditional expression.
3834 3820
fn resolveCondExpr(self: *mut Resolver, node: *ast::Node, cond: ast::CondExpr) -> Type
3835 3821
    throws (ResolveError)
3836 3822
{
3837 3823
    try checkBoolean(self, cond.condition);
3838 3824
    let thenTy = try infer(self, cond.thenExpr);
3839 3825
    let _ = try checkAssignable(self, cond.elseExpr, thenTy);
3840 3826
3841 -
    return try setNodeType(self, node, thenTy);
3827 +
    return setNodeType(self, node, thenTy);
3842 3828
}
3843 3829
3844 3830
/// Analyze a pattern match structure (used by if-let, while-let).
3845 3831
fn resolvePatternMatch(self: *mut Resolver, node: *ast::Node, pat: *ast::PatternMatch)
3846 3832
    throws (ResolveError)
3856 3842
            // Scrutinee must be optional, bind the payload.
3857 3843
            let scrutineeTy = try checkOptional(self, pat.scrutinee);
3858 3844
            let payloadTy = *scrutineeTy;
3859 3845
3860 3846
            try bindValueIdent(self, pat.pattern, node, payloadTy, false, 0, 0);
3861 -
            try setNodeType(self, pat.pattern, payloadTy);
3847 +
            setNodeType(self, pat.pattern, payloadTy);
3862 3848
        }
3863 3849
    }
3864 3850
    if let guard = pat.guard {
3865 3851
        try checkBoolean(self, guard);
3866 3852
    }
3876 3862
    let thenTy = try visit(self, cond.thenBranch, Type::Void);
3877 3863
    exitScope(self);
3878 3864
3879 3865
    let elseTy = try visitOptional(self, cond.elseBranch, Type::Void);
3880 3866
3881 -
    return try setNodeType(self, node, unifyBranches(thenTy, elseTy));
3867 +
    return setNodeType(self, node, unifyBranches(thenTy, elseTy));
3882 3868
}
3883 3869
3884 3870
/// Controls how bare identifiers are handled in case patterns.
3885 3871
union IdentMode {
3886 3872
    /// Identifier is a value to compare against.
3954 3940
{
3955 3941
    try checkBoolean(self, loopNode.condition);
3956 3942
    try visitLoop(self, loopNode.body);
3957 3943
    try visitOptional(self, loopNode.elseBranch, Type::Void);
3958 3944
3959 -
    return try setNodeType(self, node, Type::Void);
3945 +
    return setNodeType(self, node, Type::Void);
3960 3946
}
3961 3947
3962 3948
/// Analyze a `while let` loop with pattern binding.
3963 3949
fn resolveWhileLet(self: *mut Resolver, node: *ast::Node, loopNode: ast::WhileLet) -> Type
3964 3950
    throws (ResolveError)
3969 3955
    try visitLoop(self, loopNode.body);
3970 3956
    exitScope(self);
3971 3957
3972 3958
    try visitOptional(self, loopNode.elseBranch, Type::Void);
3973 3959
3974 -
    return try setNodeType(self, node, Type::Void);
3960 +
    return setNodeType(self, node, Type::Void);
3975 3961
}
3976 3962
3977 3963
/// Analyze a `for` loop, binding iteration variables.
3978 3964
fn resolveFor(self: *mut Resolver, node: *ast::Node, forStmt: ast::For) -> Type
3979 3965
    throws (ResolveError)
4003 3989
            let case ast::NodeValue::Range(range) = forStmt.iterable.value else {
4004 3990
                throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable);
4005 3991
            };
4006 3992
            itemTy = *valType;
4007 3993
4008 -
            try setForLoopInfo(self, node, ForLoopInfo::Range {
3994 +
            setForLoopInfo(self, node, ForLoopInfo::Range {
4009 3995
                valType, range, bindingName, indexName
4010 3996
            });
4011 3997
        }
4012 3998
        case Type::Array(arrayInfo) => {
4013 3999
            itemTy = *arrayInfo.item;
4014 -
            try setForLoopInfo(self, node, ForLoopInfo::Collection {
4000 +
            setForLoopInfo(self, node, ForLoopInfo::Collection {
4015 4001
                elemType: arrayInfo.item,
4016 4002
                length: arrayInfo.length,
4017 4003
                bindingName,
4018 4004
                indexName,
4019 4005
            });
4020 4006
        }
4021 4007
        case Type::Slice { item, .. } => {
4022 4008
            itemTy = *item;
4023 -
            try setForLoopInfo(self, node, ForLoopInfo::Collection {
4009 +
            setForLoopInfo(self, node, ForLoopInfo::Collection {
4024 4010
                elemType: item, length: nil, bindingName, indexName
4025 4011
            });
4026 4012
        }
4027 4013
        else => throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable),
4028 4014
    }
4041 4027
    try visitLoop(self, forStmt.body);
4042 4028
    exitScope(self);
4043 4029
4044 4030
    try visitOptional(self, forStmt.elseBranch, Type::Void);
4045 4031
4046 -
    return try setNodeType(self, node, Type::Void);
4032 +
    return setNodeType(self, node, Type::Void);
4047 4033
}
4048 4034
4049 4035
/// Check whether any pattern in a case prong is a wildcard `_`.
4050 4036
fn hasWildcardPattern(patterns: *mut [*ast::Node]) -> bool {
4051 4037
    for pattern in patterns {
4083 4069
        if state.catchAll {
4084 4070
            throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll);
4085 4071
        }
4086 4072
        state.catchAll = true;
4087 4073
    }
4088 -
    try setProngCatchAll(self, prongNode, isCatchAll);
4074 +
    setProngCatchAll(self, prongNode, isCatchAll);
4089 4075
4090 4076
    return try visitMatchProng(self, prongNode, prong, subjectTy, matchType, matchBy);
4091 4077
}
4092 4078
4093 4079
/// Analyze a `match` expression. Dispatches to specialized functions based on
4113 4099
    // Mark last non-guarded prong as exhaustive.
4114 4100
    let lastProng = sw.prongs[sw.prongs.len - 1];
4115 4101
    let case ast::NodeValue::MatchProng(p) = lastProng.value
4116 4102
        else panic "resolveMatch: expected match prong";
4117 4103
    if p.guard == nil {
4118 -
        try setProngCatchAll(self, lastProng, true);
4104 +
        setProngCatchAll(self, lastProng, true);
4119 4105
    }
4120 4106
    let ty = typeFor(self, node) else {
4121 4107
        return Type::Void;
4122 4108
    };
4123 4109
    return ty;
4155 4141
                case ast::ProngArm::Binding(_) => {
4156 4142
                    // For optionals, a binding does *not* always match.
4157 4143
                }
4158 4144
            }
4159 4145
        }
4160 -
        try setProngCatchAll(self, prongNode, isCatchAll);
4146 +
        setProngCatchAll(self, prongNode, isCatchAll);
4161 4147
        matchType = try visitMatchProng(self, prongNode, prong, subjectTy, matchType, MatchBy::Value);
4162 4148
4163 4149
        // Track coverage. Guarded prongs don't count as covering a case.
4164 4150
        if prong.guard == nil {
4165 4151
            if let case ast::ProngArm::Binding(_) = prong.arm {
4189 4175
            throw emitError(self, node, ErrorKind::OptionalMatchMissingNil);
4190 4176
        }
4191 4177
    } else if hasValue and hasNil {
4192 4178
        throw emitError(self, node, ErrorKind::UnreachableElse);
4193 4179
    }
4194 -
    return try setNodeType(self, node, matchType);
4180 +
    return setNodeType(self, node, matchType);
4195 4181
}
4196 4182
4197 4183
/// Analyze a `match` expression on a union subject.
4198 4184
fn resolveMatchUnion(
4199 4185
    self: *mut Resolver,
4240 4226
            }
4241 4227
        }
4242 4228
    } else if coveredCount == info.variants.len as u32 {
4243 4229
        throw emitError(self, node, ErrorKind::UnreachableElse);
4244 4230
    }
4245 -
    return try setNodeType(self, node, matchType);
4231 +
    return setNodeType(self, node, matchType);
4246 4232
}
4247 4233
4248 4234
/// Analyze a `match` expression on a generic subject type. Requires exhaustiveness:
4249 4235
/// booleans must cover both `true` and `false`, other types require a catch-all.
4250 4236
fn resolveMatchGeneric(self: *mut Resolver, node: *ast::Node, sw: ast::Match, subjectTy: Type) -> Type
4307 4293
            throw emitError(self, node, ErrorKind::UnreachableElse);
4308 4294
        }
4309 4295
    }
4310 4296
    setMatchConst(self, node, state.isConst and hasConstCase);
4311 4297
4312 -
    return try setNodeType(self, node, matchType);
4298 +
    return setNodeType(self, node, matchType);
4313 4299
}
4314 4300
4315 4301
/// Analyze a single `match` prong branch. Returns the unified match type.
4316 4302
fn visitMatchProng(
4317 4303
    self: *mut Resolver,
4325 4311
    let prongTy = try resolveMatchProngBody(self, prongNode, subjectTy, matchBy) catch {
4326 4312
        exitScope(self);
4327 4313
        throw ResolveError::Failure; // TODO: Rethrow same error.
4328 4314
    };
4329 4315
    exitScope(self);
4330 -
    try setNodeType(self, node, prongTy);
4316 +
    setNodeType(self, node, prongTy);
4331 4317
4332 4318
    return unifyBranches(matchType, prongTy);
4333 4319
}
4334 4320
4335 4321
/// Analyze the contents of a `match` prong while inside the prong scope.
4487 4473
                let fieldName = try nodeName(self, label);
4488 4474
                let fieldIndex = findRecordField(&recInfo, fieldName)
4489 4475
                    else throw emitError(self, fieldNode, ErrorKind::RecordFieldUnknown(fieldName));
4490 4476
                let fieldType = recInfo.fields[fieldIndex].fieldType;
4491 4477
                // Store field index for the lowerer.
4492 -
                try setRecordFieldIndex(self, fieldNode, fieldIndex);
4478 +
                setRecordFieldIndex(self, fieldNode, fieldIndex);
4493 4479
                try bindPatternVar(self, field.value, fieldType, matchBy);
4494 4480
            }
4495 4481
        }
4496 4482
        else => throw emitError(self, pattern, ErrorKind::Internal)
4497 4483
    }
4574 4560
                let payloadTy = *inner;
4575 4561
                let _ = try bindValueIdent(self, pat.pattern, node, payloadTy, false, 0, 0);
4576 4562
                // The `else` branch must be assignable to the payload type.
4577 4563
                try checkAssignable(self, letElse.elseBranch, payloadTy);
4578 4564
4579 -
                return try setNodeType(self, node, Type::Void);
4565 +
                return setNodeType(self, node, Type::Void);
4580 4566
            }
4581 4567
            // FIXME: This shouldn't be valid, should it? What scenario needs this?
4582 4568
            // Fall through to pattern matching if not optional.
4583 4569
            try resolveCasePattern(self, pat.pattern, exprTy, IdentMode::Compare, MatchBy::Value);
4584 4570
        }
4591 4577
        try checkBoolean(self, guardExpr);
4592 4578
    }
4593 4579
    // The `else` branch must be assignable to the expression type.
4594 4580
    try checkAssignable(self, letElse.elseBranch, exprTy);
4595 4581
4596 -
    return try setNodeType(self, node, Type::Void);
4582 +
    return setNodeType(self, node, Type::Void);
4597 4583
}
4598 4584
4599 4585
/// Analyze builtin function calls like `@sizeOf(T)` and `@alignOf(T)`.
4600 4586
fn resolveBuiltinCall(
4601 4587
    self: *mut Resolver,
4617 4603
        };
4618 4604
        let _ = try checkAssignable(self, args[1], Type::U32);
4619 4605
        if args.len == 3 {
4620 4606
            let _ = try checkAssignable(self, args[2], Type::U32);
4621 4607
        }
4622 -
        return try setNodeType(self, node, Type::Slice { item: target, mutable });
4608 +
        return setNodeType(self, node, Type::Slice { item: target, mutable });
4623 4609
    }
4624 4610
    if args.len != 1 {
4625 4611
        throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch {
4626 4612
            expected: 1,
4627 4613
            actual: args.len as u32,
4649 4635
        case ast::Builtin::SliceOf => {
4650 4636
            panic "unreachable: @sliceOf handled above";
4651 4637
        }
4652 4638
    }
4653 4639
    // Record as constant value for constant folding.
4654 -
    try setNodeConstValue(self, node, ConstValue::Int(ConstInt {
4640 +
    setNodeConstValue(self, node, ConstValue::Int(ConstInt {
4655 4641
        magnitude: value as u64,
4656 4642
        bits: 32,
4657 4643
        signed: false,
4658 4644
        negative: false,
4659 4645
    }));
4660 -
    return try setNodeType(self, node, Type::U32);
4646 +
    return setNodeType(self, node, Type::U32);
4661 4647
}
4662 4648
4663 4649
/// Validate call arguments against a function type: check argument count,
4664 4650
/// type-check each argument, and verify that throwing functions use `try`.
4665 4651
fn checkCallArgs(self: *mut Resolver, node: *ast::Node, call: ast::Call, info: *FnType, ctx: CallCtx)
4744 4730
                throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
4745 4731
            }
4746 4732
            try checkCallArgs(self, node, call, method.fnType, ctx);
4747 4733
            setTraitMethodCall(self, node, traitInfo, method.index);
4748 4734
4749 -
            return try setNodeType(self, node, *method.fnType.returnType);
4735 +
            return setNodeType(self, node, *method.fnType.returnType);
4750 4736
        }
4751 4737
    }
4752 4738
    let case Type::Fn(info) = calleeTy else {
4753 4739
        // TODO: Emit type error.
4754 4740
        panic;
4755 4741
    };
4756 4742
    try checkCallArgs(self, node, call, info, ctx);
4757 4743
    // Associate function type to callee.
4758 -
    try setNodeType(self, call.callee, calleeTy);
4744 +
    setNodeType(self, call.callee, calleeTy);
4759 4745
4760 4746
    // Associate return type to call.
4761 -
    return try setNodeType(self, node, *info.returnType);
4747 +
    return setNodeType(self, node, *info.returnType);
4762 4748
}
4763 4749
4764 4750
/// Resolve `slice.append(val, allocator)`.
4765 4751
fn resolveSliceAppend(
4766 4752
    self: *mut Resolver,
4784 4770
    // Second argument: the allocator. We accept any type -- the lowerer
4785 4771
    // reads .func and .ctx at fixed offsets (structurally typed).
4786 4772
    try visit(self, args[1], Type::Unknown);
4787 4773
    self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType };
4788 4774
4789 -
    return try setNodeType(self, node, Type::Void);
4775 +
    return setNodeType(self, node, Type::Void);
4790 4776
}
4791 4777
4792 4778
/// Resolve `slice.delete(index)`.
4793 4779
fn resolveSliceDelete(
4794 4780
    self: *mut Resolver,
4808 4794
        }));
4809 4795
    }
4810 4796
    try checkAssignable(self, args[0], Type::U32);
4811 4797
    self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType };
4812 4798
4813 -
    return try setNodeType(self, node, Type::Void);
4799 +
    return setNodeType(self, node, Type::Void);
4814 4800
}
4815 4801
4816 4802
/// Analyze an assignment expression.
4817 4803
fn resolveAssign(self: *mut Resolver, node: *ast::Node, assign: ast::Assign) -> Type
4818 4804
    throws (ResolveError)
4823 4809
    if not try canBorrowMutFrom(self, assign.left) {
4824 4810
        throw emitError(self, assign.left, ErrorKind::ImmutableBinding);
4825 4811
    }
4826 4812
    try checkAssignable(self, assign.right, leftTy);
4827 4813
4828 -
    return try setNodeType(self, node, leftTy);
4814 +
    return setNodeType(self, node, leftTy);
4829 4815
}
4830 4816
4831 4817
/// Ensure slice range bounds are valid `u32` values.
4832 4818
fn checkSliceRangeIndices(self: *mut Resolver, range: ast::Range) throws (ResolveError) {
4833 4819
    if let start = range.start {
4881 4867
    let _ = try checkAssignable(self, indexNode, Type::U32);
4882 4868
    let subjectTy = autoDeref(containerTy);
4883 4869
4884 4870
    match subjectTy {
4885 4871
        case Type::Array(arrayInfo) => {
4886 -
            return try setNodeType(self, node, *arrayInfo.item);
4872 +
            return setNodeType(self, node, *arrayInfo.item);
4887 4873
        }
4888 4874
        case Type::Slice { item, .. } => {
4889 -
            return try setNodeType(self, node, *item);
4875 +
            return setNodeType(self, node, *item);
4890 4876
        }
4891 4877
        else => {
4892 4878
            throw emitError(self, container, ErrorKind::ExpectedIndexable);
4893 4879
        }
4894 4880
    }
4932 4918
    } else {
4933 4919
        if call.args.len > 0 {
4934 4920
            throw emitError(self, node, ErrorKind::UnionVariantPayloadUnexpected(variant.name));
4935 4921
        }
4936 4922
    }
4937 -
    return try setNodeType(self, node, Type::Nominal(unionNominal));
4923 +
    return setNodeType(self, node, Type::Nominal(unionNominal));
4938 4924
}
4939 4925
4940 4926
/// Analyze an unlabeled record constructor call.
4941 4927
///
4942 4928
/// Handles the syntax `R(a, b)` for unlabeled records, checking that the
4947 4933
{
4948 4934
    let case NominalType::Record(recInfo) = *recordType
4949 4935
        else panic "resolveRecordConstructorCall: not a record type";
4950 4936
4951 4937
    try checkRecordConstructorArgs(self, node, call.args, recInfo);
4952 -
    return try setNodeType(self, node, Type::Nominal(recordType));
4938 +
    return setNodeType(self, node, Type::Nominal(recordType));
4953 4939
}
4954 4940
4955 4941
/// Resolve the type name of a record literal, handling both record types and
4956 4942
/// union variant payloads like `Union::Variant { ... }`.
4957 4943
fn resolveRecordLitType(
5048 5034
            throw emitError(self, fieldNode, ErrorKind::RecordFieldOutOfOrder {
5049 5035
                field: fieldName,
5050 5036
                prev: expectedName,
5051 5037
            });
5052 5038
        }
5053 -
        try setRecordFieldIndex(self, fieldNode, idx);
5039 +
        setRecordFieldIndex(self, fieldNode, idx);
5054 5040
        try checkAssignable(self, fieldArg.value, expected.fieldType);
5055 -
        try setNodeType(self, fieldNode, expected.fieldType);
5041 +
        setNodeType(self, fieldNode, expected.fieldType);
5056 5042
    }
5057 -
    return try setNodeType(self, node, resultType);
5043 +
    return setNodeType(self, node, resultType);
5058 5044
}
5059 5045
5060 5046
/// Analyze an anonymous record literal, checking fields against the hint type.
5061 5047
fn resolveAnonRecordLit(self: *mut Resolver, node: *ast::Node, lit: ast::RecordLit, hint: Type) -> Type
5062 5048
    throws (ResolveError)
5105 5091
            throw emitError(self, fieldNode, ErrorKind::RecordFieldOutOfOrder {
5106 5092
                field: fieldName,
5107 5093
                prev: expectedName,
5108 5094
            });
5109 5095
        }
5110 -
        try setRecordFieldIndex(self, fieldNode, idx);
5096 +
        setRecordFieldIndex(self, fieldNode, idx);
5111 5097
        let fieldType = try visit(self, fieldArg.value, expected.fieldType);
5112 5098
5113 5099
        try expectAssignable(self, expected.fieldType, fieldType, fieldArg.value);
5114 -
        try setNodeType(self, fieldNode, fieldType);
5100 +
        setNodeType(self, fieldNode, fieldType);
5115 5101
    }
5116 -
    return try setNodeType(self, node, innerHint);
5102 +
    return setNodeType(self, node, innerHint);
5117 5103
}
5118 5104
5119 5105
/// Analyze an array literal expression.
5120 5106
fn resolveArrayLit(self: *mut Resolver, node: *ast::Node, items: *mut [*ast::Node], hint: Type) -> Type
5121 5107
    throws (ResolveError)
5139 5125
    }
5140 5126
    if expectedTy == Type::Unknown {
5141 5127
        throw emitError(self, node, ErrorKind::CannotInferType);
5142 5128
    };
5143 5129
    let arrayTy = Type::Array(ArrayType { item: allocType(self, expectedTy), length });
5144 -
    return try setNodeType(self, node, arrayTy);
5130 +
    return setNodeType(self, node, arrayTy);
5145 5131
}
5146 5132
5147 5133
/// Analyze an array repeat literal expression.
5148 5134
fn resolveArrayRepeat(self: *mut Resolver, node: *ast::Node, lit: ast::ArrayRepeatLit, hint: Type) -> Type
5149 5135
    throws (ResolveError)
5152 5138
    let count = try checkSizeInt(self, lit.count);
5153 5139
    let arrayTy = Type::Array(ArrayType {
5154 5140
        item: allocType(self, valueTy),
5155 5141
        length: count,
5156 5142
    });
5157 -
    return try setNodeType(self, node, arrayTy);
5143 +
    return setNodeType(self, node, arrayTy);
5158 5144
}
5159 5145
5160 5146
/// Resolve union variant access.
5161 5147
fn resolveUnionVariantAccess(
5162 5148
    self: *mut Resolver,
5171 5157
        if variant.name == variantName {
5172 5158
            let case SymbolData::Variant { ordinal, index, .. } = variant.symbol.data
5173 5159
                else panic "resolveUnionVariantAccess: expected variant symbol";
5174 5160
5175 5161
            // Associate the variant symbol with the child node.
5176 -
            try setNodeSymbol(self, access.child, variant.symbol);
5177 -
            try setNodeSymbol(self, node, variant.symbol);
5162 +
            setNodeSymbol(self, access.child, variant.symbol);
5163 +
            setNodeSymbol(self, node, variant.symbol);
5178 5164
5179 5165
            // Store the variant index for the lowerer.
5180 5166
            setVariantInfo(self, node, ordinal, index);
5181 5167
5182 5168
            return variant.symbol;
5192 5178
    let sym = try resolveAccess(self, node, access, self.scope);
5193 5179
    let mut ty: Type = undefined;
5194 5180
5195 5181
    match sym.data {
5196 5182
        case SymbolData::Value { type, .. } => {
5197 -
            try setNodeSymbol(self, node, sym);
5183 +
            setNodeSymbol(self, node, sym);
5198 5184
            ty = type;
5199 5185
        }
5200 5186
        case SymbolData::Constant { type, value } => {
5201 5187
            // Propagate the constant value.
5202 5188
            if let val = value {
5203 -
                try setNodeConstValue(self, node, val);
5189 +
                setNodeConstValue(self, node, val);
5204 5190
            }
5205 -
            try setNodeSymbol(self, node, sym);
5191 +
            setNodeSymbol(self, node, sym);
5206 5192
            ty = type;
5207 5193
        }
5208 5194
        case SymbolData::Type(t) => ty = Type::Nominal(t),
5209 5195
        case SymbolData::Variant { index, .. } => {
5210 5196
            let ty = typeFor(self, node)
5211 5197
                else throw emitError(self, node, ErrorKind::Internal);
5212 5198
            // For unions without payload, store the variant index as a constant.
5213 5199
            if isVoidUnion(ty) {
5214 -
                try setNodeConstValue(self, node, ConstValue::Int(ConstInt {
5200 +
                setNodeConstValue(self, node, ConstValue::Int(ConstInt {
5215 5201
                    magnitude: index as u64,
5216 5202
                    bits: 32,
5217 5203
                    signed: false,
5218 5204
                    negative: false,
5219 5205
                }));
5220 5206
            }
5221 -
            return try setNodeType(self, node, ty);
5207 +
            return setNodeType(self, node, ty);
5222 5208
        }
5223 5209
        case SymbolData::Module { .. } => {
5224 5210
            throw emitError(self, node, ErrorKind::UnexpectedModuleName);
5225 5211
        }
5226 5212
        case SymbolData::Trait(_) => { // Trait names are not values.
5227 5213
            throw emitError(self, node, ErrorKind::UnexpectedTraitName);
5228 5214
        }
5229 5215
    }
5230 -
    return try setNodeType(self, node, ty);
5216 +
    return setNodeType(self, node, ty);
5231 5217
}
5232 5218
5233 5219
/// Analyze a field access expression.
5234 5220
fn resolveFieldAccess(self: *mut Resolver, node: *ast::Node, access: ast::Access) -> Type
5235 5221
    throws (ResolveError)
5244 5230
                let fieldName = try nodeName(self, fieldNode);
5245 5231
                let fieldIndex = findRecordField(&recordType, fieldName)
5246 5232
                    else throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
5247 5233
                let fieldTy = recordType.fields[fieldIndex].fieldType;
5248 5234
5249 -
                try setRecordFieldIndex(self, fieldNode, fieldIndex);
5235 +
                setRecordFieldIndex(self, fieldNode, fieldIndex);
5250 5236
5251 -
                return try setNodeType(self, node, fieldTy);
5237 +
                return setNodeType(self, node, fieldTy);
5252 5238
            }
5253 5239
        }
5254 5240
        case Type::Array(arrayInfo) => {
5255 5241
            let fieldNode = access.child;
5256 5242
            let fieldName = try nodeName(self, fieldNode);
5257 5243
5258 5244
            if mem::eq(fieldName, LEN_FIELD) {
5259 5245
                let lengthConst = constInt(arrayInfo.length as u64, 32, false, false);
5260 -
                try setNodeConstValue(self, node, lengthConst);
5246 +
                setNodeConstValue(self, node, lengthConst);
5261 5247
5262 -
                return try setNodeType(self, node, Type::U32);
5248 +
                return setNodeType(self, node, Type::U32);
5263 5249
            }
5264 5250
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
5265 5251
        }
5266 5252
        case Type::Slice { item, mutable } => {
5267 5253
            let fieldNode = access.child;
5268 5254
            let fieldName = try nodeName(self, fieldNode);
5269 5255
5270 5256
            if mem::eq(fieldName, PTR_FIELD) {
5271 -
                try setRecordFieldIndex(self, fieldNode, 0);
5257 +
                setRecordFieldIndex(self, fieldNode, 0);
5272 5258
                let ptrTy = Type::Pointer {
5273 5259
                    target: item,
5274 5260
                    mutable,
5275 5261
                };
5276 -
                return try setNodeType(self, node, ptrTy);
5262 +
                return setNodeType(self, node, ptrTy);
5277 5263
            }
5278 5264
            if mem::eq(fieldName, LEN_FIELD) {
5279 -
                try setRecordFieldIndex(self, fieldNode, 1);
5280 -
                return try setNodeType(self, node, Type::U32);
5265 +
                setRecordFieldIndex(self, fieldNode, 1);
5266 +
                return setNodeType(self, node, Type::U32);
5281 5267
            }
5282 5268
            if mem::eq(fieldName, CAP_FIELD) {
5283 -
                try setRecordFieldIndex(self, fieldNode, 2);
5284 -
                return try setNodeType(self, node, Type::U32);
5269 +
                setRecordFieldIndex(self, fieldNode, 2);
5270 +
                return setNodeType(self, node, Type::U32);
5285 5271
            }
5286 5272
            throw emitError(self, node, ErrorKind::SliceFieldUnknown(fieldName));
5287 5273
        }
5288 5274
        case Type::TraitObject { traitInfo, .. } => {
5289 5275
            let fieldName = try nodeName(self, access.child);
5290 5276
            let method = findTraitMethod(traitInfo, fieldName)
5291 5277
                else throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
5292 5278
5293 -
            return try setNodeType(self, node, Type::Fn(method.fnType));
5279 +
            return setNodeType(self, node, Type::Fn(method.fnType));
5294 5280
        }
5295 5281
        else => {}
5296 5282
    }
5297 5283
    // FIXME: We can't move this to the `else` branch due to a resolver bug.
5298 5284
    throw emitError(self, access.parent, ErrorKind::ExpectedRecord);
5396 5382
                    throw emitError(self, container, ErrorKind::ExpectedIndexable);
5397 5383
                }
5398 5384
            }
5399 5385
            let sliceTy = Type::Slice { item, mutable: addr.mutable };
5400 5386
            let alloc = allocType(self, sliceTy);
5401 -
            try setSliceRangeInfo(self, node, SliceRangeInfo {
5387 +
            setSliceRangeInfo(self, node, SliceRangeInfo {
5402 5388
                itemType: item,
5403 5389
                mutable: addr.mutable,
5404 5390
                capacity,
5405 5391
            });
5406 -
            try setNodeType(self, addr.target, *alloc);
5407 -
            return try setNodeType(self, node, *alloc);
5392 +
            setNodeType(self, addr.target, *alloc);
5393 +
            return setNodeType(self, node, *alloc);
5408 5394
        }
5409 5395
    }
5410 5396
    // Derive a hint for the target type from the slice hint.
5411 5397
    let mut targetHint: Type = Type::Unknown;
5412 5398
    if let case Type::Slice { item, .. } = hint {
5434 5420
            {
5435 5421
                let sliceTy = Type::Slice {
5436 5422
                    item: arrayInfo.item,
5437 5423
                    mutable: addr.mutable,
5438 5424
                };
5439 -
                return try setNodeType(self, node, *allocType(self, sliceTy));
5425 +
                return setNodeType(self, node, *allocType(self, sliceTy));
5440 5426
            }
5441 5427
            else => {}
5442 5428
        }
5443 5429
    }
5444 5430
    let pointerTy = Type::Pointer {
5445 5431
        target: allocType(self, targetTy),
5446 5432
        mutable: addr.mutable,
5447 5433
    };
5448 -
    return try setNodeType(self, node, pointerTy);
5434 +
    return setNodeType(self, node, pointerTy);
5449 5435
}
5450 5436
5451 5437
/// Analyze a dereference expression.
5452 5438
fn resolveDeref(self: *mut Resolver, node: *ast::Node, targetNode: *ast::Node, hint: Type) -> Type
5453 5439
    throws (ResolveError)
5456 5442
    if let case Type::Pointer { target, .. } = operandTy {
5457 5443
        // Disallow dereferencing opaque pointers.
5458 5444
        if *target == Type::Opaque {
5459 5445
            throw emitError(self, targetNode, ErrorKind::OpaqueTypeDeref);
5460 5446
        }
5461 -
        return try setNodeType(self, node, *target);
5447 +
        return setNodeType(self, node, *target);
5462 5448
    } else {
5463 5449
        throw emitError(self, targetNode, ErrorKind::ExpectedPointer);
5464 5450
    }
5465 5451
}
5466 5452
5531 5517
5532 5518
    assert sourceTy != Type::Unknown;
5533 5519
    assert targetTy != Type::Unknown;
5534 5520
5535 5521
    if isValidCast(sourceTy, targetTy) {
5536 -
        return try setNodeType(self, node, targetTy);
5522 +
        return setNodeType(self, node, targetTy);
5537 5523
    }
5538 5524
    throw emitError(self, node, ErrorKind::InvalidAsCast(InvalidAsCast {
5539 5525
        from: sourceTy,
5540 5526
        to: targetTy,
5541 5527
    }));
5571 5557
            start = allocType(self, startTy);
5572 5558
        }
5573 5559
    } else if let e = range.end {
5574 5560
        end = allocType(self, try checkNumeric(self, e));
5575 5561
    }
5576 -
    return try setNodeType(self, node, Type::Range { start, end });
5562 +
    return setNodeType(self, node, Type::Range { start, end });
5577 5563
}
5578 5564
5579 5565
/// Analyze a `try` expression and its handlers.
5580 5566
/// The `expected` type is used to determine if the value is discarded (`Void`)
5581 5567
/// or if the catch expression needs type checking.
5588 5574
    let resultTy = try resolveCall(self, call, callExpr, CallCtx::Try);
5589 5575
5590 5576
    // TODO: It's annoying that we need to re-fetch the function type after
5591 5577
    // analyzing the call.
5592 5578
    let calleeTy = typeFor(self, callExpr.callee)
5593 -
        else return try setNodeType(self, node, resultTy);
5579 +
        else return setNodeType(self, node, resultTy);
5594 5580
    let case Type::Fn(calleeInfo) = calleeTy
5595 5581
        else throw emitError(self, callExpr.callee, ErrorKind::TryNonThrowing);
5596 5582
5597 5583
    if calleeInfo.throwList.len == 0 {
5598 5584
        throw emitError(self, callExpr.callee, ErrorKind::TryNonThrowing);
5630 5616
            if not found {
5631 5617
                throw emitError(self, node, ErrorKind::TryIncompatibleError);
5632 5618
            }
5633 5619
        }
5634 5620
    }
5635 -
    return try setNodeType(self, node, tryResultTy);
5621 +
    return setNodeType(self, node, tryResultTy);
5636 5622
}
5637 5623
5638 5624
5639 5625
/// Check that a `catch` body is assignable to the expected result type, but only
5640 5626
/// in expression context (`hint` is neither `Unknown` nor `Void`).
5765 5751
        throw emitError(self, node, ErrorKind::ThrowRequiresThrows);
5766 5752
    }
5767 5753
    let throwTy = try infer(self, expr);
5768 5754
    for errTy in fnInfo.throwList {
5769 5755
        if let coerce = isAssignable(self, *errTy, throwTy, expr) {
5770 -
            try setNodeCoercion(self, expr, coerce);
5771 -
            return try setNodeType(self, node, Type::Never);
5756 +
            setNodeCoercion(self, expr, coerce);
5757 +
            return setNodeType(self, node, Type::Never);
5772 5758
        }
5773 5759
    }
5774 5760
    throw emitError(self, expr, ErrorKind::ThrowIncompatibleError);
5775 5761
}
5776 5762
5787 5773
    } else if expected != Type::Void {
5788 5774
        throw emitTypeMismatch(self, node, TypeMismatch { expected, actual: Type::Void });
5789 5775
    }
5790 5776
    // In throwing functions, return values are wrapped in the success variant.
5791 5777
    if f.throwList.len > 0 {
5792 -
        try setNodeCoercion(self, node, Coercion::ResultWrap);
5778 +
        setNodeCoercion(self, node, Coercion::ResultWrap);
5793 5779
    }
5794 -
    return try setNodeType(self, node, Type::Never);
5780 +
    return setNodeType(self, node, Type::Never);
5795 5781
}
5796 5782
5797 5783
/// Analyze a binary expression.
5798 5784
fn resolveBinOp(self: *mut Resolver, node: *ast::Node, binop: ast::BinOp) -> Type
5799 5785
    throws (ResolveError)
5829 5815
            // `42` to `?u8` (not `?i32`). We also record OptionalLift directly
5830 5816
            // rather than using expectAssignable, because comparisons should
5831 5817
            // allow e.g. `?*mut T == *T` where mutability differs.
5832 5818
            if let case Type::Optional(_) = leftTy {
5833 5819
                if not isOptionalType(rightTy) {
5834 -
                    try setNodeCoercion(self, binop.right, Coercion::OptionalLift(leftTy));
5820 +
                    setNodeCoercion(self, binop.right, Coercion::OptionalLift(leftTy));
5835 5821
                }
5836 5822
            } else if let case Type::Optional(_) = rightTy {
5837 -
                try setNodeCoercion(self, binop.left, Coercion::OptionalLift(rightTy));
5823 +
                setNodeCoercion(self, binop.left, Coercion::OptionalLift(rightTy));
5838 5824
            }
5839 5825
            resultTy = Type::Bool;
5840 5826
        },
5841 5827
        else => {
5842 5828
            // Check for pointer arithmetic before numeric check.
5851 5837
                if let case Type::Pointer { target: rightTarget, .. } = rightTy; *rightTarget == Type::Opaque {
5852 5838
                    throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
5853 5839
                }
5854 5840
                // Allow pointer plus integer or integer plus pointer.
5855 5841
                if let case Type::Pointer { .. } = leftTy; isNumericType(rightTy) {
5856 -
                    return try setNodeType(self, node, leftTy);
5842 +
                    return setNodeType(self, node, leftTy);
5857 5843
                }
5858 5844
                if binop.op == ast::BinaryOp::Add {
5859 5845
                    if let case Type::Pointer { .. } = rightTy; isNumericType(leftTy) {
5860 -
                        return try setNodeType(self, node, rightTy);
5846 +
                        return setNodeType(self, node, rightTy);
5861 5847
                    }
5862 5848
                }
5863 5849
            }
5864 5850
            let leftTy = try checkNumeric(self, binop.left);
5865 5851
            let rightTy = try checkNumeric(self, binop.right);
5885 5871
                }
5886 5872
            }
5887 5873
5888 5874
        }
5889 5875
    };
5890 -
    return try setNodeType(self, node, resultTy);
5876 +
    return setNodeType(self, node, resultTy);
5891 5877
}
5892 5878
5893 5879
/// Analyze a unary expression.
5894 5880
fn resolveUnOp(self: *mut Resolver, node: *ast::Node, unop: ast::UnOp) -> Type
5895 5881
    throws (ResolveError)
5899 5885
    match unop.op {
5900 5886
        case ast::UnaryOp::Not => {
5901 5887
            resultTy = try checkBoolean(self, unop.value);
5902 5888
            if let value = constValueFor(self, unop.value) {
5903 5889
                if let case ConstValue::Bool(val) = value {
5904 -
                    try setNodeConstValue(self, node, ConstValue::Bool(not val));
5890 +
                    setNodeConstValue(self, node, ConstValue::Bool(not val));
5905 5891
                }
5906 5892
            }
5907 5893
        },
5908 5894
        case ast::UnaryOp::Neg => {
5909 5895
            // TODO: Check that we're allowed to use `-` here? Should negation
5911 5897
            resultTy = try checkNumeric(self, unop.value);
5912 5898
            if let value = constValueFor(self, unop.value) {
5913 5899
                // Get the constant expression for the value, flip the sign,
5914 5900
                // and store that new expression on the unary op node.
5915 5901
                if let case ConstValue::Int(intVal) = value {
5916 -
                    try setNodeConstValue(
5902 +
                    setNodeConstValue(
5917 5903
                        self,
5918 5904
                        node,
5919 5905
                        constInt(intVal.magnitude, intVal.bits, true, not intVal.negative)
5920 5906
                    );
5921 5907
                }
5923 5909
        },
5924 5910
        case ast::UnaryOp::BitNot => {
5925 5911
            resultTy = try checkNumeric(self, unop.value);
5926 5912
        },
5927 5913
    };
5928 -
    return try setNodeType(self, node, resultTy);
5914 +
    return setNodeType(self, node, resultTy);
5929 5915
}
5930 5916
5931 5917
/// Resolve a type signature node and set its type.
5932 5918
fn inferTypeSig(self: *mut Resolver, node: *ast::Node, sig: ast::TypeSig) -> Type
5933 5919
    throws (ResolveError)
5934 5920
{
5935 5921
    let resolved = try resolveTypeSig(self, node, sig);
5936 5922
5937 -
    return try setNodeType(self, node, resolved);
5923 +
    return setNodeType(self, node, resolved);
5938 5924
}
5939 5925
5940 5926
/// Convert a type signature node into a type value.
5941 5927
fn resolveTypeSig(self: *mut Resolver, node: *ast::Node, sig: ast::TypeSig) -> Type
5942 5928
    throws (ResolveError)
6036 6022
        }
6037 6023
        case ast::TypeSig::TraitObject { traitName, mutable } => {
6038 6024
            let sym = try resolveNamePath(self, traitName);
6039 6025
            let case SymbolData::Trait(traitInfo) = sym.data
6040 6026
                else throw emitError(self, traitName, ErrorKind::Internal);
6041 -
            try setNodeSymbol(self, traitName, sym);
6027 +
            setNodeSymbol(self, traitName, sym);
6042 6028
6043 6029
            return Type::TraitObject { traitInfo, mutable };
6044 6030
        }
6045 6031
    }
6046 6032
}
6091 6077
    };
6092 6078
    try resolveModuleDefs(self, &block) catch {
6093 6079
        return Diagnostics { errors: self.errors };
6094 6080
    };
6095 6081
    exitScope(self);
6096 -
    try setNodeType(self, root, Type::Void);
6082 +
    setNodeType(self, root, Type::Void);
6097 6083
6098 6084
    return Diagnostics { errors: self.errors };
6099 6085
}
6100 6086
6101 6087
/// Analyze the module graph. This pass processes `mod` statements, creating symbols
6285 6271
6286 6272
    // Definition phase: analyze function bodies and sub-module definitions.
6287 6273
    try resolveModuleDefs(self, &block) catch {
6288 6274
        assert self.errors.len > 0, "resolvePackage: failure should have diagnostics";
6289 6275
    };
6290 -
    try setNodeType(self, node, Type::Void);
6276 +
    setNodeType(self, node, Type::Void);
6291 6277
6292 6278
    return Diagnostics { errors: self.errors };
6293 6279
}