From 777bfb43f2e126e5d5fa0f8046eca3944d87548d Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 01:40:17 -0500 Subject: [PATCH] Revert "Name lowered helpers and closures independently of lowering order" This reverts #1750 (05e2f404d), which made main CI fail. --- package.json | 2 +- packages/compiler/src/contracts/check.ts | 3 +- .../lowering/array-indexed-mutation.ts | 3 +- .../src/frontend/lowering/array-values.ts | 5 +- .../frontend/lowering/builtins/arguments.ts | 3 +- .../lowering/builtins/child-process-async.ts | 3 +- .../lowering/builtins/child-process-sync.ts | 3 +- .../lowering/builtins/disposable-stack.ts | 3 +- .../frontend/lowering/builtins/filesystem.ts | 3 +- .../src/frontend/lowering/builtins/json.ts | 3 +- .../lowering/builtins/operating-system.ts | 7 +- .../frontend/lowering/builtins/performance.ts | 5 +- .../src/frontend/lowering/builtins/process.ts | 5 +- .../frontend/lowering/builtins/promises.ts | 5 +- .../lowering/builtins/promisify-callback.ts | 3 +- .../frontend/lowering/builtins/text-codecs.ts | 3 +- .../src/frontend/lowering/builtins/timers.ts | 2 +- .../src/frontend/lowering/builtins/url.ts | 7 +- .../src/frontend/lowering/builtins/v8.ts | 3 +- .../src/frontend/lowering/call-arguments.ts | 3 +- .../src/frontend/lowering/call-signatures.ts | 7 +- .../src/frontend/lowering/class-assertions.ts | 5 +- .../src/frontend/lowering/class-unions.ts | 3 +- .../lowering/coercions/function-adapters.ts | 11 +- .../frontend/lowering/coercions/structural.ts | 15 ++- .../src/frontend/lowering/coercions/unions.ts | 15 ++- .../frontend/lowering/collection-ingestion.ts | 3 +- .../lowering/containers/array-callbacks.ts | 25 ++-- .../lowering/containers/array-concat.ts | 3 +- .../lowering/containers/array-construction.ts | 7 +- .../lowering/containers/array-methods.ts | 11 +- .../lowering/containers/array-pipelines.ts | 3 +- .../src/frontend/lowering/containers/bytes.ts | 5 +- .../lowering/containers/callback-arguments.ts | 3 +- .../containers/collection-grouping.ts | 5 +- .../lowering/containers/collection-methods.ts | 15 ++- .../lowering/containers/indexed-objects.ts | 15 ++- .../lowering/containers/iterator-helpers.ts | 7 +- .../lowering/containers/string-and-regexp.ts | 11 +- .../lowering/containers/string-replacement.ts | 3 +- .../frontend/lowering/expressions/binary.ts | 3 +- .../lowering/expressions/object-literals.ts | 7 +- .../lowering/expressions/optional-chains.ts | 10 +- .../lowering/expressions/property-access.ts | 3 +- .../lowering/expressions/relational.ts | 5 +- .../frontend/lowering/generic-functions.ts | 17 +-- .../src/frontend/lowering/intern-tables.ts | 7 +- .../frontend/lowering/iterator-adapters.ts | 17 ++- .../frontend/lowering/js-dynamic-objects.ts | 5 +- .../src/frontend/lowering/json-require.ts | 3 +- .../src/frontend/lowering/lifetime-regions.ts | 3 +- .../src/frontend/lowering/lower-assert.ts | 11 +- .../src/frontend/lowering/lower-calls.ts | 49 ++++---- .../src/frontend/lowering/lower-classes.ts | 9 +- .../src/frontend/lowering/lower-dgram.ts | 5 +- .../frontend/lowering/lower-event-emitter.ts | 13 +- .../src/frontend/lowering/lower-exprs.ts | 9 +- .../src/frontend/lowering/lower-functions.ts | 2 +- .../src/frontend/lowering/lower-inspect.ts | 7 +- .../src/frontend/lowering/lower-mixins.ts | 3 +- .../src/frontend/lowering/lower-mock.ts | 3 +- .../frontend/lowering/lower-modules.test.ts | 4 +- .../src/frontend/lowering/lower-modules.ts | 15 +-- .../src/frontend/lowering/lower-namespaces.ts | 11 +- .../src/frontend/lowering/lower-server.ts | 13 +- .../src/frontend/lowering/lower-stdlib.ts | 2 +- .../src/frontend/lowering/lower-stream.ts | 15 ++- .../src/frontend/lowering/lower-timers.ts | 7 +- .../src/frontend/lowering/lowerer.test.ts | 30 ++--- .../compiler/src/frontend/lowering/lowerer.ts | 101 +++------------- .../src/frontend/lowering/native-ffi.ts | 2 +- .../lowering/object-enumeration-receiver.ts | 3 +- .../src/frontend/lowering/pairs-snapshot.ts | 3 +- .../lowering/promise-executor-adapter.ts | 3 +- .../lowering/require-initialization.ts | 3 +- .../src/frontend/lowering/stable-names.ts | 48 -------- .../src/frontend/lowering/strict-equality.ts | 3 +- .../frontend/lowering/structural-positions.ts | 107 ----------------- packages/compiler/src/frontend/ts7/ast.ts | 90 +------------- .../compiler/src/frontend/type-mapper.test.ts | 2 +- packages/compiler/src/frontend/type-mapper.ts | 92 ++------------ .../test/array-pipeline-fusion.test.ts | 2 +- .../test/format-float-arguments.test.ts | 2 +- .../test/in-runtime-key-emission.test.ts | 2 +- packages/compiler/test/stable-names.test.ts | 112 ------------------ .../compiler/test/type-mapper-unions.test.ts | 3 +- 86 files changed, 258 insertions(+), 854 deletions(-) delete mode 100644 packages/compiler/src/frontend/lowering/stable-names.ts delete mode 100644 packages/compiler/src/frontend/lowering/structural-positions.ts delete mode 100644 packages/compiler/test/stable-names.test.ts diff --git a/package.json b/package.json index d1a8e34ae..5cc30d9f8 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "test:test262": "tsx tests/test262/run.ts", "test:test262:fetch": "node tests/test262/fetch.mjs", "test:cache-identity": "node tests/harness/cache-identity.mjs", - "test:lowering-order": "node scripts/lowering-order.mjs --fail-on names", + "test:lowering-order": "node scripts/lowering-order.mjs --fail-on content", "test:sandbox": "node scripts/sandbox-test.mjs", "test:sandbox:image": "node scripts/sandbox-image.mjs", "test:watch": "vitest", diff --git a/packages/compiler/src/contracts/check.ts b/packages/compiler/src/contracts/check.ts index c80468961..5934624bf 100644 --- a/packages/compiler/src/contracts/check.ts +++ b/packages/compiler/src/contracts/check.ts @@ -174,8 +174,7 @@ class ContractChecker { return `${owner}.${method[2]}`; } if (fn?.sourceName !== undefined && fn.sourceName !== "") return fn.sourceName; - if (fn !== undefined && /^%fn\.[0-9a-f]{12}$/.test(fnName)) - return `the function at ${this.where(fn.loc)}`; + if (fn !== undefined && /^%fn\d+$/.test(fnName)) return `the function at ${this.where(fn.loc)}`; return fnName.replace(/^%/, ""); } diff --git a/packages/compiler/src/frontend/lowering/array-indexed-mutation.ts b/packages/compiler/src/frontend/lowering/array-indexed-mutation.ts index 0ded460da..6d539212e 100644 --- a/packages/compiler/src/frontend/lowering/array-indexed-mutation.ts +++ b/packages/compiler/src/frontend/lowering/array-indexed-mutation.ts @@ -9,7 +9,6 @@ import { type SrcLoc, typeEquals, } from "../../ir/ir.js"; -import { keyedHelperName } from "./stable-names.js"; import { numLit, varRef } from "../../ir/build.js"; import { typeKey } from "../type-mapper.js"; import type { Lowerer } from "./lowerer.js"; @@ -126,7 +125,7 @@ export function lowerArrayFill( writeNull; let name = lowerer.arrHofHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%arr.fill", key); + name = "%arr.fill." + lowerer.arrHofHelpers.size; lowerer.arrHofHelpers.set(key, name); const a = varRef("a.0", arrType, loc); const n = varRef("n.0", F64, loc); diff --git a/packages/compiler/src/frontend/lowering/array-values.ts b/packages/compiler/src/frontend/lowering/array-values.ts index 314cdfd24..0ca8503df 100644 --- a/packages/compiler/src/frontend/lowering/array-values.ts +++ b/packages/compiler/src/frontend/lowering/array-values.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { InternalCompilerError } from "../../errors.js"; import { dynUndefinedExpr, helperLoc, varRef } from "../../ir/build.js"; import { @@ -253,7 +252,7 @@ export function lowerSafeIndexRead( let name = lowerer.arrHofHelpers.get(key); if (!name) { const at = helperLoc(loc); - name = keyedHelperName(lowerer, "%arr.idxOr", key); + name = `%arr.idxOr.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const arrT = arr.type; lowerer.liftedFns.push({ @@ -299,7 +298,7 @@ export function lowerSafeBytesRead( let name = lowerer.arrHofHelpers.get(key); if (!name) { const at = helperLoc(loc); - name = keyedHelperName(lowerer, "%bytes.idxOr", key); + name = `%bytes.idxOr.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const b = varRef("b.0", bytesT, at); const i = varRef("i.0", F64, at); diff --git a/packages/compiler/src/frontend/lowering/builtins/arguments.ts b/packages/compiler/src/frontend/lowering/builtins/arguments.ts index d2fc430dd..7f862f603 100644 --- a/packages/compiler/src/frontend/lowering/builtins/arguments.ts +++ b/packages/compiler/src/frontend/lowering/builtins/arguments.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { BYTES_U8, BOOL, @@ -73,7 +72,7 @@ export function lowerOptionalNumberPredicate( const key = `number.optionalPredicate:${fn}:${typeKey(widened)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%number.optionalPredicate", key); + helper = `%number.optionalPredicate.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const input = varRef("value.0", widened, loc); lowerer.liftedFns.push({ diff --git a/packages/compiler/src/frontend/lowering/builtins/child-process-async.ts b/packages/compiler/src/frontend/lowering/builtins/child-process-async.ts index d0991dce5..5590fbe9f 100644 --- a/packages/compiler/src/frontend/lowering/builtins/child-process-async.ts +++ b/packages/compiler/src/frontend/lowering/builtins/child-process-async.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { recordToEnvPairs } from "./environment.js"; import { lowerChildArgsArg } from "./child-process.js"; import { boolLit, numLit, varRef } from "../../../ir/build.js"; @@ -219,7 +218,7 @@ function execFileAsyncHelper( const key = shell ? "execAsync" : "execFileAsync"; const existing = lowerer.valueHelpers.get(key); if (existing) return { name: existing, shapeId, envShapeId }; - const name = keyedHelperName(lowerer, `%${key}`, key); + const name = `%${key}.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const recT: IrType = { kind: "record", shapeId }; const envRecT: IrType = { kind: "record", shapeId: envShapeId }; diff --git a/packages/compiler/src/frontend/lowering/builtins/child-process-sync.ts b/packages/compiler/src/frontend/lowering/builtins/child-process-sync.ts index b9858e768..24adcc1ba 100644 --- a/packages/compiler/src/frontend/lowering/builtins/child-process-sync.ts +++ b/packages/compiler/src/frontend/lowering/builtins/child-process-sync.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { recordToEnvPairs } from "./environment.js"; import { lowerChildArgsArg } from "./child-process.js"; import { boolLit, numLit, strLit, varRef } from "../../../ir/build.js"; @@ -542,7 +541,7 @@ function execStdioModeHelper( const key = `cp.stdiomode:${shapeId}:${fd}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%cp.stdioMode.${fd}`, key); + const name = `%cp.stdioMode.${fd}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const optsT: IrType = { kind: "record", shapeId }; diff --git a/packages/compiler/src/frontend/lowering/builtins/disposable-stack.ts b/packages/compiler/src/frontend/lowering/builtins/disposable-stack.ts index 375c3f1e7..1b9a9c03a 100644 --- a/packages/compiler/src/frontend/lowering/builtins/disposable-stack.ts +++ b/packages/compiler/src/frontend/lowering/builtins/disposable-stack.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { locOf } from "../../program.js"; @@ -85,7 +84,7 @@ export function lowerDisposableStackUseCall( const key = `disposableStack.use:${className}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%disposableStack.use", key); + helper = `%disposableStack.use.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const context = newFnCtx(false, null, null, VOID); lowerer.fnStack.push(context); diff --git a/packages/compiler/src/frontend/lowering/builtins/filesystem.ts b/packages/compiler/src/frontend/lowering/builtins/filesystem.ts index 6b988c491..0e1c062c5 100644 --- a/packages/compiler/src/frontend/lowering/builtins/filesystem.ts +++ b/packages/compiler/src/frontend/lowering/builtins/filesystem.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { dynUndefinedExpr, boolLit, numLit, varRef } from "../../../ir/build.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer, ladderFenceExpr } from "../lowerer.js"; @@ -443,7 +442,7 @@ export function lowerStringOrBytesWrite( const key = `fs.${append ? "append" : "write"}:${dataType.unionId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%fs.writeData", key); + helper = `%fs.writeData.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const body: IrStmt[] = []; for (let tag = 0; tag < arms.length; tag++) { diff --git a/packages/compiler/src/frontend/lowering/builtins/json.ts b/packages/compiler/src/frontend/lowering/builtins/json.ts index 64f829865..7eb8aa9b2 100644 --- a/packages/compiler/src/frontend/lowering/builtins/json.ts +++ b/packages/compiler/src/frontend/lowering/builtins/json.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { isDateJsonSource } from "./dates.js"; import { dynUndefinedExpr, varRef } from "../../../ir/build.js"; import { InternalCompilerError } from "../../../errors.js"; @@ -254,7 +253,7 @@ function lowerOptionalStringifyRoot( const key = `json.optionalString:${value.type.unionId}:${JSON.stringify(indent)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%json.optionalString", key); + helper = `%json.optionalString.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const input = varRef("value.0", value.type, loc); const serialized: IrExpr = { diff --git a/packages/compiler/src/frontend/lowering/builtins/operating-system.ts b/packages/compiler/src/frontend/lowering/builtins/operating-system.ts index ee189a1f3..c10465039 100644 --- a/packages/compiler/src/frontend/lowering/builtins/operating-system.ts +++ b/packages/compiler/src/frontend/lowering/builtins/operating-system.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { numLit, strLit, varRef } from "../../../ir/build.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; @@ -220,7 +219,7 @@ export function lowerOsCpusCall(lowerer: Lowerer, call: ts.CallExpression, loc: const key = `os.cpus:${typeKey(result)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%os.cpus", key); + helper = `%os.cpus.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const index = varRef("i.0", F64, loc); const field = (k: number): IrExpr => ({ @@ -347,7 +346,7 @@ export function lowerPathParseCall( const key = `${fn}:${typeKey(result)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%path.parse", key); + helper = `%path.parse.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const parts = varRef("parts.0", arrayOf(STRING), loc); lowerer.liftedFns.push({ @@ -449,7 +448,7 @@ export function lowerPathFormatCall( const key = `${fn}:${typeKey(recordT)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%path.format", key); + helper = `%path.format.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const object = varRef("object.0", recordT, loc); const read = (name: string): IrExpr => { diff --git a/packages/compiler/src/frontend/lowering/builtins/performance.ts b/packages/compiler/src/frontend/lowering/builtins/performance.ts index bae525c17..72304e6a9 100644 --- a/packages/compiler/src/frontend/lowering/builtins/performance.ts +++ b/packages/compiler/src/frontend/lowering/builtins/performance.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { locOf } from "../../program.js"; @@ -331,7 +330,7 @@ function lowerPerfTimelineCall( const key = `perf.${many ? "entries" : timeline.fn}:${typeKey(result)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%perf.${many ? "entries" : member}`, key); + helper = `%perf.${many ? "entries" : member}.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const argsRef = varRef("a.0", DYN, loc); const whichRef = varRef("w.0", F64, loc); @@ -462,7 +461,7 @@ export function perfEntryTag( const key = `perf.tag:${entryT.shapeId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%perf.tag", key); + helper = `%perf.tag.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const e = varRef("e.0", entryT, loc); lowerer.liftedFns.push({ diff --git a/packages/compiler/src/frontend/lowering/builtins/process.ts b/packages/compiler/src/frontend/lowering/builtins/process.ts index 842f42b57..25653f541 100644 --- a/packages/compiler/src/frontend/lowering/builtins/process.ts +++ b/packages/compiler/src/frontend/lowering/builtins/process.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { stdinKeypressListener } from "./readline.js"; import { envSnapshotHelper, lowerProcessLoadEnvFile } from "./environment.js"; import { dynUndefinedExpr, boolLit, numLit, strLit, varRef } from "../../../ir/build.js"; @@ -1562,7 +1561,7 @@ export function lowerProcessMethodCall( const key = `${prefix}usage.diff:${prevT.shapeId}:${t.shapeId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%${prefix}usage.diff`, key); + helper = `%${prefix}usage.diff.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const pRef: IrExpr = { kind: "varRef", localId: "p.0", type: prevT, loc }; const fieldOf = (name: string): IrExpr => ({ @@ -1637,7 +1636,7 @@ export function lowerProcessMethodCall( const key = `process.memoryUsage:${t.shapeId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%process.memoryUsage", key); + helper = `%process.memoryUsage.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); lowerer.liftedFns.push({ name: helper, diff --git a/packages/compiler/src/frontend/lowering/builtins/promises.ts b/packages/compiler/src/frontend/lowering/builtins/promises.ts index 75e527aa5..668ef01f8 100644 --- a/packages/compiler/src/frontend/lowering/builtins/promises.ts +++ b/packages/compiler/src/frontend/lowering/builtins/promises.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { checkedPromiseAll, thenReader } from "../checked-promise-all.js"; import { InternalCompilerError } from "../../../errors.js"; import * as ts from "../../ts7/adapter.js"; @@ -56,7 +55,7 @@ function lowerTuplePromiseAll( const key = `${elems.map((e) => typeKey(e.type)).join(",")}->${typeKey(resultT.inner)}`; let name = lowerer.arrHofHelpers.get(`promise.allTuple:${key}`); if (name === undefined) { - name = keyedHelperName(lowerer, "%promise.allTuple", `promise.allTuple:${key}`); + name = `%promise.allTuple.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(`promise.allTuple:${key}`, name); const ctx = newFnCtx(false, null, null, resultT.inner); ctx.isAsync = true; @@ -558,7 +557,7 @@ export function lowerPromiseStaticCall( const key = `promise.try:${typeKey(f.type)}:${args.map((a) => typeKey(a.type)).join(",")}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%promise.try", key); + helper = `%promise.try.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const fRef: IrExpr = { kind: "varRef", localId: "f.0", type: f.type, loc }; const argLocals = args.map((a, i) => ({ id: `a${i}.0`, name: `a${i}`, type: a.type })); diff --git a/packages/compiler/src/frontend/lowering/builtins/promisify-callback.ts b/packages/compiler/src/frontend/lowering/builtins/promisify-callback.ts index b4dbbf513..822a4fecc 100644 --- a/packages/compiler/src/frontend/lowering/builtins/promisify-callback.ts +++ b/packages/compiler/src/frontend/lowering/builtins/promisify-callback.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { varRef } from "../../../ir/build.js"; @@ -171,7 +170,7 @@ function promisifyMaker(lowerer: Lowerer, shape: CallbackShape, loc: SrcLoc): st const key = `promisify:${typeKey(shape.fnT)}=>${typeKey(shape.resultT)}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const base = keyedHelperName(lowerer, "%promisify", key); + const base = `%promisify.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, base); const { fnT, resultT, args, callbackT, callbackParamT, inner, error } = shape; const promiseT = resultT.ret; diff --git a/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts b/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts index 8d47c8e3a..7229d5b84 100644 --- a/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts +++ b/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { isBuiltinClassInstance } from "./receiver-types.js"; import { strLit, varRef, dynUndefinedExpr } from "../../../ir/build.js"; import { staticTextDecoderEncoding } from "../text-decoder-encoding.js"; @@ -130,7 +129,7 @@ function stringDecoderHelper( const key = `strdec.${op}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%strdec.${op}`, key); + const name = `%strdec.${op}.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const recT: IrType = { kind: "record", shapeId }; diff --git a/packages/compiler/src/frontend/lowering/builtins/timers.ts b/packages/compiler/src/frontend/lowering/builtins/timers.ts index d7cbd63b5..2d531663f 100644 --- a/packages/compiler/src/frontend/lowering/builtins/timers.ts +++ b/packages/compiler/src/frontend/lowering/builtins/timers.ts @@ -85,7 +85,7 @@ export function lowerTimersPromisesSetInterval( const genT = timersPromisesIntervalType(lowerer, expr); if (genT === null) lowerer.badType(expr, lowerer.typeOf(expr)); const yielded = lowerer.coerceInto(valueNode, value, genT.yieldT); - const fnName = lowerer.closureName(loc, "_tpInterval"); + const fnName = `%fn${lowerer.lambdaCounter++}_tpInterval`; const msParam: IrLocal = { id: "%tp.ms", name: "delay", type: F64, mutable: false }; const valueParam: IrLocal = { id: "%tp.value", name: "value", type: genT.yieldT, mutable: false }; const promiseVoid: IrType = { kind: "promise", inner: VOID }; diff --git a/packages/compiler/src/frontend/lowering/builtins/url.ts b/packages/compiler/src/frontend/lowering/builtins/url.ts index 2a77fa85c..dca8a7cc0 100644 --- a/packages/compiler/src/frontend/lowering/builtins/url.ts +++ b/packages/compiler/src/frontend/lowering/builtins/url.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { nodeThrowExpr, countedFor, strLit, varRef, dynUndefinedExpr } from "../../../ir/build.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer, own } from "../lowerer.js"; @@ -293,7 +292,7 @@ function searchParamsFromTuples( const key = `sp.fromTuples:${row.shapeId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%sp.fromTuples", key); + helper = `%sp.fromTuples.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const pairsT = init.type; const sp = (): IrExpr => varRef("sp.0", SEARCH_PARAMS_T, loc); @@ -373,7 +372,7 @@ function lowerOptionalStringSearchParams( const key = `sp.optionalString:${init.type.unionId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%sp.optionalString", key); + helper = `%sp.optionalString.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const value = varRef("init.0", init.type, loc); lowerer.liftedFns.push({ @@ -679,7 +678,7 @@ function lowerSpForEachCall( const key = `${arity}:${typeKey(fnRet)}`; let helper = lowerer.spHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%sp.forEach", key); + helper = `%sp.forEach.${lowerer.spHofHelpers.size}`; lowerer.spHofHelpers.set(key, helper); lowerer.liftedFns.push(buildSpForEachFn(helper, arity, fnRet, loc)); } diff --git a/packages/compiler/src/frontend/lowering/builtins/v8.ts b/packages/compiler/src/frontend/lowering/builtins/v8.ts index 989a61a3f..3582ce8ae 100644 --- a/packages/compiler/src/frontend/lowering/builtins/v8.ts +++ b/packages/compiler/src/frontend/lowering/builtins/v8.ts @@ -5,7 +5,6 @@ * spirit of process.memoryUsage(): approximate values, not V8 heap * figures (a compiled binary embeds no V8 engine). Every other member * fences at its use with the by-design reason (builtinFenceHintOf). */ -import { keyedHelperName } from "../stable-names.js"; import { numLit } from "../../../ir/build.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; @@ -56,7 +55,7 @@ export function lowerV8HeapStatisticsCall( const key = `v8.getHeapStatistics:${t.shapeId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%v8.getHeapStatistics", key); + helper = `%v8.getHeapStatistics.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const sample = (index: number): IrExpr => ({ kind: "libCall", diff --git a/packages/compiler/src/frontend/lowering/call-arguments.ts b/packages/compiler/src/frontend/lowering/call-arguments.ts index 060ffe9d2..49f7c8ec0 100644 --- a/packages/compiler/src/frontend/lowering/call-arguments.ts +++ b/packages/compiler/src/frontend/lowering/call-arguments.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { forwardedTupleType, pureForwardedValues, stripTypeWrappers } from "./typed-arguments.js"; import { dynUndefinedExpr } from "../../ir/build.js"; import { InternalCompilerError } from "../../errors.js"; @@ -754,7 +753,7 @@ function holeReadingLift(lowerer: Lowerer, from: IrType, to: IrType, loc: SrcLoc const key = `arr.holes:${typeKey(elem)}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%arr.holes", key); + const name = `%arr.holes.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push( buildArrayConversion( diff --git a/packages/compiler/src/frontend/lowering/call-signatures.ts b/packages/compiler/src/frontend/lowering/call-signatures.ts index dacb4d324..34343ad27 100644 --- a/packages/compiler/src/frontend/lowering/call-signatures.ts +++ b/packages/compiler/src/frontend/lowering/call-signatures.ts @@ -849,10 +849,7 @@ export function collectSignatureInner(lowerer: Lowerer, decl: ts.FunctionDeclara lowerer.genericFnsBySymbol.set(symbol, { decl, baseName: nameText, - qualifiedName: lowerer.qualify( - ts.getSourceFileOfNode(decl), - nsPathPrefix(lowerer, decl) + nameText, - ), + qualifiedName: lowerer.qualify(ts.getSourceFileOfNode(decl), nsPathPrefix(decl) + nameText), typeParams: [], instances: new Map(), implicitParams: implicit, @@ -900,7 +897,7 @@ export function collectSignatureInner(lowerer: Lowerer, decl: ts.FunctionDeclara // "%default" spelling ('%' cannot appear in a user identifier). name: lowerer.qualify( ts.getSourceFileOfNode(decl), - nsPathPrefix(lowerer, decl) + (decl.name?.text ?? "%default"), + nsPathPrefix(decl) + (decl.name?.text ?? "%default"), ), params, returnType, diff --git a/packages/compiler/src/frontend/lowering/class-assertions.ts b/packages/compiler/src/frontend/lowering/class-assertions.ts index 52654fab8..900c32426 100644 --- a/packages/compiler/src/frontend/lowering/class-assertions.ts +++ b/packages/compiler/src/frontend/lowering/class-assertions.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { nodeThrowExpr, varRef } from "../../ir/build.js"; import { BOOL, @@ -123,7 +122,7 @@ export function checkedClassAssertion( const key = `classassert:${typeKey(source.type)}:${typeKey(target)}`; let name = lowerer.coercions.retags.get(key); if (!name) { - name = keyedHelperName(lowerer, "%class.assert", key); + name = `%class.assert.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); const input = varRef("value.0", source.type, loc); const body: IrStmt[] = []; @@ -229,7 +228,7 @@ export function checkedClassUnionAssertion( const key = `classunionassert:${typeKey(value.type)}:${typeKey(target)}`; let name = lowerer.coercions.retags.get(key); if (!name) { - name = keyedHelperName(lowerer, "%class.assert", key); + name = `%class.assert.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); const input = varRef("value.0", value.type, loc); const locals = [{ id: "value.0", name: "value", type: value.type, mutable: false }]; diff --git a/packages/compiler/src/frontend/lowering/class-unions.ts b/packages/compiler/src/frontend/lowering/class-unions.ts index 0021b2cf8..f52026ba4 100644 --- a/packages/compiler/src/frontend/lowering/class-unions.ts +++ b/packages/compiler/src/frontend/lowering/class-unions.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import * as ts from "../ts7/adapter.js"; import { BOOL, typeKey, type IrExpr, type IrStmt, type IrType } from "../../ir/ir.js"; import { nodeThrowExpr, varRef } from "../../ir/build.js"; @@ -133,7 +132,7 @@ export function narrowClassUnion( const key = `classUnion:${source.className}:${target.unionId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%class.union", key); + helper = `%class.union.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const input = varRef("value.0", source, loc); // Rank by ancestry before sorting: returning zero for unrelated pairs diff --git a/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts b/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts index fe3c14605..ffdac19f0 100644 --- a/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts +++ b/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { dynUndefinedExpr } from "../../../ir/build.js"; import { buildFunctionAdapter } from "./builders.js"; import { InternalCompilerError } from "../../../errors.js"; @@ -34,7 +33,7 @@ export function funcReturnWidthAdapter( const key = `fn:${typeKey(fromT.ret.elem)}:${typeKey(toT.ret.elem)}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%fn.width", key); + const name = `%fn.width.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.freshClosureAdapters.add(name); // The returned closure's body: call the captured original, width-map. @@ -164,7 +163,7 @@ function restPackingAdapter( const key = `fnrestadapt:${typeKey(fromT)}:${typeKey(toT)}`; const existing = lowerer.coercions.retags.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%fn.adapt", key); + const name = `%fn.adapt.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); lowerer.freshClosureAdapters.add(name); const fixed = fromT.params.length - 1; @@ -221,7 +220,7 @@ function funcIntoDynRestAdapter( const key = `fnadapt:${typeKey(fromT)}:${typeKey(toT)}`; const existing = lowerer.coercions.retags.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%fn.adapt", key); + const name = `%fn.adapt.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); lowerer.freshClosureAdapters.add(name); const params: IrParam[] = [{ localId: "rest.0", name: "args", type: DYN }]; @@ -377,7 +376,7 @@ export function funcCoerceAdapter( const key = `fnadapt:${typeKey(fromT)}:${typeKey(toT)}`; const existing = lowerer.coercions.retags.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%fn.adapt", key); + const name = `%fn.adapt.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); lowerer.freshClosureAdapters.add(name); const params: IrParam[] = toT.params.map((t, i) => ({ @@ -605,7 +604,7 @@ export function spawnResFnAdapter( const key = `fnspawn:${typeKey(fromT)}:${typeKey(toT)}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%fnval.spawnres", key); + const name = `%fnval.spawnres.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.freshClosureAdapters.add(name); const params: IrParam[] = toT.params.map((p, i) => ({ diff --git a/packages/compiler/src/frontend/lowering/coercions/structural.ts b/packages/compiler/src/frontend/lowering/coercions/structural.ts index 5b5e283b3..496a29607 100644 --- a/packages/compiler/src/frontend/lowering/coercions/structural.ts +++ b/packages/compiler/src/frontend/lowering/coercions/structural.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { constructedValue } from "../constructor-returns.js"; import { dynUndefinedExpr, varRef } from "../../../ir/build.js"; import type { FieldLift } from "./structural-plans.js"; @@ -254,7 +253,7 @@ export function unionRecordWidthHelper( const key = `unionWidth:${fromId}:${target.shapeId}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%union.record", key); + const name = `%union.record.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const type: IrType = { kind: "union", unionId: fromId }; const value = varRef("value.0", type, loc); @@ -313,7 +312,7 @@ export function recordWidthHelper( const key = `rec:${fromId}:${toId}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%rec.width", key); + const name = `%rec.width.${lowerer.valueHelpers.size}`; // Interned BEFORE the body builds: a recursive nested-width field // (self-referential shapes) resolves to this helper itself. lowerer.valueHelpers.set(key, name); @@ -342,7 +341,7 @@ export function tupleArrayWidthHelper( const key = `tuparr:${fromId}:${typeKey(toT.elem)}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%tup.arr", key); + const name = `%tup.arr.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const fromT: IrType = { kind: "record", shapeId: fromId }; const t: IrExpr = { kind: "varRef", localId: "t.0", type: fromT, loc }; @@ -389,7 +388,7 @@ export function emptyArrayLiftHelper( const key = `emptyarr:${typeKey(fromT.elem)}:${typeKey(toT.elem)}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%arr.empty", key); + const name = `%arr.empty.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const a: IrExpr = { kind: "varRef", localId: "a.0", type: fromT, loc }; lowerer.liftedFns.push({ @@ -453,7 +452,7 @@ export function arrayWidthHelper( const key = `arr:${typeKey(fromElem)}:${typeKey(toElem)}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%arr.width", key); + const name = `%arr.width.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const arrT: IrType = { kind: "array", elem: fromElem }; const outT: IrType = { kind: "array", elem: toElem }; @@ -493,7 +492,7 @@ export function objRecordWidthHelper( const key = `obj:${className}:${toId}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%obj.width", key); + const name = `%obj.width.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const fromT: IrType = { kind: "object", className }; lowerer.liftedFns.push(buildRecordProjection(lowerer, name, fromT, to, plan, loc)); @@ -518,7 +517,7 @@ export function recordClassWidthHelper( const key = `cls:${fromId}:${className}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%cls.width", key); + const name = `%cls.width.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.noteEdge(`%${className}.constructor`); const fromT: IrType = { kind: "record", shapeId: fromId }; diff --git a/packages/compiler/src/frontend/lowering/coercions/unions.ts b/packages/compiler/src/frontend/lowering/coercions/unions.ts index 434e687a5..06c0af9c6 100644 --- a/packages/compiler/src/frontend/lowering/coercions/unions.ts +++ b/packages/compiler/src/frontend/lowering/coercions/unions.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { buildUnionNarrow, unionNarrowFailureMessage } from "../union-narrow.js"; import { isSafeToRepeat } from "../expressions/evaluation-safety.js"; import { nodeThrowExpr } from "../../../ir/build.js"; @@ -148,7 +147,7 @@ export function strandedUnitTrap( const key = `strandunit:${typeKey(expected)}:${expr.type.kind}`; let name = lowerer.coercions.retags.get(key); if (!name) { - name = keyedHelperName(lowerer, "%unit.strand", key); + name = `%unit.strand.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); lowerer.liftedFns.push({ name, @@ -228,7 +227,7 @@ export function strandedCoercionTrap( const key = `strand:${expected.unionId}:${typeKey(src)}`; let name = lowerer.coercions.retags.get(key); if (!name) { - name = keyedHelperName(lowerer, "%union.strand", key); + name = `%union.strand.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); const toT: IrType = { kind: "union", unionId: expected.unionId }; lowerer.liftedFns.push({ @@ -276,7 +275,7 @@ export function recordUnionWrapHelper( const key = `recordWrap:${source.shapeId}:${toId}`; const existing = lowerer.coercions.retags.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%record.wrap", key); + const name = `%record.wrap.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); lowerer.liftedFns.push( buildRecordUnionWrap(name, source, to, plan, loc, (lift, value, dst) => @@ -308,7 +307,7 @@ export function recordUnionRouteHelper( (from, dst) => lowerer.widthLiftPlan(from, dst), ); if (!plan) return null; - const name = keyedHelperName(lowerer, "%record.route", key); + const name = `%record.route.${lowerer.coercions.retags.size}`; lowerer.coercions.retags.set(key, name); lowerer.liftedFns.push( buildRecordUnionWrap(name, source, to, plan, loc, (lift, value, dst) => @@ -353,7 +352,7 @@ export function unionRetagHelper( }); const key = `${fromId}:${toId}:${stranded.join(".")}`; const existing = lowerer.coercions.retags.get(key); - const name = existing ?? keyedHelperName(lowerer, "%union.retag", key); + const name = existing ?? `%union.retag.${lowerer.coercions.retags.size}`; if (!existing) { lowerer.coercions.retags.set(key, name); lowerer.liftedFns.push( @@ -411,7 +410,7 @@ export function narrowedArmHelper( lowerer.coercions.checkedNarrows.add(existing); return existing; } - const name = keyedHelperName(lowerer, "%union.narrow", key); + const name = `%union.narrow.${lowerer.coercions.narrows.size}`; lowerer.coercions.narrows.set(key, name); lowerer.coercions.checkedNarrows.add(name); const fn = buildUnionNarrow(name, from, target, loc, (type) => lowerer.fmt(type)); @@ -588,7 +587,7 @@ export function deferredReadHelper( const key = `deferred:${fromId}:${tag}`; const existing = lowerer.coercions.narrows.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%deferred.read", key); + const name = `%deferred.read.${lowerer.coercions.narrows.size}`; lowerer.coercions.narrows.set(key, name); const dflt: IrExpr = target.kind === "bool" diff --git a/packages/compiler/src/frontend/lowering/collection-ingestion.ts b/packages/compiler/src/frontend/lowering/collection-ingestion.ts index 8fe2a6bbb..5d14d5492 100644 --- a/packages/compiler/src/frontend/lowering/collection-ingestion.ts +++ b/packages/compiler/src/frontend/lowering/collection-ingestion.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import * as ts from "../ts7/adapter.js"; import { InternalCompilerError } from "../../errors.js"; import { typeKey } from "../type-mapper.js"; @@ -198,7 +197,7 @@ export function ingestCollection( const key = `ingest:${input.collection ? typeKey(input.collection) + ":" + input.selection : "cursor:" + typeKey(input.element)}:${typeKey(destination)}:${mapper ? typeKey(mapper.type) : "copy"}`; let name = lowerer.arrHofHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%collection.ingest", key); + name = `%collection.ingest.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const context = newFnCtx(false, null, null, destination); lowerer.fnStack.push(context); diff --git a/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts b/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts index 7ca69d9ba..eb99592bb 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { boolLit, countedFor, numLit, varRef } from "../../../ir/build.js"; import { transformStmtList } from "../../../ir/traverse.js"; import type { ScrDiagnostic } from "../../../diagnostics/diagnostic.js"; @@ -507,7 +506,7 @@ function arrayHofHelper( const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}:${typeKey(outElem)}${site}${fastT ? ":split" : ""}${present ? ":present" : ""}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%arr.${method}`, key); + const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); lowerer.arrHofInfo.set(name, { method, elem, fnRet, arity, outElem, present, split: !!fastT }); const fn = buildArrayHofFn( @@ -620,7 +619,7 @@ function arrayUnionHofHelper( const key = `union:${method}:${receiverT.unionId}:${typeKey(callbackT)}:${typeKey(resultT)}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%arr.union", key); + const name = `%arr.union.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const receiver = varRef("a.0", receiverT, loc); const callback = varRef("f.0", callbackT, loc); @@ -1205,7 +1204,7 @@ function findHelper( const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}${site}${present ? ":present" : ""}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%arr.${method}`, key); + const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const arrT = arrayOf(elem); const valueT = callbackValueType(lowerer, elem, present); @@ -1305,7 +1304,7 @@ function findIndexHelper( const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}${present ? ":present" : ""}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%arr.${method}`, key); + const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); if (!last) lowerer.arrHofInfo.set(name, { @@ -1389,7 +1388,7 @@ function someEveryHelper( const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}${present ? ":present" : ""}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%arr.${method}`, key); + const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); lowerer.arrHofInfo.set(name, { method, @@ -1588,7 +1587,7 @@ function flatMapHelper( const key = `flatMap:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}${present ? ":present" : ""}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%arr.flatMap", key); + const name = `%arr.flatMap.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); lowerer.arrHofInfo.set(name, { method: "flatMapArray", @@ -1830,7 +1829,7 @@ function reduceHelper( const key = `${method}:${typeKey(elem)}:${typeKey(accT)}:${typeKey(fnRet)}:${arity}:${hasInit ? "init" : "seed"}${site}${fastT ? ":split" : ""}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%arr.${method}`, key); + const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); if (method === "reduce") lowerer.arrHofInfo.set(name, { @@ -2122,7 +2121,7 @@ export function lowerArraySortCall( const key = `${method}:${typeKey(elem)}:${arity}${native ? ":native" : ""}${keyed ? `:keyed${order}${reads ? `:field${reads.length}` : ""}` : ""}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%arr.${method}`, key); + helper = `%arr.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const undefinedTag = elem.kind === "union" ? lowerer.armTag(elem.unionId, UNDEFINED_T) : -1; lowerer.liftedFns.push( @@ -2168,7 +2167,7 @@ function sortKeyReader( const cacheKey = `sortKey:${typeKey(elem)}:${sortKeysId(reads.map((read) => ({ order: 1, read })))}`; let reader = lowerer.arrHofHelpers.get(cacheKey); if (!reader) { - reader = keyedHelperName(lowerer, "%arr.sortKey", cacheKey); + reader = `%arr.sortKey.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(cacheKey, reader); lowerer.liftedFns.push(buildSortKeyFn(reader, elem, reads, loc)); } @@ -2309,7 +2308,7 @@ function dynFlatMapHelper(lowerer: Lowerer, elemT: IrType, arity: number, loc: S const key = `dynflatmap:${typeKey(elemT)}:${arity}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%dyn.flatmap", key); + const name = `%dyn.flatmap.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); lowerer.liftedFns.push(buildDynFlatMapFn(name, elemT, arity, loc)); return name; @@ -2482,7 +2481,7 @@ function dynFilterHelper(lowerer: Lowerer, elemT: IrType, arity: number, loc: Sr const key = `dynfilter:${typeKey(elemT)}:${arity}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%dyn.filter", key); + const name = `%dyn.filter.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); lowerer.liftedFns.push(buildDynFilterFn(name, elemT, arity, loc)); return name; @@ -2677,7 +2676,7 @@ export function lowerTuplePredicateCall( const key = `tuple.${method}:${typeKey(receiver.type)}:${typeKey(fnArg.type)}:${typeKey(resultT)}:${arity}${callbackSite(fnArg)}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%tuple.${method}`, key); + helper = `%tuple.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const v = varRef("v.0", elem, loc); const out = varRef("out.0", resultT, loc); diff --git a/packages/compiler/src/frontend/lowering/containers/array-concat.ts b/packages/compiler/src/frontend/lowering/containers/array-concat.ts index b4e285ee9..4f6e4ca43 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-concat.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-concat.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { identityPreservingWidening } from "../coercions/identity.js"; import { countedFor, numLit, varRef } from "../../../ir/build.js"; import { @@ -29,7 +28,7 @@ export function arrayConcatHelper( const key = `concat:${typeKey(elem)}:${shape.map((type) => (type ? `a:${typeKey(type)}` : "e")).join(";")}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%arr.concat", key); + const name = `%arr.concat.${lowerer.arrHofHelpers.size}`; const arrT = arrayOf(elem); const params = [ { localId: "a.0", name: "a", type: arrT }, diff --git a/packages/compiler/src/frontend/lowering/containers/array-construction.ts b/packages/compiler/src/frontend/lowering/containers/array-construction.ts index 1f10640c0..40e4d6436 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-construction.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-construction.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { generatorDrain } from "../iterator-adapters.js"; import { identityPreservingWidening } from "../coercions/identity.js"; import { liftedFreshSpread } from "../coercions/fresh-spread.js"; @@ -257,7 +256,7 @@ function appendWidenedArrayValues( const key = `insertValues:${typeKey(sourceType.elem)}:${typeKey(elem)}`; let name = lowerer.arrHofHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%arr.insertValues", key); + name = `%arr.insertValues.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const outType = arrayOf(elem); const valueType = arrayValueType(lowerer, source.type.elem); @@ -1036,7 +1035,7 @@ export function lowerArrayFromCall( const key = `fromArray:${typeKey(arrT.elem)}:${typeKey(outElem)}:${typeKey(fnRet)}:${arity}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%arr.fromArray", key); + helper = `%arr.fromArray.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); lowerer.liftedFns.push( buildArrayFromArrayFn(lowerer, helper, arrT.elem, outElem, fnRet, arity, loc), @@ -1123,7 +1122,7 @@ export function lowerArrayFromCall( const key = `fromLen:${typeKey(fnRet)}:${arity}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%arr.fromLen", key); + helper = `%arr.fromLen.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); lowerer.liftedFns.push(buildArrayFromLenFn(helper, fnRet, arity, loc)); } diff --git a/packages/compiler/src/frontend/lowering/containers/array-methods.ts b/packages/compiler/src/frontend/lowering/containers/array-methods.ts index 44182fbda..e9a130a2d 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-methods.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-methods.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { liftedFreshSpread } from "../coercions/fresh-spread.js"; import { lowerArrayIteratorValue } from "../iterator-adapters.js"; import { identityPreservingWidening } from "../coercions/identity.js"; @@ -1617,7 +1616,7 @@ function arraySearchHelper( const key = `${method}:${typeKey(elem)}:${typeKey(valueT)}:${typeKey(needleT)}:${directNeedle}:${typeKey(fromT)}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%arr.${method}`, key); + const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const arrT = arrayOf(elem); const resultT = method === "includes" ? BOOL : F64; @@ -1973,7 +1972,7 @@ export function lowerTupleReadMethodCall( let helper = lowerer.arrHofHelpers.get(key); const resultType = method === "includes" ? BOOL : F64; if (!helper) { - helper = keyedHelperName(lowerer, `%tuple.${method}`, key); + helper = `%tuple.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const params = [ { localId: "a.0", name: "a", type: receiver.type }, @@ -2035,7 +2034,7 @@ export function lowerTupleReadMethodCall( const key = `tuple.slice:${typeKey(receiver.type)}:${args.length}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%tuple.slice", key); + helper = `%tuple.slice.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const params = [receiver, ...args].map((arg, i) => ({ localId: i === 0 ? "a.0" : `arg.${i}`, @@ -2126,7 +2125,7 @@ export function lowerTupleReadMethodCall( const key = `tuple.${method}:${typeKey(receiver.type)}:${typeKey(fnArg.type)}:${typeKey(outElem)}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%tuple.${method}`, key); + helper = `%tuple.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const out = varRef("out.0", outType, loc); const result = varRef("r.0", ret, loc); @@ -2254,7 +2253,7 @@ function lowerArrayAtCall( const key = `at:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(index.type)}`; let name = lowerer.arrHofHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%arr.at", key); + name = `%arr.at.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const arrT = arrayOf(elem); diff --git a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts index 180f40435..cf45a7575 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { boolLit, countedFor, numLit, varRef } from "../../../ir/build.js"; import { BOOL, @@ -852,7 +851,7 @@ class PipelineFusion { if (!built) return null; let name = this.helpers.get(built.key); if (!name) { - name = keyedHelperName(this.lowerer, "%arr.fused", built.key); + name = `%arr.fused.${this.helpers.size}`; this.helpers.set(built.key, name); this.added.push({ ...built.fn, name }); } diff --git a/packages/compiler/src/frontend/lowering/containers/bytes.ts b/packages/compiler/src/frontend/lowering/containers/bytes.ts index 4b20d7bf5..bf9821d31 100644 --- a/packages/compiler/src/frontend/lowering/containers/bytes.ts +++ b/packages/compiler/src/frontend/lowering/containers/bytes.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { boolLit, dynUndefinedExpr, numLit, varRef } from "../../../ir/build.js"; import { BUF_NUM_METHODS } from "./buffer-numeric-methods.js"; import * as ts from "../../ts7/adapter.js"; @@ -78,7 +77,7 @@ function lowerBytesSortCall( const cacheKey = `bytes.${method}:${bytesT.elem}:${key}`; let helper = lowerer.arrHofHelpers.get(cacheKey); if (!helper) { - helper = keyedHelperName(lowerer, `%bytes.${method}`, cacheKey); + helper = `%bytes.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(cacheKey, helper); lowerer.liftedFns.push( buildBytesSortFn(helper, bytesT, arity, hasComparator, copyFirst, order, loc), @@ -271,7 +270,7 @@ function bytesCallbackHelper( const key = `bytes.${method}:${bytesT.elem}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}:${hasInit ? "init" : ""}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%bytes.${method}`, key); + const name = `%bytes.${method}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const reduce = method === "reduce" || method === "reduceRight"; const backward = method === "reduceRight" || method === "findLast" || method === "findLastIndex"; diff --git a/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts b/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts index f39c8e86c..18754f088 100644 --- a/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts +++ b/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import * as ts from "../../ts7/adapter.js"; import type { Lowerer } from "../lowerer.js"; import { isJsSourceFile, locOf } from "../../program.js"; @@ -286,7 +285,7 @@ export function truthyFilterCallback( const key = `filterBoolean:${typeKey(valueT)}`; let name = lowerer.arrHofHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%arr.filterBoolean", key); + name = `%arr.filterBoolean.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const value = varRef("v.0", valueT, loc); lowerer.liftedFns.push({ diff --git a/packages/compiler/src/frontend/lowering/containers/collection-grouping.ts b/packages/compiler/src/frontend/lowering/containers/collection-grouping.ts index dae68d518..0bf126830 100644 --- a/packages/compiler/src/frontend/lowering/containers/collection-grouping.ts +++ b/packages/compiler/src/frontend/lowering/containers/collection-grouping.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { countedFor, numLit, varRef } from "../../../ir/build.js"; import * as ts from "../../ts7/adapter.js"; import type { Lowerer } from "../lowerer.js"; @@ -105,7 +104,7 @@ export function lowerGroupByStaticCall( const key = `map.groupBy:${typeKey(items.type)}:${typeKey(f.type)}`; let helper = lowerer.mapHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%map.groupBy", key); + helper = `%map.groupBy.${lowerer.mapHofHelpers.size}`; lowerer.mapHofHelpers.set(key, helper); lowerer.liftedFns.push(buildGroupByFn(lowerer, helper, items.type, f.type, resultT, loc)); } @@ -142,7 +141,7 @@ export function lowerGroupByStaticCall( const key = `object.groupBy:${typeKey(items.type)}:${typeKey(f.type)}`; let helper = lowerer.mapHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%object.groupBy", key); + helper = `%object.groupBy.${lowerer.mapHofHelpers.size}`; lowerer.mapHofHelpers.set(key, helper); lowerer.liftedFns.push(buildGroupByFn(lowerer, helper, items.type, f.type, resultT, loc)); } diff --git a/packages/compiler/src/frontend/lowering/containers/collection-methods.ts b/packages/compiler/src/frontend/lowering/containers/collection-methods.ts index d3169ec5c..370974c85 100644 --- a/packages/compiler/src/frontend/lowering/containers/collection-methods.ts +++ b/packages/compiler/src/frontend/lowering/containers/collection-methods.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { nodeThrowExpr, boolLit, countedFor, numLit, strLit, varRef } from "../../../ir/build.js"; import { InternalCompilerError } from "../../../errors.js"; import * as ts from "../../ts7/adapter.js"; @@ -233,7 +232,7 @@ function lowerMapIterDrainCall( const key = `${method}:${typeKey(mapT.key)}:${typeKey(mapT.value)}`; let helper = lowerer.mapHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%map.${method}`, key); + helper = `%map.${method}.${lowerer.mapHofHelpers.size}`; lowerer.mapHofHelpers.set(key, helper); lowerer.liftedFns.push(buildMapIterDrainFn(helper, mapT, method, elemT, tupleT, loc)); } @@ -349,7 +348,7 @@ export function mapEntriesArray(lowerer: Lowerer, receiver: IrExpr): IrExpr { const key = `entries:${typeKey(mapT.key)}:${typeKey(mapT.value)}`; let helper = lowerer.mapHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%map.entries", key); + helper = `%map.entries.${lowerer.mapHofHelpers.size}`; lowerer.mapHofHelpers.set(key, helper); lowerer.liftedFns.push( buildMapIterDrainFn(helper, mapT, "entries", tupleT, tupleT, receiver.loc), @@ -520,7 +519,7 @@ export function lowerMapForEachCall( const key = `${typeKey(mapT.key)}:${typeKey(mapT.value)}:${arity}:${typeKey(fnRet)}`; let helper = lowerer.mapHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%map.forEach", key); + helper = `%map.forEach.${lowerer.mapHofHelpers.size}`; lowerer.mapHofHelpers.set(key, helper); lowerer.liftedFns.push(buildCollectionForEachFn(helper, mapT, arity, fnRet, loc)); } @@ -694,7 +693,7 @@ export function lowerSetForEachCall( const key = `${typeKey(setT.elem)}:${arity}:${typeKey(fnRet)}`; let helper = lowerer.setHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%set.forEach", key); + helper = `%set.forEach.${lowerer.setHofHelpers.size}`; lowerer.setHofHelpers.set(key, helper); lowerer.liftedFns.push(buildCollectionForEachFn(helper, setT, arity, fnRet, loc)); } @@ -746,7 +745,7 @@ function lowerSetCombineCall( const key = `${name}:${typeKey(setT.elem)}:${typeKey(otherT)}`; let helper = lowerer.setHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%set.${name}`, key); + helper = `%set.${name}.${lowerer.setHofHelpers.size}`; lowerer.setHofHelpers.set(key, helper); lowerer.liftedFns.push(buildSetCombineFn(helper, name, setT, otherT, loc)); } @@ -1358,7 +1357,7 @@ export function mapFromSeedValue( const key = `checked-seed:${typeKey(mapT)}`; let name = lowerer.mapHofHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%map.checkedSeed", key); + name = `%map.checkedSeed.${lowerer.mapHofHelpers.size}`; lowerer.mapHofHelpers.set(key, name); const source = varRef("source.0", DYN, loc); const entries = varRef("entries.0", DYN, loc); @@ -1458,7 +1457,7 @@ export function mapFromSeedValue( const key = `seed:${typeKey(mapT.key)}:${typeKey(mapT.value)}:${elem.shapeId}`; let helper = lowerer.mapHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%map.seed", key); + helper = `%map.seed.${lowerer.mapHofHelpers.size}`; lowerer.mapHofHelpers.set(key, helper); lowerer.liftedFns.push(buildMapSeedFn(mapT, helper, seed.type, elem, kT, vT, loc)); } diff --git a/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts b/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts index b3faf649e..efc173ffc 100644 --- a/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts +++ b/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { nullProtoRecordShape, recordNullProtoTest } from "../null-prototype.js"; import { countedFor, numLit, varRef } from "../../../ir/build.js"; import { objectEnumerationReceiver } from "../object-enumeration-receiver.js"; @@ -185,7 +184,7 @@ export function objectIterOverIndexShape( const key = `obj.${member}:ovf:${argIr.shapeId}:${typeKey(resultT)}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%obj.${member}`, key); + helper = `%obj.${member}.${lowerer.arrHofHelpers.size}`; const outRef = varRef("out.0", resultT, loc); const rRef = varRef("r.0", argIr, loc); @@ -609,7 +608,7 @@ function lowerTypedObjectFromEntriesCall( const key = `obj.fromEntries:${argIr.elem.shapeId}:${resultT.shapeId}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%obj.fromEntries", key); + helper = `%obj.fromEntries.${lowerer.arrHofHelpers.size}`; const tupleT = argIr.elem as IrType & { kind: "record" }; const tRef = varRef("t.0", tupleT, loc); @@ -713,7 +712,7 @@ function lowerFromEntriesStringRows( const key = `obj.fromEntries:strrows:${resultT.shapeId}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%obj.fromEntries", key); + helper = `%obj.fromEntries.${lowerer.arrHofHelpers.size}`; const tRef = varRef("t.0", rowT, loc); const rowLen: IrExpr = { @@ -932,7 +931,7 @@ export function lowerRecordOvfCaptureHelper( const key = `ovf:${fromId}:${toId}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%rec.capture", key); + const name = `%rec.capture.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const fromT: IrType = { kind: "record", shapeId: fromId }; const toT: IrType = { kind: "record", shapeId: toId }; @@ -1205,7 +1204,7 @@ export function lowerObjectAssignIndexShape( const key = `assign:${targetIr.shapeId}:${plan.fromId}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%obj.assign", key); + const name = `%obj.assign.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const toT: IrType = { kind: "record", shapeId: targetIr.shapeId }; const fromT: IrType = { kind: "record", shapeId: plan.fromId }; @@ -1475,7 +1474,7 @@ export function lowerIndexMergeHelper( .join(","); const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%rec.merge", key); + const name = `%rec.merge.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const toT: IrType = { kind: "record", shapeId: toId }; const ksT = arrayOf(STRING); @@ -1806,7 +1805,7 @@ export function lowerEnvToPairsHelper( const key = `env.pairs:${shapeId}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%env.pairs", key); + const name = `%env.pairs.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const recT: IrType = { kind: "record", shapeId }; const arrT = arrayOf(STRING); diff --git a/packages/compiler/src/frontend/lowering/containers/iterator-helpers.ts b/packages/compiler/src/frontend/lowering/containers/iterator-helpers.ts index 48b4caabd..c23e6931c 100644 --- a/packages/compiler/src/frontend/lowering/containers/iterator-helpers.ts +++ b/packages/compiler/src/frontend/lowering/containers/iterator-helpers.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { boolLit, numLit, varRef } from "../../../ir/build.js"; import { InternalCompilerError } from "../../../errors.js"; import * as ts from "../../ts7/adapter.js"; @@ -967,7 +966,7 @@ function lowerFusedChain( const key = `iter:${srcKey}:${stageKeys.join(",")}:${terminal}:${termArgs.map((a) => typeKey(a.type)).join(",")}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%iter.${terminal}`, key); + helper = `%iter.${terminal}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); lowerer.liftedFns.push( buildIterChainFn( @@ -1039,7 +1038,7 @@ function lowerHelperObject( const key = `iterHelper:${stage.kind}:${srcKey}:${typeKey(srcElem)}:${typeKey(arg.type)}:${typeKey(outT)}`; let name = lowerer.arrHofHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, `%iter.${stage.kind}`, key); + name = `%iter.${stage.kind}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); lowerer.liftedFns.push( buildHelperGenFn(lowerer, name, source, srcElem, stage, arg.type, outT, resultType, loc), @@ -1059,7 +1058,7 @@ function internBudgetChecker(lowerer: Lowerer, loc: SrcLoc, srcT: GenType | null const key = srcT === null ? "iter:budget" : `iter:budget:close:${typeKey(srcT)}`; let name = lowerer.arrHofHelpers.get(key); if (name !== undefined) return name; - name = srcT === null ? "%iter.budget" : keyedHelperName(lowerer, "%iter.budget.close", key); + name = srcT === null ? "%iter.budget" : `%iter.budget.close.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const v = (): IrExpr => ({ kind: "varRef", localId: "v.0", type: F64, loc }); diff --git a/packages/compiler/src/frontend/lowering/containers/string-and-regexp.ts b/packages/compiler/src/frontend/lowering/containers/string-and-regexp.ts index fe4ddbc6c..9567ee0f6 100644 --- a/packages/compiler/src/frontend/lowering/containers/string-and-regexp.ts +++ b/packages/compiler/src/frontend/lowering/containers/string-and-regexp.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { matchAllRowsReadByElements } from "./match-row-uses.js"; import { boolLit, @@ -160,7 +159,7 @@ export function lowerStringSplitCall( const key = `str.split:${receiver.type.kind === "union" ? typeKey(receiver.type) : receiver.type.kind}:${typeKey(separator.type)}:${typeKey(limit.type)}:${absent}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%str.split", key); + helper = `%str.split.${lowerer.valueHelpers.size}`; const values = [receiver, separator, limit]; const params = values.map((value, index) => ({ localId: `arg.${index}`, @@ -396,7 +395,7 @@ function stringIndexHelperCall( const key = `str.index:${method}:${typeKey(receiver.type)}:${typeKey(index.type)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%str.index", key); + helper = `%str.index.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const rawReceiver = varRef("arg.0", receiver.type, loc); const rawIndex = varRef("arg.1", index.type, loc); @@ -674,7 +673,7 @@ export function lowerStringPaddingCall( const key = `str.pad:${method}:${values.map((value) => typeKey(value.type)).join(":")}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%str.pad", key); + helper = `%str.pad.${lowerer.valueHelpers.size}`; const params = values.map((value, index) => ({ localId: `arg.${index}`, name: `arg${index}`, @@ -1310,7 +1309,7 @@ export function lowerStringMethodCall( const key = `str.positions:${entry.method}:${typeKey(needle.type)}:${typeKey(position.type)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%str.positions", key); + helper = `%str.positions.${lowerer.valueHelpers.size}`; const params = [receiver, needle, position].map((arg, index) => ({ localId: `arg.${index}`, name: `arg${index}`, @@ -1412,7 +1411,7 @@ export function lowerStringMethodCall( const key = `str.positions:${entry.method}:${args.map((arg) => typeKey(arg.type)).join(":")}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%str.positions", key); + helper = `%str.positions.${lowerer.valueHelpers.size}`; const params = [receiver, ...args].map((arg, index) => ({ localId: `arg.${index}`, name: `arg${index}`, diff --git a/packages/compiler/src/frontend/lowering/containers/string-replacement.ts b/packages/compiler/src/frontend/lowering/containers/string-replacement.ts index 780c77d0f..6856bc50b 100644 --- a/packages/compiler/src/frontend/lowering/containers/string-replacement.ts +++ b/packages/compiler/src/frontend/lowering/containers/string-replacement.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import * as ts from "../../ts7/adapter.js"; import { BOOL, @@ -163,7 +162,7 @@ function lowerStringReplacementValues( const key = `str.${method}:${typeKey(replacement.type)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%str.${method}`, key); + helper = `%str.${method}.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const subject = varRef("s.0", STRING, loc); const needle = varRef("search.0", STRING, loc); diff --git a/packages/compiler/src/frontend/lowering/expressions/binary.ts b/packages/compiler/src/frontend/lowering/expressions/binary.ts index 7e449f12b..fafbbf695 100644 --- a/packages/compiler/src/frontend/lowering/expressions/binary.ts +++ b/packages/compiler/src/frontend/lowering/expressions/binary.ts @@ -1,5 +1,4 @@ /* Binary operators: arithmetic, comparisons and equality, logical and nullish pairs, and string conversion for concatenation. */ -import { keyedHelperName } from "../stable-names.js"; import * as ts from "../../ts7/adapter.js"; import { cleanFuncAdaptable } from "../coercions/function-adapters.js"; import { type Lowerer, jsFuncNameOf } from "../lowerer.js"; @@ -802,7 +801,7 @@ function nullProtoToString(lowerer: Lowerer, e: IrExpr, t: IrType & { kind: "rec const key = `nullProtoToString:${t.shapeId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%rec.tostr", key); + helper = `%rec.tostr.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const r = varRef("r.0", t, loc); lowerer.liftedFns.push({ diff --git a/packages/compiler/src/frontend/lowering/expressions/object-literals.ts b/packages/compiler/src/frontend/lowering/expressions/object-literals.ts index 93bf43e95..565db0cd8 100644 --- a/packages/compiler/src/frontend/lowering/expressions/object-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/object-literals.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "../stable-names.js"; import { dateJsonType, isDateJsonSource } from "../builtins/dates.js"; import { dynUndefinedExpr, numLit, strLit, varRef } from "../../../ir/build.js"; import { pathModuleValue } from "../lower-builtin-values.js"; @@ -407,7 +406,7 @@ export function lowerDynObjectLiteral( if (!(err instanceof PoisonError) || !pureMember) throw err; const fence = lowerer.deferToRuntimeFence(propDiagsBefore, prop, { kind: "closure", - name: () => lowerer.closureName(loc, "_dynfence"), + name: () => `%fn${lowerer.lambdaCounter++}_dynfence`, returnType: VOID, type: { kind: "func", params: [], ret: VOID }, }); @@ -462,7 +461,7 @@ export function lowerDynObjectLiteral( if (!(err instanceof PoisonError)) throw err; const fence = lowerer.deferToRuntimeFence(convDiagsBefore, prop, { kind: "closure", - name: () => lowerer.closureName(loc, "_dynfence"), + name: () => `%fn${lowerer.lambdaCounter++}_dynfence`, returnType: VOID, type: { kind: "func", params: [], ret: VOID }, }); @@ -2957,7 +2956,7 @@ function lowerDeclaredSpreadMerge( const key = `declmerge-source:${type.shapeId}:${source.shapeId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%rec.declmerge", key); + helper = `%rec.declmerge.${lowerer.valueHelpers.size}`; const sourceType = source.value.type; const destination = varRef("out.0", type, loc); const receiver = varRef("source.0", sourceType, loc); diff --git a/packages/compiler/src/frontend/lowering/expressions/optional-chains.ts b/packages/compiler/src/frontend/lowering/expressions/optional-chains.ts index 4b8c5692a..fbcecdc32 100644 --- a/packages/compiler/src/frontend/lowering/expressions/optional-chains.ts +++ b/packages/compiler/src/frontend/lowering/expressions/optional-chains.ts @@ -240,7 +240,7 @@ export function lowerOptionalChain( const receiver = lowerer.runtimeOptionalSourceValue(recvNode, loweredReceiver) ?? loweredReceiver; if (receiver.type.kind === "dyn") { if (dotNode === expr && ts.isCallExpression(expr)) { - const id = lowerer.closureName(loc, "", "chain"); + const id = `chain.${lowerer.chainCounter++}`; const callee: IrExpr = { kind: "chainRecv", id, type: DYN, loc }; const stmts: IrStmt[] = []; let guarded = receiver; @@ -298,7 +298,7 @@ export function lowerOptionalChain( ); } if (dotNode === expr && ts.isElementAccessExpression(expr)) { - const id = lowerer.closureName(loc, "", "chain"); + const id = `chain.${lowerer.chainCounter++}`; const reference: IrExpr = { kind: "chainRecv", id, type: DYN, loc }; lowerer.chainRecvByNode.set(recvNode, reference); lowerer.chainHandled.add(dotNode); @@ -331,7 +331,7 @@ export function lowerOptionalChain( dotNode === expr.expression ) { const m = dotNode.name.text; - const id = lowerer.closureName(loc, "", "chain"); + const id = `chain.${lowerer.chainCounter++}`; const recvRef: IrExpr = { kind: "chainRecv", id, type: DYN, loc: locOf(recvNode) }; lowerer.chainRecvByNode.set(recvNode, recvRef); lowerer.chainHandled.add(dotNode); @@ -358,7 +358,7 @@ export function lowerOptionalChain( } return { kind: "optChain", id, receiver, body, type: DYN, loc }; } - const id = lowerer.closureName(loc, "", "chain"); + const id = `chain.${lowerer.chainCounter++}`; const reference: IrExpr = { kind: "chainRecv", id, type: DYN, loc }; lowerer.chainRecvByNode.set(recvNode, reference); lowerer.chainHandled.add(dotNode); @@ -420,7 +420,7 @@ export function lowerOptionalChain( rest.length === 1 ? rest[0]! : { kind: "union" as const, unionId: lowerer.unions.transform(def, rest) }; - const id = lowerer.closureName(loc, "", "chain"); + const id = `chain.${lowerer.chainCounter++}`; // A single present arm binds its payload. Multiple present arms bind // the original tagged value, then retag inside the guarded body. The // nullish arms never enter that body, and each record keeps its identity. diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 6c8dfa3bf..f0b980da0 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -1,5 +1,4 @@ /* Property reads (`a.b`): lowerExprInner's property-access branch, intrinsic and union properties, field reads and targets, and match-group reads. */ -import { keyedHelperName } from "../stable-names.js"; import { staticallySelected } from "../static-typeof.js"; import * as ts from "../../ts7/adapter.js"; import { lowerHistogramProperty } from "../builtins/performance.js"; @@ -2784,7 +2783,7 @@ export function lowerGroupsProjection( const key = `regexgroups:${shapeId}:${groups.map((g) => `${g.name}=${g.index}`).join(",")}:${recvKey}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%regex.groups", key); + helper = `%regex.groups.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const body: IrStmt[] = []; const locals: IrLocal[] = [{ id: "m.0", name: "m", type: recv.type, mutable: true }]; diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index 836391835..088b45cff 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -1,5 +1,4 @@ /* instanceof and in, including private-name and runtime-key in. */ -import { keyedHelperName } from "../stable-names.js"; import * as ts from "../../ts7/adapter.js"; import { builtinClassInstanceOfAny, builtinClassKind } from "../builtins/builtin-class-dyn.js"; import { @@ -648,7 +647,7 @@ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc const key = `instanceof.union:${unionId}:${target.def.name}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%instanceof.union", key); + helper = `%instanceof.union.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const value: IrExpr = { kind: "varRef", localId: "value.0", type: left.type, loc }; const body: IrStmt[] = []; @@ -1848,7 +1847,7 @@ function lowerRuntimeKeyIn( const hkey = `haskey:${recvT.shapeId}`; let helper = lowerer.valueHelpers.get(hkey); if (!helper) { - helper = keyedHelperName(lowerer, "%rec.haskey", hkey); + helper = `%rec.haskey.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(hkey, helper); const recT: IrType = { kind: "record", shapeId: recvT.shapeId }; diff --git a/packages/compiler/src/frontend/lowering/generic-functions.ts b/packages/compiler/src/frontend/lowering/generic-functions.ts index daf082db7..abcd5a584 100644 --- a/packages/compiler/src/frontend/lowering/generic-functions.ts +++ b/packages/compiler/src/frontend/lowering/generic-functions.ts @@ -1,6 +1,4 @@ import { staticNameBindings } from "./static-function-names.js"; -import { positionTag } from "./structural-positions.js"; -import { keyedHelperName } from "./stable-names.js"; import * as ts from "../ts7/adapter.js"; import { bodyReadsArguments } from "../arguments-usage.js"; import type { Lowerer } from "./lowerer.js"; @@ -231,10 +229,7 @@ export function collectGenericSignature(lowerer: Lowerer, decl: ts.FunctionDecla lowerer.genericFnsBySymbol.set(symbol, { decl, baseName: nameText, - qualifiedName: lowerer.qualify( - ts.getSourceFileOfNode(decl), - nsPathPrefix(lowerer, decl) + nameText, - ), + qualifiedName: lowerer.qualify(ts.getSourceFileOfNode(decl), nsPathPrefix(decl) + nameText), typeParams, instances: new Map(), }); @@ -656,7 +651,7 @@ function internGenericInstance( const typeArgsText = `<${rendered.length > 80 ? rendered.slice(0, 77) + "..." : rendered}>`; inst = { path, - name: keyedHelperName(lowerer, `${info.qualifiedName}%`, key, ""), + name: `${info.qualifiedName}%${info.instances.size}`, ordinal: info.instances.size, params, returnType, @@ -2134,7 +2129,7 @@ function internImplicitInstance( const declared = dynamicBroadPromise ? null : implicitDeclaredReturn(lowerer, info); inst = { path, - name: keyedHelperName(lowerer, `${info.qualifiedName}%`, key, ""), + name: `${info.qualifiedName}%${info.instances.size}`, ordinal: info.instances.size, params: shapes, // The promise callers rely on before the body settles it: the @@ -2322,7 +2317,7 @@ export function implicitLocalFnInfoOf( baseName: name, qualifiedName: lowerer.qualify( ts.getSourceFileOfNode(decl), - nsPathPrefix(lowerer, stmt ?? decl, decl) + `${name}%l${positionTag(lowerer, decl)}`, + nsPathPrefix(stmt ?? decl, decl) + `${name}%l${ts.tokenStartOfNode(decl)}`, ), typeParams: [], instances: new Map(), @@ -2418,7 +2413,7 @@ export function objLitGenericFnInfoOf( baseName: name, qualifiedName: lowerer.qualify( ts.getSourceFileOfNode(fnNode), - `%ol${positionTag(lowerer, fnNode)}.${name}`, + `%ol${ts.tokenStartOfNode(fnNode)}.${name}`, ), typeParams, instances: new Map(), @@ -2564,7 +2559,7 @@ export function bindingGenericFnInfoOf( baseName: name, qualifiedName: lowerer.qualify( ts.getSourceFileOfNode(decl), - nsPathPrefix(lowerer, stmt ?? decl, decl) + + nsPathPrefix(stmt ?? decl, decl) + (topLevel ? name : `${name}%l${ts.tokenStartOfNode(decl)}`), ), typeParams, diff --git a/packages/compiler/src/frontend/lowering/intern-tables.ts b/packages/compiler/src/frontend/lowering/intern-tables.ts index e3f2b0889..fc69237db 100644 --- a/packages/compiler/src/frontend/lowering/intern-tables.ts +++ b/packages/compiler/src/frontend/lowering/intern-tables.ts @@ -23,7 +23,6 @@ * The entry handles that itable.find and itable.insert answer stay inside * these lowerings: f64 locals that only reach toBool and itable.value. * Any other use of the class or its members as values is refused. */ -import { keyedHelperName } from "./stable-names.js"; import { dynUndefinedExpr } from "../../ir/build.js"; import { BOOL, F64, STRING, funcOf, typeKey } from "../../ir/ir.js"; import type { IrExpr, IrFunction, IrStmt, IrType, SrcLoc } from "../../ir/ir.js"; @@ -448,11 +447,7 @@ function helperName(lowerer: Lowerer, member: InternTableMember, signature: stri } function registerHelper(lowerer: Lowerer, member: InternTableMember, signature: string): string { - const name = keyedHelperName( - lowerer, - `%${INTERN_TABLE_CLASS}.${member}`, - `${member}|${signature}`, - ); + const name = `%${INTERN_TABLE_CLASS}.${member}.${lowerer.internTableHelpers.size}`; lowerer.internTableHelpers.set(`${member}|${signature}`, name); return name; } diff --git a/packages/compiler/src/frontend/lowering/iterator-adapters.ts b/packages/compiler/src/frontend/lowering/iterator-adapters.ts index e50652182..898c46f20 100644 --- a/packages/compiler/src/frontend/lowering/iterator-adapters.ts +++ b/packages/compiler/src/frontend/lowering/iterator-adapters.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { dynUndefinedExpr, varRef } from "../../ir/build.js"; import { BOOL, @@ -87,7 +86,7 @@ function dynIteratorAdapter( const key = `iterAdapt:${typeKey(expected)}`; let name = lowerer.valueHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%iter.adapt", key); + name = `%iter.adapt.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const locals: IrLocal[] = []; const local = (id: string, type: IrType, mutable = false): IrExpr => { @@ -314,7 +313,7 @@ export function lowerCollectionIteratorValue( loc, }; if (!typeEquals(yielded.type, type.yieldT)) return null; - name = keyedHelperName(lowerer, "%coll.iter", key); + name = `%coll.iter.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ name, @@ -412,7 +411,7 @@ export function lowerBytesIteratorValue( const key = `bytesIter:${method}:${typeKey(bytesT)}:${typeKey(type)}`; let name = lowerer.valueHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%bytes.iter", key); + name = `%bytes.iter.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const list = varRef("list.0", bytesT, loc); const index = varRef("index.0", F64, loc); @@ -518,7 +517,7 @@ export function lowerStringIteratorValue( const key = `strIter:${typeKey(type)}`; let name = lowerer.valueHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%str.iter", key); + name = `%str.iter.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const text = varRef("text.0", STRING, loc); const index = varRef("index.0", F64, loc); @@ -678,7 +677,7 @@ function generatorRetypeAdapter( type: resumeType(expected.nextT), loc, }; - name = keyedHelperName(lowerer, "%gen.retype", key); + name = `%gen.retype.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ name, @@ -795,7 +794,7 @@ export function generatorDrain( const outRef = varRef("out.0", arrT, loc); const value = lowerer.coerceToExpected(genValue(genRef, loc), elem); if (!typeEquals(value.type, elem)) return null; - name = keyedHelperName(lowerer, "%gen.drain", key); + name = `%gen.drain.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ name, @@ -857,7 +856,7 @@ export function generatorDrain( if (!raw) return null; const value = lowerer.coerceToExpected(raw, elem); if (!typeEquals(value.type, elem)) return null; - name = keyedHelperName(lowerer, "%gen.drain", key); + name = `%gen.drain.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ name, @@ -979,7 +978,7 @@ export function lowerArrayIteratorValue( }; } if (!yielded || !typeEquals(yielded.type, type.yieldT)) return null; - name = keyedHelperName(lowerer, "%arr.iter", key); + name = `%arr.iter.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ name, diff --git a/packages/compiler/src/frontend/lowering/js-dynamic-objects.ts b/packages/compiler/src/frontend/lowering/js-dynamic-objects.ts index e27dd4183..b9bbf6216 100644 --- a/packages/compiler/src/frontend/lowering/js-dynamic-objects.ts +++ b/packages/compiler/src/frontend/lowering/js-dynamic-objects.ts @@ -21,7 +21,6 @@ * files only, and an empty answer leaves every mapping unchanged, so * TypeScript programs and JavaScript that never uses these patterns * compile exactly as before. */ -import { keyedHelperName } from "./stable-names.js"; import * as ts from "../ts7/adapter.js"; import { isJsSourceFile, locOf } from "../program.js"; import { BOOL, DYN, type IrExpr, type IrStmt } from "../../ir/ir.js"; @@ -216,10 +215,10 @@ export function lowerValueReturningConstructorNew( "spread arguments when constructing a class whose constructor returns a value", ); } - const key = `ctorValue:${lowerer.positions.of(decl)}`; + const key = `ctorValue:${ts.getSourceFileOfNode(decl).fileName}:${ts.tokenStartOfNode(decl)}`; let name = lowerer.valueHelpers.get(key); if (name === undefined) { - name = keyedHelperName(lowerer, "%ctorValue", key); + name = `%ctorValue.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const savedClass = lowerer.currentClass; lowerer.currentClass = null; diff --git a/packages/compiler/src/frontend/lowering/json-require.ts b/packages/compiler/src/frontend/lowering/json-require.ts index d6c2da571..927745253 100644 --- a/packages/compiler/src/frontend/lowering/json-require.ts +++ b/packages/compiler/src/frontend/lowering/json-require.ts @@ -10,7 +10,6 @@ * JSON module is ordinary storage holding that object — destructuring * copies its properties at the require, exactly like Node. ES-module JSON * imports keep their own record (Node's ESM loader caches separately). */ -import { keyedHelperName } from "./stable-names.js"; import * as ts from "../ts7/adapter.js"; import type { Lowerer } from "./lowerer.js"; import { PoisonError } from "./lowerer.js"; @@ -85,7 +84,7 @@ export function collectJsonRequires(lowerer: Lowerer, parts: FileParts[]): void ); throw new PoisonError(); } - const id = keyedHelperName(lowerer, "%g.jsonRequire", jsonSf.fileName); + const id = `%g.jsonRequire.${lowerer.jsonRequireModules.size}`; const global: IrGlobal = { id, name: "%json", type: mapped, mutable: true }; const loadedId = `${id}%loaded`; lowerer.globalsList.push(global, { diff --git a/packages/compiler/src/frontend/lowering/lifetime-regions.ts b/packages/compiler/src/frontend/lowering/lifetime-regions.ts index b684c0395..b212ae473 100644 --- a/packages/compiler/src/frontend/lowering/lifetime-regions.ts +++ b/packages/compiler/src/frontend/lowering/lifetime-regions.ts @@ -14,7 +14,6 @@ * Any other use of the class or its methods as values is refused. The * module is marked lifetimeRegions, which moves every ProgramLifetime * class into counted regions. */ -import { keyedHelperName } from "./stable-names.js"; import { F64, VOID, funcOf, typeKey } from "../../ir/ir.js"; import type { IrExpr, IrFunction, IrStmt, IrType, SrcLoc } from "../../ir/ir.js"; import { experimentalImportOf, lifetimeRegionMemberOf } from "../experimental-import.js"; @@ -153,7 +152,7 @@ function runHelper(lowerer: Lowerer, fnType: IrType & { kind: "func" }, loc: Src const key = typeKey(fnType); const known = lowerer.regionRunHelpers.get(key); if (known !== undefined) return known; - const name = keyedHelperName(lowerer, `%${LIFETIME_REGION_CLASS}.run`, key); + const name = `%${LIFETIME_REGION_CLASS}.run.${lowerer.regionRunHelpers.size}`; lowerer.regionRunHelpers.set(key, name); const regionT = lifetimeRegionType(lowerer); const ret = fnType.ret; diff --git a/packages/compiler/src/frontend/lowering/lower-assert.ts b/packages/compiler/src/frontend/lowering/lower-assert.ts index bc51a9382..460f4d53a 100644 --- a/packages/compiler/src/frontend/lowering/lower-assert.ts +++ b/packages/compiler/src/frontend/lowering/lower-assert.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { InternalCompilerError } from "../../errors.js"; /* The node:assert lowering (a spoke module like lower-dgram.ts): the * callable module form (`assert(x)` through a default import or a CJS @@ -668,7 +667,7 @@ function partialEqHelper(lowerer: Lowerer, ta: IrType, tb: IrType, loc: SrcLoc): const key = `assert.pdeq:${typeKey(ta)}|${typeKey(tb)}`; const existing = lowerer.assertHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%assert.pdeq", key); + const name = `%assert.pdeq.${lowerer.assertHelpers.size}`; lowerer.assertHelpers.set(key, name); const a = (): IrExpr => varRef("a.0", ta, loc); const b = (): IrExpr => varRef("b.0", tb, loc); @@ -1281,7 +1280,7 @@ function deepCheckCall( const key = `assert.dcheck:${variant}:${negated}:${typeKey(a.type)}:${typeKey(b.type)}`; let name = lowerer.assertHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%assert.dcheck", key); + name = `%assert.dcheck.${lowerer.assertHelpers.size}`; lowerer.assertHelpers.set(key, name); const pa = varRef("a.0", a.type, loc); const pb = varRef("b.0", b.type, loc); @@ -1845,7 +1844,7 @@ function assertThrowsHelper( const key = `assert.${mode}:${recvIsPromise ? "p" : "f"}:${typeKey(recvType)}:${sig}`; const existing = lowerer.assertHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%assert.${mode}`, key); + const name = `%assert.${mode}.${lowerer.assertHelpers.size}`; lowerer.assertHelpers.set(key, name); const caughtRef = (): IrExpr => varRef("e.0", CAUGHT, loc); @@ -2294,7 +2293,7 @@ function ifErrorHelper(lowerer: Lowerer, t: IrType & { kind: "union" }, loc: Src const key = `assert.iferr:${typeKey(t)}`; const existing = lowerer.assertHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%assert.iferr", key); + const name = `%assert.iferr.${lowerer.assertHelpers.size}`; lowerer.assertHelpers.set(key, name); const def = lowerer.unions.get(t.unionId); if (!def) throw new InternalCompilerError(`assert.ifError over unknown union ${t.unionId}`); @@ -2465,7 +2464,7 @@ function deepEqHelper(lowerer: Lowerer, t: IrType, loc: SrcLoc, loose = false): const key = `assert.${prefix}:${typeKey(t)}`; const existing = lowerer.assertHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%assert.${prefix}`, key); + const name = `%assert.${prefix}.${lowerer.assertHelpers.size}`; lowerer.assertHelpers.set(key, name); const a = (): IrExpr => varRef("a.0", t, loc); diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 63b8781f2..7102f37ab 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { isForwardedTupleSpread, lowerForwardingApply } from "./typed-arguments.js"; import { guardNullProto, nullProtoRecordShape } from "./null-prototype.js"; import { lowerDynStreamMemberCall } from "./dyn-streams.js"; @@ -2095,7 +2094,7 @@ function lowerOptionalNumberDefault( const key = `number.optionalDefault:${widened.unionId}:${dflt}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%number.optionalDefault", key); + helper = `%number.optionalDefault.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const input = varRef("value.0", widened, loc); lowerer.liftedFns.push({ @@ -2204,7 +2203,7 @@ function primitiveConversionHandler( const key = `then.${name}:${typeKey(inner)}`; let fnName = lowerer.arrHofHelpers.get(key); if (fnName === undefined) { - fnName = keyedHelperName(lowerer, `%then.${name}`, key); + fnName = `%then.${name}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, fnName); const value = varRef("v.0", inner, loc); let body: IrExpr; @@ -2373,7 +2372,7 @@ function lowerBigIntConstructorValue(lowerer: Lowerer, arg: IrExpr, loc: SrcLoc) const key = `bigint.scalar:${unionId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%bigint.scalar", key); + helper = `%bigint.scalar.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const value = varRef("value.0", arg.type, loc); const body: IrStmt[] = []; @@ -3235,7 +3234,7 @@ function lowerScalarUnionNumber( const key = `number.scalar:${arg.type.unionId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%number.scalar", key); + helper = `%number.scalar.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const value = varRef("value.0", arg.type, loc); const nan: IrExpr = { @@ -3280,7 +3279,7 @@ function lowerOptionalStringNumber( const key = `${label}.optionalString:${arg.type.unionId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%${label}.optionalString`, key); + helper = `%${label}.optionalString.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const value = varRef("value.0", arg.type, loc); lowerer.liftedFns.push({ @@ -4707,7 +4706,7 @@ function lowerDefaultToStringCall( const key = `objToStr:${typeKey(recv.type)}${missing ? `:${missing}` : ""}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%obj.tostr", key); + helper = `%obj.tostr.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const o = varRef("o.0", recv.type, loc); lowerer.liftedFns.push({ @@ -5394,7 +5393,7 @@ function loweredTemplateStrings( const site = lowerer.globalsList.length; const globalId = `%g.templateStrings.${site}`; const readyId = `%g.templateStringsReady.${site}`; - getter = keyedHelperName(lowerer, "%templateStrings.get", key); + getter = `%templateStrings.get.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, getter); lowerer.globalsList.push( { id: globalId, name: "%templateStrings", type, mutable: true }, @@ -5575,7 +5574,7 @@ export function lowerPromiseMethodCall( // IS the spec's identity/thrower/no-op substitution for all three // members. An argument expression, when present, is undefined/null // by construction — nothing to evaluate. - const fnName = lowerer.closureName(loc, `_${member}pass`); + const fnName = `%fn${lowerer.lambdaCounter++}_${member}pass`; const funcType: IrType & { kind: "func" } = { kind: "func", params: [promT], ret: promT }; const fnCtx = newFnCtx(true, null, funcType, inner); fnCtx.isAsync = true; @@ -5672,7 +5671,7 @@ export function lowerPromiseMethodCall( // Evaluate both callback expressions before the wrapper runs, in source order. const fulfilled = fulfilledAbsent ? null : boxHandler(fulfilledNode, true); const rejected = rejectedAbsent ? null : boxHandler(rejectedNode, false); - const fnName = lowerer.closureName(loc, "_then2"); + const fnName = `%fn${lowerer.lambdaCounter++}_then2`; const paramTypes: IrType[] = [ promT, ...(fulfilled ? [fulfilled.value.type] : []), @@ -5921,7 +5920,7 @@ export function lowerPromiseMethodCall( ); }; const resultT: IrType & { kind: "promise" } = { kind: "promise", inner: DYN }; - const fnName = lowerer.closureName(loc, "_then"); + const fnName = `%fn${lowerer.lambdaCounter++}_then`; const funcType: IrType & { kind: "func" } = { kind: "func", params: [promT, DYN], @@ -6016,7 +6015,7 @@ export function lowerPromiseMethodCall( ); } const R = resultT.inner; - const fnName = lowerer.closureName(loc, "_then"); + const fnName = `%fn${lowerer.lambdaCounter++}_then`; const funcType: IrType & { kind: "func" } = { kind: "func", params: [promT, cb.type], @@ -6119,7 +6118,7 @@ export function lowerPromiseMethodCall( "finally callbacks with parameters or a return value (use () => { ... })", ); } - const fnName = lowerer.closureName(loc, "_finally"); + const fnName = `%fn${lowerer.lambdaCounter++}_finally`; const funcType: IrType & { kind: "func" } = { kind: "func", params: [promT, cb.type], @@ -6222,7 +6221,7 @@ export function lowerPromiseMethodCall( } if (cb.type.kind === "dyn") { const resultT: IrType & { kind: "promise" } = { kind: "promise", inner: DYN }; - const fnName = lowerer.closureName(loc, "_catchdyn"); + const fnName = `%fn${lowerer.lambdaCounter++}_catchdyn`; const funcType: IrType & { kind: "func" } = { kind: "func", params: [promT, DYN], @@ -6352,7 +6351,7 @@ export function lowerPromiseMethodCall( ); } const R = resultT.inner; - const fnName = lowerer.closureName(loc, "_catch"); + const fnName = `%fn${lowerer.lambdaCounter++}_catch`; const funcType: IrType & { kind: "func" } = { kind: "func", params: [promT], ret: resultT }; const fnCtx = newFnCtx(true, null, funcType, R); fnCtx.isAsync = true; @@ -6589,7 +6588,7 @@ function filterNarrowHelper( const key = `filterNarrow:${test}:${typeKey(elem)}:${typeKey(outElem)}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%arr.filterNarrow", key); + const name = `%arr.filterNarrow.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const arrT = arrayOf(elem); @@ -6835,7 +6834,7 @@ export function recordKeysArrayCall( const key = `obj.keys:${argIr.shapeId}:${typeKey(resultT)}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%obj.keys", key); + helper = `%obj.keys.${lowerer.arrHofHelpers.size}`; const ref: IrExpr = { kind: "varRef", localId: "r.0", type: argIr, loc }; const outRef: IrExpr = { kind: "varRef", localId: "out.0", type: resultT, loc }; lowerer.arrHofHelpers.set(key, helper); @@ -6905,7 +6904,7 @@ function recordHasOwnHelper(lowerer: Lowerer, shapeId: string, loc: SrcLoc): str const key = `obj.hasOwn:${shapeId}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const helper = keyedHelperName(lowerer, "%obj.hasOwn", key); + const helper = `%obj.hasOwn.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const shape = lowerer.shapes.get(shapeId)!; const recT: IrType = { kind: "record", shapeId }; @@ -6990,7 +6989,7 @@ function classAssignHelper( const key = `obj.assignClass:${className}:${srcShapeId}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const helper = keyedHelperName(lowerer, "%obj.assignClass", key); + const helper = `%obj.assignClass.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const sShape = lowerer.shapes.get(srcShapeId)!; const oT: IrType = { kind: "object", className }; @@ -7058,7 +7057,7 @@ function recordAssignHelper( const key = `obj.assign:${targetShapeId}:${srcShapeId}`; const existing = lowerer.arrHofHelpers.get(key); if (existing) return existing; - const helper = keyedHelperName(lowerer, "%obj.assign", key); + const helper = `%obj.assign.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const sShape = lowerer.shapes.get(srcShapeId)!; const tShape = lowerer.shapes.get(targetShapeId)!; @@ -8515,7 +8514,7 @@ function lowerObjectStaticCall( const key = `obj.${member}:${argIr.shapeId}:${typeKey(resultT)}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%obj.${member}`, key); + helper = `%obj.${member}.${lowerer.arrHofHelpers.size}`; const recT = argIr; const ref: IrExpr = { kind: "varRef", localId: "r.0", type: recT, loc }; const outRef: IrExpr = { kind: "varRef", localId: "out.0", type: resultT, loc }; @@ -9151,7 +9150,7 @@ function lowerInlineArrowBind( const length = firstDefault < 0 ? arrow.parameters.nodes.length : firstDefault; const key = `arrow.bind:${typeKey(type)}:${length}`; const existing = lowerer.arrHofHelpers.get(key); - const name = existing ?? keyedHelperName(lowerer, "%arrow.bind", key); + const name = existing ?? `%arrow.bind.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, name); lowerer.freshClosureAdapters.add(name); @@ -10080,7 +10079,7 @@ function lowerUnionObjectDynFieldCall( const receiverRef = varRef(receiverLocal.id, receiverT, loc); let helper = lowerer.unionCallHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%union.call", key); + helper = `%union.call.${lowerer.unionCallHelpers.size}`; lowerer.unionCallHelpers.set(key, helper); const receiverRef = varRef("this.0", receiverT, loc); const branch = (plan: (typeof plans)[number]): IrStmt[] => { @@ -10173,7 +10172,7 @@ function unionObjectMethodHelper( const key = `${receiverT.unionId}:${method}:${shapes.map((shape) => `${shape.mode}:${typeKey(shape.type)}`).join(",")}:${typeKey(resultT)}`; const existing = lowerer.unionCallHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%union.call", key); + const name = `%union.call.${lowerer.unionCallHelpers.size}`; lowerer.unionCallHelpers.set(key, name); // A probe that catches a refusal while the body lowers must not leave // the name registered for a helper that was never emitted. @@ -10367,7 +10366,7 @@ export function lowerStaticNumberGlobal( const key = `parseInt.optional:${unionT.unionId}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%parseInt.optional", key); + helper = `%parseInt.optional.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const value: IrExpr = { kind: "varRef", localId: "value.0", type: unionT, loc }; const radixRef: IrExpr = { kind: "varRef", localId: "radix.0", type: F64, loc }; diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index fcea03790..790efe988 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { lowerValueReturningConstructorNew } from "./js-dynamic-objects.js"; import { adaptPromiseExecutor } from "./promise-executor-adapter.js"; import { dynUndefinedExpr, nodeThrowExpr, varRef } from "../../ir/build.js"; @@ -4664,7 +4663,7 @@ export function genericClassInstanceType( ); } const ordinal = gci.instances.size; - const name = keyedHelperName(lowerer, `${gci.family.def.name}%`, key, ""); + const name = `${gci.family.def.name}%${ordinal}`; const entry: { name: string; info: ClassInfo | null; poisoned?: boolean } = { name, info: null }; gci.instances.set(key, entry); const bindings = new Map(); @@ -7911,7 +7910,7 @@ export function classIteratorDrainCall( const key = `${cit.className}:${typeKey(outElem)}`; let name = lowerer.iterDrainHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%iter.drain", key); + name = `%iter.drain.${lowerer.iterDrainHelpers.size}`; lowerer.iterDrainHelpers.set(key, name); const recvT: IrType = { kind: "object", className: cit.className }; const recvRef: IrExpr = { kind: "varRef", localId: "r.0", type: recvT, loc }; @@ -8025,7 +8024,7 @@ export function classIteratorRestDrainCall( const key = `it:${cit.iterT.className}`; let name = lowerer.iterDrainHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%iter.drain", key); + name = `%iter.drain.${lowerer.iterDrainHelpers.size}`; lowerer.iterDrainHelpers.set(key, name); const itRef: IrExpr = { kind: "varRef", localId: "it.0", type: cit.iterT, loc }; const outRef: IrExpr = { kind: "varRef", localId: "out.0", type: outT, loc }; @@ -10533,7 +10532,7 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { const key = `x509.record:${isBytes ? "bytes" : "str"}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%x509.record", key); + helper = `%x509.record.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const dataT = data.type; const dRef: IrExpr = { kind: "varRef", localId: "d.0", type: dataT, loc }; diff --git a/packages/compiler/src/frontend/lowering/lower-dgram.ts b/packages/compiler/src/frontend/lowering/lower-dgram.ts index aa90fc7c7..5c99ebc82 100644 --- a/packages/compiler/src/frontend/lowering/lower-dgram.ts +++ b/packages/compiler/src/frontend/lowering/lower-dgram.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { dynUndefinedExpr, boolLit } from "../../ir/build.js"; /* The dgram/dns-surface lowering (node:dgram + node:dns — a spoke module * like lower-server.ts): module-function calls (dgram createSocket, dns @@ -358,7 +357,7 @@ function checkedDynPromise( const key = `dns.promise:${typeKey(declared)}`; let helper = lowerer.valueHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%dns.promise", key); + helper = `%dns.promise.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, helper); const promiseT: IrType = { kind: "promise", inner: DYN }; lowerer.liftedFns.push({ @@ -892,7 +891,7 @@ export function lowerPromisifiedDnsCall( const key = `dnsPromise:${JSON.stringify(value)}`; let name = lowerer.valueHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%dnsPromise", key); + name = `%dnsPromise.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ name, diff --git a/packages/compiler/src/frontend/lowering/lower-event-emitter.ts b/packages/compiler/src/frontend/lowering/lower-event-emitter.ts index f105af786..f472672b2 100644 --- a/packages/compiler/src/frontend/lowering/lower-event-emitter.ts +++ b/packages/compiler/src/frontend/lowering/lower-event-emitter.ts @@ -42,7 +42,6 @@ * emit-overrides block at the bottom of this file (per-event * monomorphization of the override body, dispatch on the dynamic class, * super.emit as the prototype chain). */ -import { keyedHelperName } from "./stable-names.js"; import { checkKeypressListener } from "./builtins/readline.js"; import * as ts from "../ts7/adapter.js"; import type { Lowerer } from "./lowerer.js"; @@ -632,7 +631,7 @@ function lowerFlexListenerCall( const key = `emitter.${registering ? "onFlex" : "offDyn"}:${typeKey(recvT)}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, `%emitter.${registering ? "onFlex" : "offFlex"}`, key); + helper = `%emitter.${registering ? "onFlex" : "offFlex"}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const params: IrParam[] = [ { localId: "r.0", name: "r", type: recvT }, @@ -851,7 +850,7 @@ function lowerDynListenerCall( const existing = lowerer.arrHofHelpers.get(key); let helper = existing; if (!helper) { - helper = keyedHelperName(lowerer, `%emitter.${registering ? "onDyn" : "offDyn"}`, key); + helper = `%emitter.${registering ? "onDyn" : "offDyn"}.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const check: IrStmt = { kind: "exprStmt", @@ -1001,7 +1000,7 @@ export function lowerDynamicEmitterEmit( const key = `emitter.dynEmit:${typeKey(recvT)}:${k}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%emitter.dynEmit", key); + helper = `%emitter.dynEmit.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const params: IrParam[] = [ { localId: "r.0", name: "r", type: recvT }, @@ -1093,7 +1092,7 @@ export function lowerDynamicEmitterOn( const key = `emitter.dynOn:${typeKey(recvT)}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%emitter.dynOn", key); + helper = `%emitter.dynOn.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const params: IrParam[] = [ { localId: "r.0", name: "r", type: recvT }, @@ -2360,7 +2359,7 @@ function emitDispatchExpr( const key = `emitter.emitDispatch:${typeKey(recvT)}:${name}`; let helper = lowerer.arrHofHelpers.get(key); if (!helper) { - helper = keyedHelperName(lowerer, "%emitter.emitDispatch", key); + helper = `%emitter.emitDispatch.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const params: IrParam[] = [ { localId: "r.0", name: "r", type: recvT }, @@ -2425,7 +2424,7 @@ function eventsOnceBoxer( const key = `eventsOnce:${typeKey(fnType)}`; let name = lowerer.valueHelpers.get(key); if (name === undefined) { - name = keyedHelperName(lowerer, "%events.onceArgs", key); + name = `%events.onceArgs.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const params: IrParam[] = tuple.map((type, i) => ({ localId: `%once.a${i}`, diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index ba96bea8c..e7a1b79a8 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { lowerWebAssemblyValue, refuseWebAssemblyUse } from "./builtins/webassembly.js"; import { dynUndefinedExpr, nodeThrowExpr, numLit, strLit, varRef } from "../../ir/build.js"; import { InternalCompilerError } from "../../errors.js"; @@ -2275,11 +2274,7 @@ export function cjsAccessorSnapshotOf( if (!lexerVisibleAccessors(ts.getSourceFileOfNode(getter)).includes(getter)) return null; const call = cjsAccessorCall(lowerer, getter, locOf(getter)); if (call === null) return null; - const at = locOf(getter); - const snapshot = { - id: keyedHelperName(lowerer, "%g.cjsSnapshot", `${at.file}:${at.start}:${at.end}`), - type: call.type, - }; + const snapshot = { id: `%g.cjsSnapshot.${lowerer.cjsAccessorSnapshots.size}`, type: call.type }; lowerer.globalsList.push({ id: snapshot.id, name: "%cjsSnapshot", @@ -2304,7 +2299,7 @@ export function cjsAccessorSnapshotStores( if (getters.length === 0) return []; let readyId = lowerer.cjsSnapshotReady.get(dep); if (readyId === undefined) { - readyId = keyedHelperName(lowerer, "%g.cjsSnapshotReady", dep.fileName); + readyId = `%g.cjsSnapshotReady.${lowerer.cjsSnapshotReady.size}`; lowerer.globalsList.push({ id: readyId, name: "%cjsSnapshotReady", type: BOOL, mutable: true }); lowerer.cjsSnapshotReady.set(dep, readyId); } diff --git a/packages/compiler/src/frontend/lowering/lower-functions.ts b/packages/compiler/src/frontend/lowering/lower-functions.ts index 653c0d837..cd8dc31d1 100644 --- a/packages/compiler/src/frontend/lowering/lower-functions.ts +++ b/packages/compiler/src/frontend/lowering/lower-functions.ts @@ -270,7 +270,7 @@ export function lowerLambda( const nameIdent = !ts.isArrowFunction(node) && node.name && ts.isIdentifier(node.name) ? node.name : null; const baseName = nameIdent ? nameIdent.text : ""; - const fnName = lowerer.closureName(locOf(node), baseName ? `_${baseName}` : ""); + const fnName = `%fn${lowerer.lambdaCounter++}${baseName ? `_${baseName}` : ""}`; // Named function expressions/declarations can self-reference by name; an // object-literal method's name is a PROPERTY, not a binding — no self. const selfSymbol = diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index 1979b43aa..4be5d0b7e 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { dynUndefinedExpr, boolLit, @@ -269,7 +268,7 @@ function errorInspectHelper( const key = `insp.userError:${typeKey(t)}`; const existing = lowerer.inspectHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%util.insp", key); + const name = `%util.insp.${lowerer.inspectHelpers.size}`; lowerer.inspectHelpers.set(key, name); const v = (): IrExpr => varRef("v.0", t, loc); const r = (): IrExpr => varRef("r.0", F64, loc); @@ -1146,7 +1145,7 @@ function inspectHelper(lowerer: Lowerer, t: IrType, loc: SrcLoc): string { const key = `insp:${typeKey(t)}`; const existing = lowerer.inspectHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, "%util.insp", key); + const name = `%util.insp.${lowerer.inspectHelpers.size}`; lowerer.inspectHelpers.set(key, name); const v = (): IrExpr => varRef("v.0", t, loc); @@ -2075,7 +2074,7 @@ function formatUnionHelper( const existing = lowerer.inspectHelpers.get(key); if (existing) return existing; const loc = helperLoc(site); - const name = keyedHelperName(lowerer, "%util.fmtv", key); + const name = `%util.fmtv.${lowerer.inspectHelpers.size}`; lowerer.inspectHelpers.set(key, name); const def = lowerer.unions.get(t.unionId); if (!def) throw new InternalCompilerError(`format value over unknown union ${t.unionId}`); diff --git a/packages/compiler/src/frontend/lowering/lower-mixins.ts b/packages/compiler/src/frontend/lowering/lower-mixins.ts index 9de027563..766059dfb 100644 --- a/packages/compiler/src/frontend/lowering/lower-mixins.ts +++ b/packages/compiler/src/frontend/lowering/lower-mixins.ts @@ -34,7 +34,6 @@ * statics-bearing mixin classes outside a plain top-level statement * (their declaration-time code must run exactly where the call * evaluates). */ -import { positionTag } from "./structural-positions.js"; import * as ts from "../ts7/adapter.js"; import type { Lowerer } from "./lowerer.js"; import { PoisonError } from "./lowerer.js"; @@ -453,7 +452,7 @@ function instantiateMixinCall( const base = mixinBaseClassOf(lowerer, call.arguments.nodes[0]!); const instName = lowerer.qualify( ts.getSourceFileOfNode(call), - `%mx${positionTag(lowerer, call)}.${shape.classNode.name?.text ?? ""}`, + `%mx${ts.tokenStartOfNode(call)}.${shape.classNode.name?.text ?? ""}`, ); const ordinal = lowerer.mixinOrdinals.get(shape.classNode) ?? 0; lowerer.mixinOrdinals.set(shape.classNode, ordinal + 1); diff --git a/packages/compiler/src/frontend/lowering/lower-mock.ts b/packages/compiler/src/frontend/lowering/lower-mock.ts index 8c50dee46..fcc68c787 100644 --- a/packages/compiler/src/frontend/lowering/lower-mock.ts +++ b/packages/compiler/src/frontend/lowering/lower-mock.ts @@ -17,7 +17,6 @@ * writes the original back on restore(). Each mock registers a closure * that calls its restore() with its tracker (scr_test.c): the module's * `mock`, or the test's t.mock, which is reset when the test ends. */ -import { keyedHelperName } from "./stable-names.js"; import * as ts from "../ts7/adapter.js"; import { BOOL, @@ -137,7 +136,7 @@ function liftOnce( const key = `mock.${role}:${owner}`; const existing = lowerer.assertHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%mock.${role}`, key); + const name = `%mock.${role}.${lowerer.assertHelpers.size}`; lowerer.assertHelpers.set(key, name); build(name); return name; diff --git a/packages/compiler/src/frontend/lowering/lower-modules.test.ts b/packages/compiler/src/frontend/lowering/lower-modules.test.ts index f1021e4da..84cc96e7d 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.test.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.test.ts @@ -34,7 +34,7 @@ test("retains dependencies from function storage, captures, generator channels a const completed = record("completed"); const body = record("body"); const global = record("global", record("nested")); - const wanted = lowerer.shapes.shapes.map((shape) => shape.id).sort(); + const wanted = lowerer.shapes.shapes.map((shape) => shape.id); record("unused"); const unionId = lowerer.unions.intern([body, UNDEFINED_T]); const unusedUnion = lowerer.unions.intern([F64, UNDEFINED_T]); @@ -162,7 +162,7 @@ test("closes nested structural types and index-signature values", () => { sent = record("sent"), indexed = record("indexed"); const containerId = lowerer.shapes.intern([], false, indexed); - const wanted = lowerer.shapes.shapes.map((shape) => shape.id).sort(); + const wanted = lowerer.shapes.shapes.map((shape) => shape.id); record("unused"); const nested: IrType = { kind: "func", diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index 0b99e88d3..d1f276d44 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -1,5 +1,4 @@ import { THREADS_MODULE } from "../threads-import.js"; -import { positionTag } from "./structural-positions.js"; import { EXPERIMENTAL_MODULE } from "../experimental-import.js"; import { dynUndefinedExpr } from "../../ir/build.js"; import { everyStmtList, everyTypeChild } from "../../ir/traverse.js"; @@ -1075,14 +1074,8 @@ export function moduleArtifacts( else delete rest.abstractMethods; return rest; }), - // Ids come from what each shape and union is (keyedHelperName), so - // ordering by id gives every lowering order the same module. - records: lowerer.shapes.shapes - .filter((r) => shapeIds.has(r.id)) - .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)), - unions: lowerer.unions.unions - .filter((u) => unionIds.has(u.id)) - .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)), + records: lowerer.shapes.shapes.filter((r) => shapeIds.has(r.id)), + unions: lowerer.unions.unions.filter((u) => unionIds.has(u.id)), }; } @@ -1684,7 +1677,7 @@ export function collectGlobals( } if (type.kind === "void") lowerer.badType(stmt.name, lowerer.typeOf(stmt.name)); const g: IrGlobal = { - id: `%g.${tag}${nsPathPrefix(lowerer, stmt)}%alias.${stmt.name.text}%${positionTag(lowerer, stmt)}`, + id: `%g.${tag}${nsPathPrefix(stmt)}%alias.${stmt.name.text}%${ts.tokenStartOfNode(stmt)}`, name: stmt.name.text, type, mutable: false, @@ -1761,7 +1754,7 @@ export function collectGlobals( // (`%g.e.A%B.x`), so `namespace A { export const x }` and a // top-level `const x` never collide; non-exported members add the // declaring block's position (block-local bindings). - const nsPrefix = nsPathPrefix(lowerer, stmt, list.declarations.nodes[0]); + const nsPrefix = nsPathPrefix(stmt, list.declarations.nodes[0]); for (const decl of list.declarations.nodes) { // --provenance-sources: an elided pure-annotated dead const in a // fetched source module registers no global (the statement diff --git a/packages/compiler/src/frontend/lowering/lower-namespaces.ts b/packages/compiler/src/frontend/lowering/lower-namespaces.ts index 19123dae3..dca835d77 100644 --- a/packages/compiler/src/frontend/lowering/lower-namespaces.ts +++ b/packages/compiler/src/frontend/lowering/lower-namespaces.ts @@ -36,7 +36,6 @@ * of the compiler already takes (a body running before the declaring * statement is not modeled — same as top-level const reads through early * calls). */ -import { positionTag, type PositionTagOwner } from "./structural-positions.js"; import * as ts from "../ts7/adapter.js"; import { packageShimFor } from "../package-shims.js"; import type { Lowerer } from "./lowerer.js"; @@ -165,11 +164,7 @@ function registerTypeOnlyBlocks(lowerer: Lowerer, decl: ts.ModuleDeclaration): v * distinct (resolution is by symbol; names only need uniqueness and * determinism). `modifierDecl` carries the declaration whose modifiers * decide exportedness (the first declarator of a variable statement). */ -export function nsPathPrefix( - owner: PositionTagOwner, - node: ts.Node, - modifierDecl?: ts.Node, -): string { +export function nsPathPrefix(node: ts.Node, modifierDecl?: ts.Node): string { const parent = node.parent; if (parent === undefined || !ts.isModuleBlock(parent)) return ""; const flagsHost = modifierDecl ?? node; @@ -184,10 +179,10 @@ export function nsPathPrefix( const nested = p.parent !== undefined && ts.isModuleBlock(p.parent); const nonExported = nested && (ts.getCombinedModifierFlags(p) & ts.ModifierFlags.Export) === 0; - segs.unshift(p.name.text + (nonExported ? `%${positionTag(owner, p)}` : "")); + segs.unshift(p.name.text + (nonExported ? `%${ts.tokenStartOfNode(p)}` : "")); } } - return `${segs.join("%")}${exported ? "" : `%${positionTag(owner, parent)}`}.`; + return `${segs.join("%")}${exported ? "" : `%${ts.tokenStartOfNode(parent)}`}.`; } /** The registered namespace-block kind a symbol's declaration sits in diff --git a/packages/compiler/src/frontend/lowering/lower-server.ts b/packages/compiler/src/frontend/lowering/lower-server.ts index 94d49d8b3..058d7874a 100644 --- a/packages/compiler/src/frontend/lowering/lower-server.ts +++ b/packages/compiler/src/frontend/lowering/lower-server.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { dynUndefinedExpr, nodeThrowExpr, @@ -184,7 +183,7 @@ export function voidizedCallback(lowerer: Lowerer, cb: IrExpr, loc: SrcLoc): IrE const toT = funcOf([...fromT.params], VOID); const key = `server.voidcb:${typeKey(fromT)}`; const existing = lowerer.arrHofHelpers.get(key); - const name = existing ?? keyedHelperName(lowerer, "%server.voidcb", key); + const name = existing ?? `%server.voidcb.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, name); const impl = `${name}.impl`; @@ -280,7 +279,7 @@ function receiverReturningCall( ): IrExpr { const key = `server.recvret:${fn}:${opts?.prefix?.fn ?? ""}:${(opts?.mainArgIndices ?? []).join(".")}:${callArgs.map((a) => typeKey(a.type)).join(",")}`; const existing = lowerer.arrHofHelpers.get(key); - const name = existing ?? keyedHelperName(lowerer, "%server.recvret", key); + const name = existing ?? `%server.recvret.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, name); const params = callArgs.map((a, i) => ({ localId: `p${i}.0`, name: `p${i}`, type: a.type })); @@ -591,7 +590,7 @@ function h2HeadersCallbackAdapter( ); const key = `h2.hdrcb:${handleKind}:${withStatus}:${typeKey(fromT)}:${shapeId ?? ""}`; const existing = lowerer.arrHofHelpers.get(key); - const name = existing ?? keyedHelperName(lowerer, "%h2.hdrcb", key); + const name = existing ?? `%h2.hdrcb.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, name); const impl = `${name}.impl`; @@ -3584,7 +3583,7 @@ export function lowerCompatReqStreamOptionalCall( type: unionT, loc, }; - const id = lowerer.closureName(loc, "", "chain"); + const id = `chain.${lowerer.chainCounter++}`; const body = lowerH2StreamMethodCall(lowerer, call, call.expression, { kind: "chainRecv", id, @@ -4425,7 +4424,7 @@ function lowerHttpCreateServerForms( const hasMax = opts.maxHeaderSize !== null; const key = `server.opts:${opts.joinDup ? 1 : 0}:${opts.allowMissingHost ? 1 : 0}:${hasBuffer ? 1 : 0}:${hasMax ? 1 : 0}`; const existing = lowerer.arrHofHelpers.get(key); - const name = existing ?? keyedHelperName(lowerer, "%server.opts", key); + const name = existing ?? `%server.opts.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, name); const params = [ @@ -8010,7 +8009,7 @@ function lowerHttpResMethodCall( const all = [...callArgs, cb]; const key = `server.endcb:${fn}:${all.map((a) => typeKey(a.type)).join(",")}`; const existing = lowerer.arrHofHelpers.get(key); - const helper = existing ?? keyedHelperName(lowerer, "%server.endcb", key); + const helper = existing ?? `%server.endcb.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, helper); const params = all.map((a, i) => ({ localId: `p${i}.0`, name: `p${i}`, type: a.type })); diff --git a/packages/compiler/src/frontend/lowering/lower-stdlib.ts b/packages/compiler/src/frontend/lowering/lower-stdlib.ts index 0beb24a0e..2ad3657c7 100644 --- a/packages/compiler/src/frontend/lowering/lower-stdlib.ts +++ b/packages/compiler/src/frontend/lowering/lower-stdlib.ts @@ -2278,7 +2278,7 @@ function lowerStaticNamespaceImport( ): IrExpr { const loc = locOf(call); const resultT: IrType & { kind: "promise" } = { kind: "promise", inner: ns }; - const fnName = lowerer.closureName(loc, "_staticImport"); + const fnName = `%fn${lowerer.lambdaCounter++}_staticImport`; const fnType: IrType & { kind: "func" } = { kind: "func", params: [], ret: resultT }; const fnCtx = newFnCtx(true, null, fnType, ns); fnCtx.isAsync = true; diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index a75ec43b7..b9add95a6 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { nodeThrowExpr, boolLit, numLit, strLit } from "../../ir/build.js"; import { hashStreamOf, isHashValueType } from "./builtins/hash-stream.js"; import { InternalCompilerError } from "../../errors.js"; @@ -312,7 +311,7 @@ function lowerStreamCallback( ); } } - const fnName = lowerer.closureName(loc, `_${which}cb`); + const fnName = `%fn${lowerer.lambdaCounter++}_${which}cb`; const fnCtx = newFnCtx(true, null, funcType, funcType.ret); lowerer.fnStack.push(fnCtx); try { @@ -1145,7 +1144,7 @@ function streamMethodWrapper( paramTypes.push(got.type); } const ret = found.sig.ret; - const fnName = lowerer.closureName(loc, `_${which}vt`); + const fnName = `%fn${lowerer.lambdaCounter++}_${which}vt`; const funcType = funcOf([thisType, ...paramTypes], ret); lowerer.fnStack.push(newFnCtx(true, null, funcType, ret)); try { @@ -1691,7 +1690,7 @@ function fromGenHelpers( const key = `streamFromGen:${role}:${typeKey(gen)}`; let name = lowerer.valueHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, `%stream.fromGen.${role}`, key); + name = `%stream.fromGen.${role}.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ name, @@ -1780,7 +1779,7 @@ function classIteratorObject( const key = `streamFromIter:${cit.iterT.className}`; let name = lowerer.valueHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%stream.fromIter", key); + name = `%stream.fromIter.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const nextName = `${name}.next`; const nextT = funcOf([], DYN); @@ -1941,7 +1940,7 @@ function classAsyncIteratorObject( const key = `streamFromAsyncIter:${cit.className}`; let name = lowerer.valueHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%stream.fromAsyncIter", key); + name = `%stream.fromAsyncIter.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const it: IrLocal = { id: "it.0", name: "it", type: cit.iterT, mutable: false, boxed: true }; const src: IrLocal = { @@ -2895,7 +2894,7 @@ function pipelineBoxHelper( const key = `pipelineBox:${typeKey(promiseT)}`; let name = lowerer.valueHelpers.get(key); if (!name) { - name = keyedHelperName(lowerer, "%stream.pipelineBox", key); + name = `%stream.pipelineBox.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ name, @@ -2922,7 +2921,7 @@ function pipelineAbortHelper(lowerer: Lowerer, ac: IrExpr, loc: SrcLoc): IrExpr let name = lowerer.valueHelpers.get(key); const abortT = funcOf([], VOID); if (!name) { - name = keyedHelperName(lowerer, "%stream.pipelineAbort", key); + name = `%stream.pipelineAbort.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const acLocal: IrLocal = { id: "ac.0", name: "ac", type: DYN, mutable: false, boxed: true }; const acRef = varRef(acLocal.id, DYN, loc); diff --git a/packages/compiler/src/frontend/lowering/lower-timers.ts b/packages/compiler/src/frontend/lowering/lower-timers.ts index 03c9c5c1f..7d4bba34b 100644 --- a/packages/compiler/src/frontend/lowering/lower-timers.ts +++ b/packages/compiler/src/frontend/lowering/lower-timers.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { dynUndefinedExpr, numLit, varRef } from "../../ir/build.js"; import * as ts from "../ts7/adapter.js"; import { isJsSourceFile } from "../program.js"; @@ -56,7 +55,7 @@ export function adaptZeroArgTimerCallback( const toT: IrType = { kind: "func", params: [], ret: VOID }; const key = `timer.dropret:${typeKey(fromT)}`; const existing = lowerer.arrHofHelpers.get(key); - const name = existing ?? keyedHelperName(lowerer, "%timer.dropret", key); + const name = existing ?? `%timer.dropret.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, name); lowerer.liftedFns.push( @@ -118,7 +117,7 @@ export function adaptZeroArgTimerCallback( const toT: IrType = { kind: "func", params: [], ret: VOID }; const key = `timer.droparg:${typeKey(fromT)}`; const existing = lowerer.arrHofHelpers.get(key); - const name = existing ?? keyedHelperName(lowerer, "%timer.droparg", key); + const name = existing ?? `%timer.droparg.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, name); lowerer.liftedFns.push( @@ -204,7 +203,7 @@ function makeTimerArgsThunk( const toT: IrType = { kind: "func", params: [], ret: VOID }; const key = `timer.argsthunk:${n}`; const existing = lowerer.arrHofHelpers.get(key); - const name = existing ?? keyedHelperName(lowerer, "%timer.argsthunk", key); + const name = existing ?? `%timer.argsthunk.${lowerer.arrHofHelpers.size}`; if (!existing) { lowerer.arrHofHelpers.set(key, name); const impl = `${name}.impl`; diff --git a/packages/compiler/src/frontend/lowering/lowerer.test.ts b/packages/compiler/src/frontend/lowering/lowerer.test.ts index 7fbb9661f..bacdc7941 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.test.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.test.ts @@ -10,7 +10,6 @@ import { } from "../../ir/ir.js"; import type { Node, Program, SourceFile, Symbol, Type } from "../ts7/adapter.js"; import { Lowerer } from "./lowerer.js"; -import { UnionRegistry } from "../type-mapper.js"; import { classMethodValue } from "./class-method-values.js"; const loc = { file: "island.ts", start: 0, end: 1 }; @@ -33,7 +32,7 @@ test("reuses complete copy routes without repeating discriminator planning", () expect(plan).not.toHaveBeenCalled(); expect(lowerer.liftedFns.filter((fn) => fn.name === helper)).toHaveLength(1); const recursive = {} as Type; - lowerer.shapes.recursiveRef(recursive, () => "Recursive"); + lowerer.shapes.recursiveRef(recursive); lowerer.shapes.finalizeRecursive(recursive, [{ name: "kind", type: STRING }]); expect(lowerer.unionRetagHelper(from, to, loc)).toBe(helper); expect(plan).toHaveBeenCalled(); @@ -55,7 +54,7 @@ test("replans after a recursive union gains its final arms", () => { const lowerer = context(); const recursive = {} as Type; const from = lowerer.unions.intern([UNDEFINED_T, NULL_T]); - const to = lowerer.unions.recursiveRef(recursive, () => "Recursive"); + const to = lowerer.unions.recursiveRef(recursive); const trapped = lowerer.unionRetagHelper(from, to, loc); expect(trapped).not.toBeNull(); lowerer.unions.finalizeRecursive(recursive, [UNDEFINED_T]); @@ -76,7 +75,7 @@ test("rechecks width conversions after recursive record definitions settle", () const lowerer = context(); const recursive = {} as Type; const source = record(lowerer.shapes.intern([{ name: "value", type: F64 }])); - const target = record(lowerer.shapes.recursiveRef(recursive, () => "Recursive")); + const target = record(lowerer.shapes.recursiveRef(recursive)); const from = lowerer.unions.intern([source, UNDEFINED_T]); const to = lowerer.unions.intern([target, NULL_T]); expect(lowerer.unionRetagHelper(from, to, loc)).not.toBeNull(); @@ -130,7 +129,7 @@ test("literal ownership is reused across values and rechecked when recursive rec expect(inspect).not.toHaveBeenCalled(); const recursive = {} as Type; - const pendingShape = record(lowerer.shapes.recursiveRef(recursive, () => "Recursive")); + const pendingShape = record(lowerer.shapes.recursiveRef(recursive)); const pending = lowerer.unions.intern([pendingShape], { field: "kind", cases: [{ tag: 0, values: ["a"] }], @@ -144,7 +143,7 @@ test("literal ownership is reused across values and rechecked when recursive rec test("literal ownership sees a recursive union's finalized discriminator", () => { const lowerer = context(); const recursive = {} as Type; - const union = lowerer.unions.recursiveRef(recursive, () => "Recursive"); + const union = lowerer.unions.recursiveRef(recursive); const shape = record(lowerer.shapes.intern([{ name: "kind", type: STRING }])); expect(lowerer.literalUnionArm(union, ["ready"])).toBeNull(); lowerer.unions.finalizeRecursive(recursive, [shape], { @@ -183,10 +182,7 @@ test("removing undefined reuses the discriminator transformation without hiding ); const recursive = {} as Type; - const pending: IrType = { - kind: "union", - unionId: lowerer.unions.recursiveRef(recursive, () => "Recursive"), - }; + const pending: IrType = { kind: "union", unionId: lowerer.unions.recursiveRef(recursive) }; expect(lowerer.stripUndefinedArm(pending)).toEqual(pending); lowerer.unions.finalizeRecursive(recursive, [STRING, UNDEFINED_T]); expect(lowerer.stripUndefinedArm(pending)).toEqual(STRING); @@ -219,10 +215,7 @@ test("adding undefined reuses semantic union transformations and sees recursive expect(lowerer.unions.get(added.unionId)?.discriminant).toEqual(discriminant); const recursive = {} as Type; - const pending: IrType = { - kind: "union", - unionId: lowerer.unions.recursiveRef(recursive, () => "Recursive"), - }; + const pending: IrType = { kind: "union", unionId: lowerer.unions.recursiveRef(recursive) }; const before = lowerer.withUndefinedArmOf(pending); lowerer.unions.finalizeRecursive(recursive, [a, b], discriminant); expect(lowerer.withUndefinedArmOf(pending)).toEqual(added); @@ -234,18 +227,13 @@ test("adding undefined reuses semantic union transformations and sees recursive test("optional union widening keeps refused and missing contracts current", () => { const lowerer = context(); const recursive = {} as Type; - const pending: IrType = { - kind: "union", - unionId: lowerer.unions.recursiveRef(recursive, () => "Recursive"), - }; + const pending: IrType = { kind: "union", unionId: lowerer.unions.recursiveRef(recursive) }; expect(lowerer.withUndefinedArmOf(pending)).not.toBeNull(); lowerer.unions.finalizeRecursive(recursive, [{ kind: "date" }, STRING]); expect(lowerer.withUndefinedArmOf(pending)).toBeNull(); expect(lowerer.withUndefinedArmOf(pending)).toBeNull(); - // Union ids come from their arms, so a fresh registry names the union - // this one has not interned yet. - const missing: IrType = { kind: "union", unionId: new UnionRegistry().intern([F64, STRING]) }; + const missing: IrType = { kind: "union", unionId: `u${lowerer.unions.unions.length}` }; expect(lowerer.withUndefinedArmOf(missing)).toBeNull(); expect(lowerer.unions.intern([F64, STRING])).toBe(missing.unionId); expect(lowerer.withUndefinedArmOf(missing)?.kind).toBe("union"); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 3f8a0a66e..ee8ba7ecb 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1,6 +1,4 @@ import { relieveHeapPressure } from "../../heap-pressure.js"; -import { keyedHelperName } from "./stable-names.js"; -import { positionTag, StructuralPositions } from "./structural-positions.js"; import { onlyForwarded, stripTypeWrappers } from "./typed-arguments.js"; import { needsGeneralNodeStreams, @@ -1006,11 +1004,6 @@ function lowerShuffle(): ((wave: string[]) => void) | null { * the bodies reachable emit did NOT mark (plus deferred collection * diagnostics nothing flushed), reported separately: whole-program analysis without * letting unreached code fail builds. */ -/** The closure root of an emit-override specialization body. */ -function emitSpecRoot(spec: EmitSpecRequest): string { - return `%emit.${spec.info.def.name}.${spec.event}.${spec.ordinal}`; -} - export function lowerToIr( program: ts.Program, entry: ts.SourceFile, @@ -2808,8 +2801,6 @@ export class Lowerer { /** Generated value helpers, keyed by operation and type. Callers own * their key prefixes; this includes more than structural conversions. */ readonly valueHelpers = new Map(); - /** Each name keyedHelperName made, with a second hash of its key. */ - readonly keyedNameKeys = new Map(); /** structuralNarrowing's assignable classes, keyed by static and * narrowed class name. */ readonly structuralClassPeers = new Map(); @@ -2946,6 +2937,7 @@ export class Lowerer { ctx: FnCtx; } >(); + chainCounter = 0; /** Keyed by program-wide qualified class name (what IR object types carry). */ readonly classes = new Map(); readonly classBySymbol = new Map(); @@ -3175,47 +3167,7 @@ export class Lowerer { * dispatch revision needs no weak-key identity or process-global state. */ errorMethodDispatchRevision: string | null = null; errorPropertyDispatchRevision: string | null = null; - /** Structural source positions (structural-positions.ts) for names that - * stay the same when unrelated code moves. */ - readonly positions = new StructuralPositions(); - - /** The outermost node whose token span is exactly `loc`, or null. */ - nodeAtLoc(loc: SrcLoc): ts.Node | null { - const sf = this.program.getSourceFile(loc.file); - return sf === undefined ? null : (ts.nodeAtSpan(sf, loc.start, loc.end) ?? null); - } - - /** The lowering unit whose name scopes the closures it lifts. */ - private closureRoot = "%pre"; - private readonly closureNameCounts = new Map(); - - /** Runs `fn` with the closures it lifts named under `root`. */ - withClosureRoot(root: string, fn: () => T): T { - const previous = this.closureRoot; - this.closureRoot = root; - try { - return fn(); - } finally { - this.closureRoot = previous; - } - } - - /** The name of a closure (or wrapper) lifted for the source at `loc`: - * `.` of the current lowering unit, the location and - * `suffix`, then `suffix`. A unit that lifts several functions for the same - * location and suffix numbers them in the order it lifts them, so a - * closure's name depends only on its unit, not on which units lowered - * before it. */ - closureName(loc: SrcLoc, suffix = "", prefix = "%fn"): string { - const node = this.nodeAtLoc(loc); - const where = node === null ? `${loc.file}:${loc.start}:${loc.end}` : this.positions.of(node); - const key = `${prefix}|${this.closureRoot}|${where}|${suffix}`; - const first = keyedHelperName(this, prefix, key); - const seen = this.closureNameCounts.get(first) ?? 0; - this.closureNameCounts.set(first, seen + 1); - return (seen === 0 ? first : keyedHelperName(this, prefix, `${key}|${seen}`)) + suffix; - } - + lambdaCounter = 0; readonly preparedClassFactories = new Map(); readonly preparingClassFactories = new Set(); @@ -3568,7 +3520,6 @@ export class Lowerer { this.checker = program.getTypeChecker(); this.typeCtx = { checker: this.checker, - positionOf: (node) => this.positions.of(node), shapes: this.shapes, unions: this.unions, classNamer: this.classNamer, @@ -3857,11 +3808,11 @@ export class Lowerer { })() ? this.qualify( ts.getSourceFileOfNode(decl), - `%cx${positionTag(this, decl)}.${decl.name?.text ?? ""}`, + `%cx${ts.tokenStartOfNode(decl)}.${decl.name?.text ?? ""}`, ) : this.qualify( ts.getSourceFileOfNode(decl), - nsPathPrefix(this, decl) + (decl.name ? decl.name.text : "%anon"), + nsPathPrefix(decl) + (decl.name ? decl.name.text : "%anon"), ); for (let index = this.localClassInstantiations.length - 1; index >= 0; index--) { const entry = this.localClassInstantiations[index]!; @@ -7420,10 +7371,7 @@ export class Lowerer { } for (const decl of fp.classDecls) { const info = this.classes.get(this.classNamer(decl)); - if (info) - functions.push( - ...this.withClosureRoot(info.def.name, () => this.lowerClassMembers(info)), - ); + if (info) functions.push(...this.lowerClassMembers(info)); else if (this.countsSkips()) this.countSkippedBody(decl); } } @@ -7436,10 +7384,7 @@ export class Lowerer { // are reachable by definition, already counted by reachable emit. if (!this.remainder) { for (const fp of parts) { - const initName = this.initNameOf.get(fp.sf)!; - functions.push( - this.withClosureRoot(initName, () => this.lowerFileInit(fp.sf, fp.topStmts, initName)), - ); + functions.push(this.lowerFileInit(fp.sf, fp.topStmts, this.initNameOf.get(fp.sf)!)); } functions.push(this.buildMain()); } @@ -7481,9 +7426,7 @@ export class Lowerer { // default): the diagnostic is recorded — the instance skips // like a signature-blocked function (lowerFunction's rule). try { - functions.push( - this.withClosureRoot(inst.name, () => this.lowerGenericInstance(info, inst)), - ); + functions.push(this.lowerGenericInstance(info, inst)); } catch (e) { if (!(e instanceof PoisonError)) throw e; } @@ -7493,10 +7436,7 @@ export class Lowerer { // instances of its own; the joint fixpoint covers both). while (es < this.emitSpecQueue.length) { try { - const spec = this.emitSpecQueue[es++]!; - const fn = this.withClosureRoot(emitSpecRoot(spec), () => - lowerEmitOverrideSpec(this, spec), - ); + const fn = lowerEmitOverrideSpec(this, this.emitSpecQueue[es++]!); if (fn) functions.push(fn); } catch (e) { if (!(e instanceof PoisonError)) throw e; @@ -8050,9 +7990,7 @@ export class Lowerer { this.genericClassDemandPriority.set(info, ref); instanceFunctions.push( ...this.withGenericDemandOwner(owner, () => - this.shapes.withDeclaredOrderPriority(ref, () => - this.withClosureRoot(info.def.name, () => this.lowerClassMembers(info)), - ), + this.shapes.withDeclaredOrderPriority(ref, () => this.lowerClassMembers(info)), ), ); relieveHeapPressure(); @@ -8079,7 +8017,7 @@ export class Lowerer { instanceFunctions.push( this.withGenericDemandOwner(owner, () => this.shapes.withDeclaredOrderPriority(ref, () => - this.withClosureRoot(inst.name, () => this.lowerGenericInstance(info, inst)), + this.lowerGenericInstance(info, inst), ), ), ); @@ -8112,12 +8050,9 @@ export class Lowerer { ); while (specLowered < waveEnd) { try { - const fn = this.shapes.withDeclaredOrderPriority([4, instanceMetadataOrder++], () => { - const spec = this.emitSpecQueue[specLowered++]!; - return this.withClosureRoot(emitSpecRoot(spec), () => - lowerEmitOverrideSpec(this, spec), - ); - }); + const fn = this.shapes.withDeclaredOrderPriority([4, instanceMetadataOrder++], () => + lowerEmitOverrideSpec(this, this.emitSpecQueue[specLowered++]!), + ); if (fn) instanceFunctions.push(fn); } catch (e) { if (!(e instanceof PoisonError)) throw e; @@ -8145,9 +8080,7 @@ export class Lowerer { initFunctions.push( this.withGenericDemandOwner(owner, () => this.shapes.withDeclaredOrderPriority(priority, () => - this.withClosureRoot(this.initNameOf.get(fp.sf)!, () => - this.lowerFileInit(fp.sf, fp.topStmts, this.initNameOf.get(fp.sf)!), - ), + this.lowerFileInit(fp.sf, fp.topStmts, this.initNameOf.get(fp.sf)!), ), ), ); @@ -8173,9 +8106,7 @@ export class Lowerer { const priority = metadataPriority.get(name) ?? [3, expressionMetadataOrder++]; const owner = demandOwner(priority); const fn = this.withGenericDemandOwner(owner, () => - this.shapes.withDeclaredOrderPriority(priority, () => - this.withClosureRoot(name, unit.lower), - ), + this.shapes.withDeclaredOrderPriority(priority, unit.lower), ); if (fn) loweredUnits.set(name, fn); relieveHeapPressure(); @@ -13558,7 +13489,7 @@ export class Lowerer { const key = `${fn.valueFn ?? fn.fn}:${typeKey(funcType)}:${adapterShape}`; let fnName = this.builtinCallableValueFns.get(key); if (!fnName) { - fnName = keyedHelperName(this, `%builtin.value.${fn.valueFn ?? fn.fn}`, key); + fnName = `%builtin.value.${fn.valueFn ?? fn.fn}.${this.builtinCallableValueFns.size}`; this.builtinCallableValueFns.set(key, fnName); this.builtinCallableValueNames.set(fnName, display.slice(display.lastIndexOf(".") + 1)); const params = funcType.params.map((type, index) => ({ diff --git a/packages/compiler/src/frontend/lowering/native-ffi.ts b/packages/compiler/src/frontend/lowering/native-ffi.ts index 62f2be9f1..0f932ba93 100644 --- a/packages/compiler/src/frontend/lowering/native-ffi.ts +++ b/packages/compiler/src/frontend/lowering/native-ffi.ts @@ -562,7 +562,7 @@ export function lowerFfiMemoryModule(lowerer: Lowerer, loc: SrcLoc): IrExpr { const entries = lowerer.ffiImports .filter((entry) => entry.library !== undefined) .map((entry) => { - const name = lowerer.closureName(loc, "", "%ffi.module"); + const name = `%ffi.module.${lowerer.lambdaCounter++}`; const sourceTypes = ffiSourceParamTypes(entry.params); const locals: IrLocal[] = sourceTypes.map((_, i) => ({ id: `%arg${i}`, diff --git a/packages/compiler/src/frontend/lowering/object-enumeration-receiver.ts b/packages/compiler/src/frontend/lowering/object-enumeration-receiver.ts index 388ac3904..855da3bda 100644 --- a/packages/compiler/src/frontend/lowering/object-enumeration-receiver.ts +++ b/packages/compiler/src/frontend/lowering/object-enumeration-receiver.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { BOOL, STRING, @@ -28,7 +27,7 @@ export function objectEnumerationReceiver( const key = `obj.receiver:${source.unionId}:${expected.shapeId}`; let name = lowerer.arrHofHelpers.get(key); if (name === undefined) { - name = keyedHelperName(lowerer, "%obj.receiver", key); + name = `%obj.receiver.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const value = varRef("value.0", source, loc); lowerer.liftedFns.push({ diff --git a/packages/compiler/src/frontend/lowering/pairs-snapshot.ts b/packages/compiler/src/frontend/lowering/pairs-snapshot.ts index acf7b3bf9..3b33fb0cd 100644 --- a/packages/compiler/src/frontend/lowering/pairs-snapshot.ts +++ b/packages/compiler/src/frontend/lowering/pairs-snapshot.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { arrayOf, BOOL, @@ -50,7 +49,7 @@ export function pairsSnapshotHelper( const key = `${options.keyPrefix}.snapshot:${shapeId}`; const existing = lowerer.valueHelpers.get(key); if (existing) return existing; - const name = keyedHelperName(lowerer, `%${options.keyPrefix}.snapshot`, key); + const name = `%${options.keyPrefix}.snapshot.${lowerer.valueHelpers.size}`; lowerer.valueHelpers.set(key, name); const recordType: IrType = { kind: "record", shapeId }; const pairsType = arrayOf(STRING); diff --git a/packages/compiler/src/frontend/lowering/promise-executor-adapter.ts b/packages/compiler/src/frontend/lowering/promise-executor-adapter.ts index 84aa8dac0..09d228b05 100644 --- a/packages/compiler/src/frontend/lowering/promise-executor-adapter.ts +++ b/packages/compiler/src/frontend/lowering/promise-executor-adapter.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { varRef } from "../../ir/build.js"; import { type IrExpr, @@ -41,7 +40,7 @@ export function adaptPromiseExecutor( const key = `promise.executor:${typeKey(execT)}:${typeKey(inner)}`; let name = lowerer.arrHofHelpers.get(key); if (name === undefined) { - name = keyedHelperName(lowerer, "%promise.executor", key); + name = `%promise.executor.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, name); const impl = `${name}.impl`; const captured: IrLocal = { id: "f.0", name: "f", type: execT, mutable: false, boxed: true }; diff --git a/packages/compiler/src/frontend/lowering/require-initialization.ts b/packages/compiler/src/frontend/lowering/require-initialization.ts index c8fc9c730..d979423b0 100644 --- a/packages/compiler/src/frontend/lowering/require-initialization.ts +++ b/packages/compiler/src/frontend/lowering/require-initialization.ts @@ -9,7 +9,6 @@ * and every reference that can run earlier checks it first — the same * module.tdzCheck the import-cycle bindings use. A reference whose lowering * leaves no expression to check keeps the SC1013 fence. */ -import { positionTag } from "./structural-positions.js"; import * as ts from "../ts7/adapter.js"; import type { Lowerer } from "./lowerer.js"; import { @@ -120,7 +119,7 @@ export function markRequireEarlyBindings(lowerer: Lowerer): void { const tag = rawTag === "" ? "e." : rawTag.replace(/^%/, ""); const bySymbol = new Map(); for (const { decl } of declared) { - const flagId = `%g.${tag}%required.${positionTag(lowerer, decl)}`; + const flagId = `%g.${tag}%required.${ts.tokenStartOfNode(decl)}`; lowerer.globalsList.push({ id: flagId, name: "%initialized", type: BOOL, mutable: true }); const flag: RequireInitFlag = { flagId, names: new Map() }; for (const id of boundNames(decl.name)) { diff --git a/packages/compiler/src/frontend/lowering/stable-names.ts b/packages/compiler/src/frontend/lowering/stable-names.ts deleted file mode 100644 index 8f7d0967e..000000000 --- a/packages/compiler/src/frontend/lowering/stable-names.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { InternalCompilerError } from "../../errors.js"; - -/** The owner of the names keyedHelperName hands out. */ -export interface KeyedNameOwner { - /** Each keyed name with a second hash of the key it was made from, which - * tells a repeated key from a different key with the same name. */ - readonly keyedNameKeys: Map; -} - -/** 48 bits of two FNV-1a hashes of `key`, as 12 hex digits. */ -function keyHash(key: string): string { - let a = 0x811c9dc5; - let b = 0x01000193 ^ 0x5bd1e995; - for (let i = 0; i < key.length; i++) { - const c = key.charCodeAt(i); - a = Math.imul(a ^ c, 0x01000193); - b = Math.imul(b ^ c, 0x01000193) ^ (b >>> 13); - } - const high = (b >>> 0).toString(16).padStart(8, "0").slice(4); - return high + (a >>> 0).toString(16).padStart(8, "0"); -} - -/** A 32-bit hash of `key` independent of keyHash's bits. */ -function checkHash(key: string): number { - let h = 0x9e3779b9; - for (let i = 0; i < key.length; i++) - h = Math.imul(h ^ key.charCodeAt(i), 0x85ebca6b) ^ (h >>> 15); - return h >>> 0; -} - -/** The name of a helper interned by `key`: ``. It depends only on the key, not on how many helpers were interned - * before, so a helper has the same name whichever unit first needs it. Two - * keys that hash to the same name throw an InternalCompilerError. */ -export function keyedHelperName( - owner: KeyedNameOwner, - prefix: string, - key: string, - separator = ".", -): string { - const name = `${prefix}${separator}${keyHash(key)}`; - const check = checkHash(key); - const previous = owner.keyedNameKeys.get(name); - if (previous === undefined) owner.keyedNameKeys.set(name, check); - else if (previous !== check) - throw new InternalCompilerError(`helper name ${name} is shared by two helper keys`); - return name; -} diff --git a/packages/compiler/src/frontend/lowering/strict-equality.ts b/packages/compiler/src/frontend/lowering/strict-equality.ts index 8a87c8111..7b9b6902b 100644 --- a/packages/compiler/src/frontend/lowering/strict-equality.ts +++ b/packages/compiler/src/frontend/lowering/strict-equality.ts @@ -1,4 +1,3 @@ -import { keyedHelperName } from "./stable-names.js"; import { boolLit, varRef } from "../../ir/build.js"; import { BOOL, @@ -136,7 +135,7 @@ export function lowerUnionEquality( loc, ); if (!result) return null; - name = keyedHelperName(lowerer, "%value.eq", key); + name = `%value.eq.${lowerer.equalityHelpers.size}`; lowerer.equalityHelpers.set(key, name); lowerer.liftedFns.push({ name, diff --git a/packages/compiler/src/frontend/lowering/structural-positions.ts b/packages/compiler/src/frontend/lowering/structural-positions.ts deleted file mode 100644 index ea8535d9e..000000000 --- a/packages/compiler/src/frontend/lowering/structural-positions.ts +++ /dev/null @@ -1,107 +0,0 @@ -import * as ts from "../ts7/adapter.js"; -import { keyedHelperName, type KeyedNameOwner } from "./stable-names.js"; - -/** The declaration kinds whose names anchor the positions inside them. */ -const ANCHOR_KINDS: ReadonlySet = new Set([ - ts.SyntaxKind.FunctionDeclaration, - ts.SyntaxKind.ClassDeclaration, - ts.SyntaxKind.ClassExpression, - ts.SyntaxKind.VariableDeclaration, - ts.SyntaxKind.MethodDeclaration, - ts.SyntaxKind.GetAccessor, - ts.SyntaxKind.SetAccessor, - ts.SyntaxKind.PropertyDeclaration, - ts.SyntaxKind.PropertyAssignment, - ts.SyntaxKind.ModuleDeclaration, - ts.SyntaxKind.EnumDeclaration, - ts.SyntaxKind.Constructor, - ts.SyntaxKind.InterfaceDeclaration, - ts.SyntaxKind.TypeAliasDeclaration, -]); - -/** The name of `node` when it is a named declaration that anchors the - * positions of the nodes inside it, or null. */ -function anchorName(node: ts.Node): string | null { - return ts.declarationNameAt(node, node.index, ANCHOR_KINDS); -} - -/** The nearest enclosing anchor of `node` (not `node` itself), or its - * source file. */ -function anchorOf(node: ts.Node): ts.Node { - for (let parent = node.parent; parent !== undefined; parent = parent.parent) { - if (ts.isSourceFile(parent) || anchorName(parent) !== null) return parent; - } - return ts.getSourceFileOfNode(node); -} - -/** Source positions that stay the same when code outside the enclosing - * declaration changes. A node's structural position is its file, the chain - * of enclosing named declarations (each with its kind, its name and its - * ordinal among the declarations of the same kind and name in its own - * anchor), and its ordinal among the nodes of its kind whose nearest anchor - * is the same declaration. Editing another declaration, or code nested in another - * named declaration of the same anchor, leaves the position unchanged. */ -export class StructuralPositions { - /** Per anchor and key: the indices of the nodes with that key whose - * nearest anchor it is, in preorder (anchoredNodes). */ - private readonly nodesByKey = new Map>(); - private readonly paths = new Map(); - - /** The ordinal of `node` among the nodes of `anchor` with its key. */ - private ordinalIn(anchor: ts.Node, node: ts.Node, key: string): number { - let byKey = this.nodesByKey.get(anchor); - if (byKey === undefined) this.nodesByKey.set(anchor, (byKey = new Map())); - let indices = byKey.get(key); - if (indices === undefined) { - indices = ts.anchoredNodes(anchor, key, ANCHOR_KINDS); - byKey.set(key, indices); - } - // Indices increase in preorder. - let low = 0; - let high = indices.length - 1; - while (low <= high) { - const middle = (low + high) >> 1; - const at = indices[middle]!; - if (at === node.index) return middle; - if (at < node.index) low = middle + 1; - else high = middle - 1; - } - return -1; - } - - /** The anchor chain of `anchor` from the file down. */ - private pathOf(anchor: ts.Node): string { - const cached = this.paths.get(anchor); - if (cached !== undefined) return cached; - let path: string; - if (ts.isSourceFile(anchor)) path = anchor.fileName; - else { - const parent = anchorOf(anchor); - // The kind keeps declarations of one name apart: a getter and its - // setter, or a class and the namespace merged with it. - const key = `${anchor.kind}:${anchorName(anchor)}`; - path = `${this.pathOf(parent)}/${key}#${this.ordinalIn(parent, anchor, key)}`; - } - this.paths.set(anchor, path); - return path; - } - - /** The structural position of `node`. */ - of(node: ts.Node): string { - const anchor = anchorOf(node); - const name = anchorName(node); - const key = name === null ? `${node.kind}` : `${node.kind}:${name}`; - return `${this.pathOf(anchor)}|${key}#${this.ordinalIn(anchor, node, key)}`; - } -} - -/** The owner of structural positions and the names made from them. */ -export interface PositionTagOwner extends KeyedNameOwner { - readonly positions: StructuralPositions; -} - -/** A short tag for `node`'s structural position, for names that must stay - * unique per source node (class expressions, namespace blocks). */ -export function positionTag(owner: PositionTagOwner, node: ts.Node): string { - return keyedHelperName(owner, "", owner.positions.of(node), ""); -} diff --git a/packages/compiler/src/frontend/ts7/ast.ts b/packages/compiler/src/frontend/ts7/ast.ts index 0bddd1a80..369213d89 100644 --- a/packages/compiler/src/frontend/ts7/ast.ts +++ b/packages/compiler/src/frontend/ts7/ast.ts @@ -47,9 +47,8 @@ import { } from "./ast-guards.generated.js"; import type { Ts7DiagnosticData as Diagnostic } from "./session-schema.generated.js"; import { ModifierFlags, SyntaxKind } from "./enums.js"; -import { AstKind, KIND_NODE_LIST } from "./ast-schema.generated.js"; +import { AstKind } from "./ast-schema.generated.js"; import { PREORDER_LIST } from "./ast-wire.js"; -import { tokenStartOfNode } from "./node-functions.js"; /* ---- everything 7 kept under the same name ---- */ @@ -197,93 +196,6 @@ function walkLinkedPreorder( } } -/** The semantic children of a wire node: list items stand in for their - * list, and attached JSDoc trees are left out (the walkPreorder view). */ -function semanticChildIndices(root: Node, index: number, out: number[]): void { - const wire = root.file.wire; - for (let child = wire.firstChild(index); child !== 0; child = wire.next(child)) { - const kind = wire.kind(child); - if (kind === KIND_NODE_LIST) { - for (let item = wire.firstChild(child); item !== 0; item = wire.next(item)) out.push(item); - } else if (kind !== AstKind.JSDoc) out.push(child); - } -} - -/** The outermost node of `sourceFile` whose token span is exactly - * [start, end), or undefined. Only nodes ending at `end` are - * materialized. */ -export function nodeAtSpan(sourceFile: SourceFile, start: number, end: number): Node | undefined { - const wire = sourceFile.file.wire; - const children: number[] = []; - let index = sourceFile.index; - for (;;) { - children.length = 0; - semanticChildIndices(sourceFile, index, children); - let next = 0; - for (const child of children) { - if (wire.pos(child) > start || wire.end(child) < end) continue; - if (wire.end(child) === end) { - const node = sourceFile.file.node(child); - if (tokenStartOfNode(node) === start) return node; - } - next = child; - break; - } - if (next === 0) return undefined; - index = next; - } -} - -/** The name of the declaration at wire `index` in `root`'s file when its - * kind is in `kinds`: its identifier, private identifier or string literal - * name, "constructor" for a constructor, or null. Reads the wire without - * materializing nodes. */ -export function declarationNameAt( - root: Node, - index: number, - kinds: ReadonlySet, -): string | null { - const wire = root.file.wire; - const kind = wire.kind(index); - if (!kinds.has(kind)) return null; - if (kind === SyntaxKind.Constructor) return "constructor"; - const name = wire.namedChild(index, "name"); - if (name === 0) return null; - const nameKind = wire.kind(name); - if ( - nameKind !== SyntaxKind.Identifier && - nameKind !== SyntaxKind.PrivateIdentifier && - nameKind !== SyntaxKind.StringLiteral - ) - return null; - return wire.text(name) ?? null; -} - -/** The indices, in preorder, of the nodes below `root` that have `key` and - * are not inside a nested named declaration (declarationNameAt with - * `kinds`). A named declaration is keyed `:` and its subtree is - * not visited; other nodes are keyed by their kind. No node is - * materialized. */ -export function anchoredNodes(root: Node, key: string, kinds: ReadonlySet): number[] { - const wire = root.file.wire; - const out: number[] = []; - const children: number[] = []; - const stack: number[] = []; - semanticChildIndices(root, root.index, children); - for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]!); - while (stack.length > 0) { - const index = stack.pop()!; - const kind = wire.kind(index); - const name = declarationNameAt(root, index, kinds); - if ((name === null ? String(kind) : `${kind}:${name}`) === key) out.push(index); - if (name !== null) continue; - children.length = 0; - semanticChildIndices(root, index, children); - for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]!); - } - return out; -} - export function getLineAndCharacterOfPosition( sourceFile: SourceFile, position: number, diff --git a/packages/compiler/src/frontend/type-mapper.test.ts b/packages/compiler/src/frontend/type-mapper.test.ts index 163ba7b9e..cf78554b4 100644 --- a/packages/compiler/src/frontend/type-mapper.test.ts +++ b/packages/compiler/src/frontend/type-mapper.test.ts @@ -41,7 +41,7 @@ describe("union arm lookup", () => { test("sees finalized recursive arms after a missing lookup", () => { const unions = new UnionRegistry(); const recursive = {} as Type; - const union = unions.recursiveRef(recursive, () => "Recursive"); + const union = unions.recursiveRef(recursive); expect(unions.armTag(union, STRING)).toBe(-1); unions.finalizeRecursive(recursive, [ F64, diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 79091cadc..a233f0186 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -1,5 +1,4 @@ import { InternalCompilerError } from "../errors.js"; -import { keyedHelperName, type KeyedNameOwner } from "./lowering/stable-names.js"; import { mockCallRecordType, mockContextType } from "./mock-shapes.js"; import * as ts from "./ts7/adapter.js"; import { bodyReadsArguments } from "./arguments-usage.js"; @@ -253,8 +252,6 @@ function comparePriority(left: DeclaredOrderPriority, right: DeclaredOrderPriori export class ShapeRegistry { /** Existing layouts change only when a recursive placeholder closes. */ revision = 0; - /** Each shape id with a second hash of its key (keyedHelperName). */ - readonly keyedNameKeys = new Map(); private readonly byKey = new Map(); private readonly byId = new Map(); /** Historical emit-order rank of the declaration-order metadata each @@ -273,7 +270,7 @@ export class ShapeRegistry { * writer after all priority candidates have closed. */ private readonly derivedDeclaredOrderFinalizers: (() => void)[] = []; private currentDeclaredOrderPriority: DeclaredOrderPriority = [0, 0]; - /** All interned shapes in first-seen order. */ + /** All interned shapes in first-seen (`r0`, `r1`, ...) order. */ readonly shapes: IrRecordShape[] = []; /** ts.Types currently being mapped — a BACK-REFERENCE to one of these is * the recursive knot (`interface TreeNode { children: TreeNode[] }`): @@ -393,12 +390,11 @@ export class ShapeRegistry { /** The shape id a back-reference to an in-progress type resolves to: * reuses the type's persistent recursive id or mints a PLACEHOLDER - * entry (empty fields) the outer frame finalizes. `describe` names a new - * placeholder (recursiveTypeName). */ - recursiveRef(t: ts.Type, describe: () => string): string { + * entry (empty fields) the outer frame finalizes. */ + recursiveRef(t: ts.Type): string { let id = this.recIds.get(t); if (id === undefined) { - id = recursivePlaceholderName(this, "r", describe(), (name) => this.byId.has(name)); + id = `r${this.shapes.length}`; const shape: IrRecordShape = { id, fields: [] }; this.byId.set(id, shape); this.shapes.push(shape); @@ -467,7 +463,7 @@ export class ShapeRegistry { const key = this.keyOf(fields, tuple, indexValue); let id = this.byKey.get(key); if (id === undefined) { - id = keyedHelperName(this, "r", key, ""); + id = `r${this.shapes.length}`; const shape: IrRecordShape = { id, fields, @@ -545,57 +541,6 @@ export class ShapeRegistry { } } -/** The id of a recursive placeholder described by `description`. Two - * different types can still share a description (recursiveTypeName stops - * after a few levels of type arguments); the later one takes the first free - * name with a numbered suffix. */ -function recursivePlaceholderName( - owner: KeyedNameOwner, - prefix: string, - description: string, - taken: (name: string) => boolean, -): string { - let name = keyedHelperName(owner, prefix, `recursive:${description}`, ""); - for (let n = 1; taken(name); n++) - name = keyedHelperName(owner, prefix, `recursive:${description}#${n}`, ""); - return name; -} - -/** How many levels of type arguments recursiveTypeName describes. */ -const RECURSIVE_NAME_DEPTH = 3; - -/** A recursive checker type's description, which names its placeholder - * whichever frame first reaches it: its printed form, the structural - * position of its first declaration, and the same for its type arguments - * (two instantiations print the same when their type arguments are type - * parameters or classes of the same name from different declarations). */ -function recursiveTypeName( - t: ts.Type, - ctx: Pick, - depth = 0, -): string { - const symbol = t.getAliasSymbol() ?? t.getSymbol(); - const declaration = symbol?.declarations[0]; - const where = declaration - ? (ctx.positionOf?.(declaration) ?? - `${ts.getSourceFileOfNode(declaration).fileName}:${declaration.pos}`) - : ""; - let description = `${ctx.checker.typeToString(t)}@${where}`; - if (depth < RECURSIVE_NAME_DEPTH) { - const aliasArguments = - t.getAliasSymbol() !== undefined ? (t.getAliasTypeArguments() ?? []) : []; - const typeArguments = - aliasArguments.length > 0 - ? aliasArguments - : t.isTypeReference() - ? ctx.checker.getTypeArguments(t) - : []; - if (typeArguments.length > 0) - description += `<${typeArguments.map((arg) => recursiveTypeName(arg, ctx, depth + 1)).join(",")}>`; - } - return description; -} - /** The frontend's union interner — mirrors ShapeRegistry. A union's * canonical identity includes its typeKey-sorted arms and literal * discriminator contract. An arm's index in that list IS its runtime tag. @@ -603,12 +548,10 @@ function recursiveTypeName( export class UnionRegistry { /** Existing arm/discriminator contracts change when a placeholder closes. */ revision = 0; - /** Each union id with a second hash of its key (keyedHelperName). */ - readonly keyedNameKeys = new Map(); private readonly byKey = new Map(); private readonly byId = new Map(); private readonly armTags = new Map>(); - /** All interned unions in first-seen order. */ + /** All interned unions in first-seen (`u0`, `u1`, ...) order. */ readonly unions: IrUnionDef[] = []; /** ts.Types currently being mapped — a back-reference to one is the * recursive knot passing through a union (`type Tree = Leaf | Branch` @@ -624,12 +567,11 @@ export class UnionRegistry { /** The union id a back-reference to an in-progress union resolves to: * reuses the type's persistent recursive id or mints a PLACEHOLDER - * entry (empty arms) the outer frame finalizes. `describe` names a new - * placeholder (recursiveTypeName). */ - recursiveRef(t: ts.Type, describe: () => string): string { + * entry (empty arms) the outer frame finalizes. */ + recursiveRef(t: ts.Type): string { let id = this.recIds.get(t); if (id === undefined) { - id = recursivePlaceholderName(this, "u", describe(), (name) => this.byId.has(name)); + id = `u${this.unions.length}`; const def: IrUnionDef = { id, arms: [] }; this.byId.set(id, def); this.unions.push(def); @@ -679,7 +621,7 @@ export class UnionRegistry { const key = JSON.stringify([arms.map(typeKey), discriminant]); let id = this.byKey.get(key); if (id === undefined) { - id = keyedHelperName(this, "u", key, ""); + id = `u${this.unions.length}`; const def: IrUnionDef = { id, arms, ...(discriminant ? { discriminant } : {}) }; this.byKey.set(key, id); this.byId.set(id, def); @@ -1173,10 +1115,6 @@ export interface TypeMapperCtx { * empty object type rule in the object mapping). */ emptyLiteralArm?: boolean; checker: ts.TypeChecker; - /** The structural position of a declaration (structural-positions.ts), - * which names recursive placeholders independently of where unrelated - * code sits. The Lowerer supplies it. */ - positionOf?: (node: ts.Node) => string; /** JavaScript declarations whose instance or object-literal types only * the checked-dynamic representation holds (js-dynamic-objects.ts). * Absent when the program has none: every mapping is unchanged. */ @@ -4713,10 +4651,7 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { const knownRecursive = unions.recursiveUnionFor(widened); if (knownRecursive !== undefined) return { kind: "union", unionId: knownRecursive }; if (unions.inProgress.has(widened)) { - return { - kind: "union", - unionId: unions.recursiveRef(widened, () => recursiveTypeName(widened, ctx)), - }; + return { kind: "union", unionId: unions.recursiveRef(widened) }; } unions.inProgress.add(widened); const sensitivityAtEntry = contextResolutions; @@ -7060,10 +6995,7 @@ function mapRecordType(widened: ts.Type, ctx: TypeMapperCtx): IrType | null { // frame completes (finalizeRecursive below). Backends represent records // as heap references, so the self-reference is an ordinary pointer. if (shapes.inProgress.has(widened)) { - return { - kind: "record", - shapeId: shapes.recursiveRef(widened, () => recursiveTypeName(widened, ctx)), - }; + return { kind: "record", shapeId: shapes.recursiveRef(widened) }; } shapes.inProgress.add(widened); const sensitivityAtEntry = contextResolutions; diff --git a/packages/compiler/test/array-pipeline-fusion.test.ts b/packages/compiler/test/array-pipeline-fusion.test.ts index 55cd0025e..f5d743265 100644 --- a/packages/compiler/test/array-pipeline-fusion.test.ts +++ b/packages/compiler/test/array-pipeline-fusion.test.ts @@ -26,7 +26,7 @@ function helperCalls(fn: IrFunction): string[] { everyStmtList(fn.body, { expr: (e) => { if (e.kind === "call" && e.callee.startsWith("%arr.")) - calls.push(e.callee.replace(/\.[0-9a-f]+$/, "")); + calls.push(e.callee.replace(/\.\d+$/, "")); return true; }, stmt: () => true, diff --git a/packages/compiler/test/format-float-arguments.test.ts b/packages/compiler/test/format-float-arguments.test.ts index 6ce9c4bc0..e59e023ca 100644 --- a/packages/compiler/test/format-float-arguments.test.ts +++ b/packages/compiler/test/format-float-arguments.test.ts @@ -27,7 +27,7 @@ test("util.format %f lowers a boolean argument once", async () => { const helpers = mod.functions .map((f) => f.name) .filter((name) => name.startsWith("%arr.")) - .map((name) => name.replace(/\.[0-9a-f]+$/, "")) + .map((name) => name.replace(/\.\d+$/, "")) .sort(); expect(helpers).toEqual(["%arr.every", "%arr.some"]); } finally { diff --git a/packages/compiler/test/in-runtime-key-emission.test.ts b/packages/compiler/test/in-runtime-key-emission.test.ts index 589685a7a..aebbb2ea4 100644 --- a/packages/compiler/test/in-runtime-key-emission.test.ts +++ b/packages/compiler/test/in-runtime-key-emission.test.ts @@ -55,7 +55,7 @@ const d: Record = {}; d["a"] = 1; console.log(has(d, "a"), has(d, "b")); `); - const helper = body(llvm, /sc_b?f__x25_rec_haskey_[0-9a-f]+/); + const helper = body(llvm, /sc_b?f__x25_rec_haskey_\d+/); expect(helper).toContain("@scr_map_has_str("); // Not a scan over a fresh key snapshot per probe. expect(helper).not.toContain("@scr_map_keys_js_order("); diff --git a/packages/compiler/test/stable-names.test.ts b/packages/compiler/test/stable-names.test.ts deleted file mode 100644 index 720472556..000000000 --- a/packages/compiler/test/stable-names.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import { expect, test } from "vitest"; -import { compile, deserializeModule, type IrModule } from "../src/index.js"; - -/** Lowers each source in turn as the same file, so names that include the - * file's path compare equal. */ -async function lower(...sources: string[]): Promise { - const dir = await mkdtemp(join(tmpdir(), "scriptc-stable-names-")); - try { - const entry = join(dir, "main.ts"); - const outPath = join(dir, "main.ir.json"); - const modules: IrModule[] = []; - for (const source of sources) { - await writeFile(entry, source); - const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); - if (!result.ok) - throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); - modules.push(deserializeModule(await readFile(outPath, "utf8"))); - } - return modules; - } finally { - await rm(dir, { recursive: true, force: true }); - } -} - -function names(mod: IrModule): string[] { - return [ - ...mod.records.map((record) => record.id), - ...mod.unions.map((union) => union.id), - ...mod.functions.map((fn) => fn.name), - ...mod.classes.map((cls) => cls.name), - ].sort(); -} - -const recursive = ` -type Tree = { value: number; children: Tree[]; parent: Tree | null }; -function total(tree: Tree): number { - let sum = tree.value; - for (const child of tree.children) sum += total(child); - return sum; -} -const root: Tree = { value: 1, children: [], parent: null }; -root.children.push({ value: 2, children: [], parent: root }); -console.log(total(root)); -`; - -test("recursive record and union ids do not depend on the code above the type", async () => { - const [before, after] = await lower( - recursive, - `// A comment above the type.\n\ntype Unrelated = { name: string };\n\n${recursive}`, - ); - expect(before.records.some((record) => record.fields.some((f) => f.name === "children"))).toBe( - true, - ); - expect(names(after)).toEqual(names(before)); -}); - -test("recursive instantiations that print alike get distinct placeholders", async () => { - const [mod] = await lower(` -namespace A { - export class Item { - a = 1; - } -} -namespace B { - export class Item { - b = "b"; - } -} -type Chain = { item: T; next: Chain | null }; -const first: Chain = { item: new A.Item(), next: null }; -const second: Chain = { item: new B.Item(), next: null }; -first.next = { item: new A.Item(), next: null }; -second.next = { item: new B.Item(), next: null }; -console.log(first.next.item.a, second.next.item.b); -`); - const chains = mod.records.filter((record) => record.fields.some((f) => f.name === "next")); - expect(new Set(chains.map((record) => record.id)).size).toBe(chains.length); - expect(chains.length).toBeGreaterThanOrEqual(2); -}); - -test("a getter and a setter of one name keep their local classes apart", async () => { - const [mod] = await lower(` -class Box { - private v = 0; - get value(): number { - class Local { - n(): number { - return 1; - } - } - return new Local().n() + this.v; - } - set value(x: number) { - class Local { - n(): number { - return 2; - } - } - this.v = x * new Local().n(); - } -} -const box = new Box(); -box.value = 5; -console.log(box.value); -`); - const locals = mod.classes.filter((cls) => cls.name.includes("Local")); - expect(locals).toHaveLength(2); - expect(locals[0]!.name).not.toBe(locals[1]!.name); -}); diff --git a/packages/compiler/test/type-mapper-unions.test.ts b/packages/compiler/test/type-mapper-unions.test.ts index 684960002..c714df4d7 100644 --- a/packages/compiler/test/type-mapper-unions.test.ts +++ b/packages/compiler/test/type-mapper-unions.test.ts @@ -139,8 +139,7 @@ describe("checker and synthesized optional union identity", () => { nullable.arms.filter((arm) => arm.kind !== "nullT" && arm.kind !== "undefinedT"), ), ).toBe(required.unionId); - // Cases follow the arms, which are ordered by their type keys. - expect(nullable.discriminant!.cases.map((entry) => entry.values).sort()).toEqual([ + expect(nullable.discriminant!.cases.map((entry) => entry.values)).toEqual([ ["a", "alias"], ["b"], ]);