mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-26 06:34:20 +08:00
Revert "Name lowered helpers and closures independently of lowering order"
This reverts #1750 (05e2f404d), which made main CI fail.
This commit is contained in:
+1
-1
@@ -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",
|
||||
|
||||
@@ -174,8 +174,7 @@ class ContractChecker {
|
||||
return `${owner}.${method[2]}`;
|
||||
}
|
||||
if (fn?.sourceName !== undefined && fn.sourceName !== "<anonymous>") 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(/^%/, "");
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 }));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 }];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) => ({
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
@@ -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}`,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 }];
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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<ts.Symbol, IrType>();
|
||||
@@ -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 };
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}`,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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`;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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<string, string>();
|
||||
/** Each name keyedHelperName made, with a second hash of its key. */
|
||||
readonly keyedNameKeys = new Map<string, number>();
|
||||
/** structuralNarrowing's assignable classes, keyed by static and
|
||||
* narrowed class name. */
|
||||
readonly structuralClassPeers = new Map<string, readonly string[]>();
|
||||
@@ -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<string, ClassInfo>();
|
||||
readonly classBySymbol = new Map<ts.Symbol, ClassInfo>();
|
||||
@@ -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<string, number>();
|
||||
|
||||
/** Runs `fn` with the closures it lifts named under `root`. */
|
||||
withClosureRoot<T>(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`:
|
||||
* `<prefix>.<hash>` 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<ts.ArrowFunction | ts.FunctionExpression, IrExpr>();
|
||||
readonly preparingClassFactories = new Set<ts.ArrowFunction | ts.FunctionExpression>();
|
||||
|
||||
@@ -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) => ({
|
||||
|
||||
@@ -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}`,
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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<ts.Symbol, { flag: RequireInitFlag; decl: ts.VariableDeclaration }>();
|
||||
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)) {
|
||||
|
||||
@@ -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<string, number>;
|
||||
}
|
||||
|
||||
/** 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`: `<prefix><separator><hash of
|
||||
* 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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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<number> = new Set<number>([
|
||||
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<ts.Node, Map<string, number[]>>();
|
||||
private readonly paths = new Map<ts.Node, string>();
|
||||
|
||||
/** 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), "");
|
||||
}
|
||||
@@ -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<number>,
|
||||
): 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 `<kind>:<name>` 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>): 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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<string, number>();
|
||||
private readonly byKey = new Map<string, string>();
|
||||
private readonly byId = new Map<string, IrRecordShape>();
|
||||
/** 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<TypeMapperCtx, "checker" | "positionOf">,
|
||||
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<string, number>();
|
||||
private readonly byKey = new Map<string, string>();
|
||||
private readonly byId = new Map<string, IrUnionDef>();
|
||||
private readonly armTags = new Map<string, Map<string, number[]>>();
|
||||
/** 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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -55,7 +55,7 @@ const d: Record<string, number> = {};
|
||||
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(");
|
||||
|
||||
@@ -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<IrModule[]> {
|
||||
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<T> = { item: T; next: Chain<T> | null };
|
||||
const first: Chain<A.Item> = { item: new A.Item(), next: null };
|
||||
const second: Chain<B.Item> = { 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);
|
||||
});
|
||||
@@ -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"],
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user