From 0f021a77e420541c3995582e09c00bed512ebbe7 Mon Sep 17 00:00:00 2001 From: cs01 Date: Fri, 17 Apr 2026 23:27:27 -0700 Subject: [PATCH] =?UTF-8?q?refactor(type-inference):=20p3b=20=E2=80=94=20m?= =?UTF-8?q?ember.ts.getObjectArrayElementInfo=20delegates=20to=20canonical?= =?UTF-8?q?,=20revert=20#521=20emitError=20workaround?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit canonical path (rich.arrayDepth>0 + rich.fields) now fires for all indexed-object-array element-field accesses; legacy branches remain as fallback for shapes canonical doesn't yet enrich. with canonical in place, #521's emitError intermediate-variable workaround is no longer necessary — reverted to the original chained method_call+index_access form; native compiler emits the expected diagnostic (no segv). zero fuzz regression; stage 2 self-hosting + fixture suite green. --- src/codegen/expressions/access/member.ts | 12 ++++++++++++ src/codegen/llvm-generator.ts | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/codegen/expressions/access/member.ts b/src/codegen/expressions/access/member.ts index 04f7728d7..3de1ac0f2 100644 --- a/src/codegen/expressions/access/member.ts +++ b/src/codegen/expressions/access/member.ts @@ -33,6 +33,7 @@ import { parseMapTypeString, canonicalTypeToLlvm, } from "../../infrastructure/type-system.js"; +import type { ResolvedType } from "../../infrastructure/type-system.js"; import type { IStringGenerator, IMapGenerator, @@ -203,6 +204,7 @@ export interface MemberAccessGeneratorContext { classGenIsStaticField(className: string, fieldName: string): boolean; classGenGetStaticFieldType(className: string, fieldName: string): string; mangleUserName(name: string): string; + resolveExpressionTypeRich(expr: Expression): ResolvedType | null; } export type MemberAccessHandlerFn = ( @@ -2221,6 +2223,16 @@ export class MemberAccessGenerator { private getObjectArrayElementInfo( arrayExpr: Expression, ): { keys: string[]; types: string[]; tsTypes: string[] } | null { + // Canonical path (P3b): delegate to TypeInference.resolveExpressionTypeRich. + // Fires when the object resolves to an array of an interface/class whose + // fields we know — covers method-chain and call returns that the legacy + // branches below partially miss. Legacy branches remain for shapes not yet + // covered by the canonical resolver. + const rich = this.ctx.resolveExpressionTypeRich(arrayExpr); + if (rich && rich.arrayDepth > 0 && rich.fields) { + return { keys: rich.fields.keys, types: rich.fields.types, tsTypes: rich.fields.tsTypes }; + } + if (arrayExpr.type === "member_access") { const memberAccess = arrayExpr as MemberAccessNode; const memberAccessObjBase = memberAccess.object as ExprBase; diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 19fa15435..b21c96d0c 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -332,9 +332,9 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { public emitError(message: string, loc?: SourceLocation, suggestion?: string): never { this.diagnostics.error(message, loc, suggestion); - const errs = this.diagnostics.getErrors(); - const last = errs[errs.length - 1]; - const output = this.diagnostics.formatDiagnostic(last); + const output = this.diagnostics.formatDiagnostic( + this.diagnostics.getErrors()[this.diagnostics.getErrors().length - 1], + ); process.stderr.write(output); process.exit(1); }