Remove `throws` from non-fallible functions
0f9c16bcf6dedf46c9f8a7823025de31164f8446154da0730662f20a0247efc7
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 | } |