diff --git a/src/codegen/infrastructure/type-system.ts b/src/codegen/infrastructure/type-system.ts index 6c77b4da..57b38c64 100644 --- a/src/codegen/infrastructure/type-system.ts +++ b/src/codegen/infrastructure/type-system.ts @@ -229,6 +229,35 @@ export function fieldTypeToLlvmPrimitive(fieldType: string): string | null { return null; } +export function fieldTypeToLlvm(fieldType: string): string { + const prim = fieldTypeToLlvmPrimitive(fieldType); + if (prim) return prim; + const ak = classifyArray(fieldType); + if (ak !== ArrayKind_None) return arrayKindToLlvm(ak); + if (fieldType.startsWith("Map<")) + return fieldType.startsWith("Map") return "%StringSet*"; + if (fieldType.startsWith("Set<")) return "%Set*"; + if (fieldType.indexOf(" | ") !== -1) { + const parts = fieldType.split(" | "); + for (let i = 0; i < parts.length; i++) { + const part = parts[i].trim(); + if (part === "null" || part === "undefined") continue; + return fieldTypeToLlvm(part); + } + } + if (fieldType === "any" || fieldType === "unknown" || fieldType === "object") return "i8*"; + if (fieldType === "null" || fieldType === "undefined" || fieldType === "never") return "i8*"; + if (fieldType === "void") return "i8*"; + if (fieldType.startsWith("{")) return "i8*"; + if (fieldType.indexOf("=>") !== -1 || fieldType.startsWith("(")) return "i8*"; + if (fieldType === "i8*" || fieldType === "double" || fieldType === "i1") return fieldType; + if (fieldType.startsWith("%")) return fieldType; + const ch = fieldType.charAt(0); + if (ch === ch.toUpperCase() && ch !== ch.toLowerCase()) return "i8*"; + throw new Error(`fieldTypeToLlvm: unrecognized type '${fieldType}'`); +} + export function tsTypeToLlvm(tsType: string): string { return canonicalTypeToLlvm(tsType, "default", false, false, ""); } diff --git a/src/codegen/statements/control-flow.ts b/src/codegen/statements/control-flow.ts index 5d69d819..a503b9ee 100644 --- a/src/codegen/statements/control-flow.ts +++ b/src/codegen/statements/control-flow.ts @@ -38,13 +38,7 @@ import { } from "../infrastructure/ir-builders.js"; import { SymbolKind_Number, SymbolKind_String } from "../infrastructure/symbol-table.js"; import type { FieldInfo } from "../infrastructure/type-resolver/types.js"; -import { - stripOptional, - classifyArray, - ArrayKind_None, - arrayKindToLlvm, - fieldTypeToLlvmPrimitive, -} from "../infrastructure/type-system.js"; +import { stripOptional, fieldTypeToLlvm } from "../infrastructure/type-system.js"; import { setWantsI1 } from "../expressions/condition-generator.js"; import { tryOptimizeWhileLoopMap } from "./loop-idiom.js"; @@ -834,7 +828,7 @@ export class ControlFlowGenerator { for (let i = 0; i < commonFields.length; i++) { const f = commonFields[i] as CommonField; keys.push(stripOptional(f.name)); - types.push(this.fieldTypeToLlvm(f.type)); + types.push(this.fieldTypeToLlvmLocal(f.type)); tsTypes.push(f.type); } @@ -864,25 +858,9 @@ export class ControlFlowGenerator { return type; } - private fieldTypeToLlvm(fieldType: string): string { - const prim = fieldTypeToLlvmPrimitive(fieldType); - if (prim) return prim; - const ak = classifyArray(fieldType); - if (ak !== ArrayKind_None) return arrayKindToLlvm(ak); - if (fieldType.startsWith("Map<")) - return fieldType.startsWith("Map") return "%StringSet*"; - if (fieldType.startsWith("Set<")) return "%Set*"; + private fieldTypeToLlvmLocal(fieldType: string): string { if (this.isEnumType(fieldType)) return "double"; - if (fieldType.indexOf(" | ") !== -1) { - const parts = fieldType.split(" | "); - for (let i = 0; i < parts.length; i++) { - const part = parts[i].trim(); - if (part === "null" || part === "undefined") continue; - return this.fieldTypeToLlvm(part); - } - } - return "i8*"; + return fieldTypeToLlvm(fieldType); } private isEnumType(typeName: string): boolean { @@ -982,7 +960,7 @@ export class ControlFlowGenerator { for (let i = 0; i < ifaceAllFields.length; i++) { const f = ifaceAllFields[i] as { name: string; type: string }; keys.push(stripOptional(f.name)); - types.push(this.fieldTypeToLlvm(f.type)); + types.push(this.fieldTypeToLlvmLocal(f.type)); tsTypes.push(f.type); } diff --git a/src/codegen/types/objects/class.ts b/src/codegen/types/objects/class.ts index b7487a18..37bbdf6c 100644 --- a/src/codegen/types/objects/class.ts +++ b/src/codegen/types/objects/class.ts @@ -30,6 +30,7 @@ import { arrayKindToLlvm, ArrayKind_None, fieldTypeToLlvmPrimitive, + fieldTypeToLlvm, } from "../../infrastructure/type-system.js"; import type { FieldInfo } from "../../infrastructure/type-resolver/types.js"; import { emitZext, emitSitofp, emitPtrtoint } from "../../infrastructure/ir-builders.js"; @@ -1586,7 +1587,7 @@ export class ClassGenerator { for (let fi = 0; fi < allFields.length; fi++) { const f = allFields[fi] as { name: string; type: string }; keys.push(stripOptional(f.name)); - types.push(this.fieldTypeToLlvm(f.type)); + types.push(this.fieldTypeToLlvmLocal(f.type)); tsTypes.push(f.type); } const isInterfaceStruct = this.ctx.interfaceStructGen?.hasInterface(tsType); @@ -1664,7 +1665,7 @@ export class ClassGenerator { for (let fi = 0; fi < inlineFields.length; fi++) { const f = inlineFields[fi] as { name: string; type: string }; keys.push(stripOptional(f.name)); - types.push(this.fieldTypeToLlvm(f.type)); + types.push(this.fieldTypeToLlvmLocal(f.type)); tsTypes.push(f.type); } this.ctx.defineVariableWithMetadata( @@ -1725,25 +1726,9 @@ export class ClassGenerator { this.ctx.defineVariable(paramName, allocaReg, llvmType, SymbolKind_Object, "local"); } - private fieldTypeToLlvm(fieldType: string): string { - const prim = fieldTypeToLlvmPrimitive(fieldType); - if (prim) return prim; - const ak = classifyArray(fieldType); - if (ak !== ArrayKind_None) return arrayKindToLlvm(ak); - if (fieldType.startsWith("Map<")) - return fieldType.startsWith("Map") return "%StringSet*"; - if (fieldType.startsWith("Set<")) return "%Set*"; + private fieldTypeToLlvmLocal(fieldType: string): string { if (this.isEnumType(fieldType)) return "double"; - if (fieldType.indexOf(" | ") !== -1) { - const parts = fieldType.split(" | "); - for (let i = 0; i < parts.length; i++) { - const part = parts[i].trim(); - if (part === "null" || part === "undefined") continue; - return this.fieldTypeToLlvm(part); - } - } - return "i8*"; + return fieldTypeToLlvm(fieldType); } private parseInlineObjectFields(typeStr: string): { name: string; type: string }[] { @@ -1837,7 +1822,7 @@ export class ClassGenerator { for (let fi = 0; fi < commonFields.length; fi++) { const f = commonFields[fi] as CommonField; keys.push(stripOptional(f.name)); - types.push(this.fieldTypeToLlvm(f.type)); + types.push(this.fieldTypeToLlvmLocal(f.type)); } return {