diff --git a/packages/compiler/src/contracts/check.ts b/packages/compiler/src/contracts/check.ts index 3c25c9b1b..5934624bf 100644 --- a/packages/compiler/src/contracts/check.ts +++ b/packages/compiler/src/contracts/check.ts @@ -889,10 +889,7 @@ class Int32Contracts { const value = s.kind === "varDecl" ? s.init : s.value; if (note && value && !int32(value)) fail(note, value, value.loc, "the value stored into"); - } else if ( - s.kind === "forOf" || - (s.kind === "tryCatch" && s.catchLocalId !== undefined) - ) { + } else if (s.kind === "forOf" || (s.kind === "tryCatch" && s.catchLocalId !== null)) { const id = s.kind === "forOf" ? s.localId : s.catchLocalId!; const note = localNote(id); if (note) diff --git a/packages/compiler/src/frontend/lowering/call-signatures.ts b/packages/compiler/src/frontend/lowering/call-signatures.ts index 9d9c9668c..55f46a7b0 100644 --- a/packages/compiler/src/frontend/lowering/call-signatures.ts +++ b/packages/compiler/src/frontend/lowering/call-signatures.ts @@ -864,9 +864,18 @@ export function lambdaSignature( // Union-inferred returns adopt too (a mixed-return body inferring a // SUB-union of the slot's union — adopting is a no-op when the two + // A synchronous object-literal method adopts its slot's return the same + // way: its slot is the property of that name on the literal's + // contextual type. + const literalMethod = + ts.isMethodDeclaration(node) && + ts.isObjectLiteralExpression(node.parent) && + !node.asteriskToken && + node.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) !== true; if ( - (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && - (!isAsyncLike || ret.kind === "promise") + ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && + (!isAsyncLike || ret.kind === "promise")) || + literalMethod ) { // The slot's signature: the contextual type stripped of its nullish // parts (an OPTIONAL callback field's context is the whole @@ -874,7 +883,10 @@ export function lambdaSignature( // declared in USER code: stdlib callback slots (flatMap's // `U | readonly U[]`, sort comparators) have intrinsic lowerings // that inspect the INFERRED type, so they must not widen. - const ctxType = lowerer.checker.getContextualType(node); + const ctxType = + literalMethod && ts.isMethodDeclaration(node) && node.parent + ? objectLiteralMethodSlot(lowerer, node, node.parent) + : lowerer.checker.getContextualType(node); const ctxSigs = ctxType ? lowerer.checker.getCallSignatures(lowerer.checker.getNonNullableType(ctxType)) : []; @@ -943,6 +955,7 @@ export function lambdaSignature( const inferredLiteral = literalSlot !== undefined && (literalType === null || literalType.kind === "dyn"); if ( + !literalMethod && !isAsyncLike && !node.type && !inferredLiteral && @@ -958,3 +971,21 @@ export function lambdaSignature( const funcType = funcTypeFromParamShapes(shapes, ret); return { shapes, funcType }; } + +/** The type of the property an object-literal method fills on the + * literal's contextual type; undefined when the literal has no contextual + * type or the method has a computed name. */ +function objectLiteralMethodSlot( + lowerer: Lowerer, + node: ts.MethodDeclaration, + literal: ts.Node, +): ts.Type | undefined { + if (!ts.isIdentifier(node.name) && !ts.isStringLiteral(node.name)) return undefined; + const literalType = lowerer.checker.getContextualType(literal); + if (!literalType) return undefined; + const property = lowerer.checker.getPropertyOfType( + lowerer.checker.getNonNullableType(literalType), + node.name.text, + ); + return property ? lowerer.checker.getTypeOfSymbol(property) : undefined; +} diff --git a/packages/compiler/src/frontend/lowering/coercions/structural-plans.ts b/packages/compiler/src/frontend/lowering/coercions/structural-plans.ts index 78c7cb73d..83798a89c 100644 --- a/packages/compiler/src/frontend/lowering/coercions/structural-plans.ts +++ b/packages/compiler/src/frontend/lowering/coercions/structural-plans.ts @@ -78,6 +78,22 @@ export function widthLiftPlan(lowerer: Lowerer, src: IrType, dst: IrType): Width }); if (absentOnly.length === 1) selected = absentOnly; } + // A record that width-lifts into several members of a discriminated + // union is converted by its discriminant's value at run time, when + // every candidate member is one of the routes. + if (selected.length > 1 && src.kind === "record" && def.discriminant) { + const shape = lowerer.shapes.get(src.shapeId); + const plan = + shape && + planRecordUnionWrap( + shape, + def, + (id) => lowerer.shapes.get(id), + (from, to) => lowerer.widthLiftPlan(from, to), + ); + if (plan && selected.every(({ tag }) => plan.routes.some((route) => route.tag === tag))) + return { how: "discriminantWrap", width: true }; + } if (selected.length !== 1) return null; return { how: "liftWrap", tag: selected[0]!.tag, arm: selected[0]!.arm }; } diff --git a/packages/compiler/src/frontend/lowering/coercions/structural.ts b/packages/compiler/src/frontend/lowering/coercions/structural.ts index 925f59d9b..5931b33a7 100644 --- a/packages/compiler/src/frontend/lowering/coercions/structural.ts +++ b/packages/compiler/src/frontend/lowering/coercions/structural.ts @@ -99,7 +99,12 @@ export function applyWidthLift( case "discriminantWrap": { if (dst.kind !== "union" || value.type.kind !== "record") throw new InternalCompilerError("lowerer bug: record discriminator lift shape"); - const helper = lowerer.recordUnionWrapHelper(value.type, dst.unionId, loc); + const helper = lowerer.recordUnionWrapHelper( + value.type, + dst.unionId, + loc, + lift.width === true, + ); if (!helper) throw new InternalCompilerError( "lowerer bug: planned record discriminator lift failed to intern", diff --git a/packages/compiler/src/frontend/lowering/coercions/unions.ts b/packages/compiler/src/frontend/lowering/coercions/unions.ts index 0356b714e..84c625c3f 100644 --- a/packages/compiler/src/frontend/lowering/coercions/unions.ts +++ b/packages/compiler/src/frontend/lowering/coercions/unions.ts @@ -265,13 +265,19 @@ export function recordUnionWrapHelper( source: IrType & { kind: "record" }, toId: string, loc: SrcLoc, + width = false, ): string | null { const shape = lowerer.shapes.get(source.shapeId); const to = lowerer.unions.get(toId); if (!shape || !to) return null; - const plan = planRecordUnionWrap(shape, to, (id) => lowerer.shapes.get(id)); + const plan = planRecordUnionWrap( + shape, + to, + (id) => lowerer.shapes.get(id), + width ? (from, dst) => lowerer.widthLiftPlan(from, dst) : undefined, + ); if (!plan) return null; - const key = `recordWrap:${source.shapeId}:${toId}`; + const key = `recordWrap${width ? "Width" : ""}:${source.shapeId}:${toId}`; const existing = lowerer.coercions.retags.get(key); if (existing) return existing; const name = `%record.wrap.${lowerer.coercions.retags.size}`; diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 9e7359a34..3c9a18713 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -9143,8 +9143,9 @@ export class Lowerer { source: IrType & { kind: "record" }, toId: string, loc: SrcLoc, + width = false, ): string | null { - return recordUnionWrapHelper(this, source, toId, loc); + return recordUnionWrapHelper(this, source, toId, loc, width); } unionRetagHelper( diff --git a/packages/compiler/src/frontend/lowering/string-index-bounds.ts b/packages/compiler/src/frontend/lowering/string-index-bounds.ts index acb41514f..32b96e63a 100644 --- a/packages/compiler/src/frontend/lowering/string-index-bounds.ts +++ b/packages/compiler/src/frontend/lowering/string-index-bounds.ts @@ -243,7 +243,8 @@ export class StringIndexBounds { /** Every write of a block-scoped local or parameter, or null for any * other binding (module imports, var, class members, ...). */ private binding(symbol: ts.Symbol): Binding | null { - if (this.bindings.has(symbol)) return this.bindings.get(symbol)!; + const cached = this.bindings.get(symbol); + if (cached !== undefined) return cached; const result = this.scanBinding(symbol); this.bindings.set(symbol, result); return result; diff --git a/packages/compiler/src/frontend/lowering/union-retag.ts b/packages/compiler/src/frontend/lowering/union-retag.ts index 8d1c61d09..82ec8226c 100644 --- a/packages/compiler/src/frontend/lowering/union-retag.ts +++ b/packages/compiler/src/frontend/lowering/union-retag.ts @@ -41,11 +41,15 @@ export interface RecordUnionWrapPlan { /** Recursive variants can retain distinct ids for the same field layout. * An independently inferred record may intern to either id, so that id - * alone cannot select its semantic destination when wrapping into a union. */ + * alone cannot select its semantic destination when wrapping into a union. + * With `widthLift`, members the record only width-lifts into are routes + * too: a record's own fields do not say which of them its discriminant + * names, so the value's discriminant selects the member at run time. */ export function planRecordUnionWrap( source: IrRecordShape, to: IrUnionDef, shapeOf: (id: string) => IrRecordShape | undefined, + widthLift?: (src: IrType, dst: IrType) => WidthLift | null, ): RecordUnionWrapPlan | null { const discriminant = to.discriminant; if (!discriminant || source.tuple || source.indexValue || shapeHasAccessorSlots(source)) @@ -57,30 +61,22 @@ export function planRecordUnionWrap( const arm = to.arms[tag]!; if (arm.kind !== "record") continue; const target = shapeOf(arm.shapeId); - if ( - !target || - target.tuple || - target.indexValue || - target.fields.length !== source.fields.length - ) - continue; - let same = true; - for (let i = 0; i < source.fields.length; i++) { + if (!target || target.tuple || target.indexValue) continue; + let same = target.fields.length === source.fields.length; + for (let i = 0; same && i < source.fields.length; i++) { const a = source.fields[i]!, b = target.fields[i]!; - if (a.name !== b.name || !typeEquals(a.type, b.type)) { - same = false; - break; - } + if (a.name !== b.name || !typeEquals(a.type, b.type)) same = false; } - if (!same) continue; + let lift: WidthLift | null = same + ? { how: arm.shapeId === source.id ? "copy" : "width" } + : null; + if (lift === null && widthLift !== undefined) + lift = widthLift({ kind: "record", shapeId: source.id }, arm); + if (lift === null) continue; const entry = discriminant.cases.find((candidate) => candidate.tag === tag); if (!entry) return null; - routes.push({ - tag, - lift: { how: arm.shapeId === source.id ? "copy" : "width" }, - values: entry.values, - }); + routes.push({ tag, lift, values: entry.values }); } if (routes.length < 2 || discriminantOwners(to, shapeOf) === null) return null; return { field: discriminant.field, fieldType, routes }; diff --git a/packages/compiler/src/frontend/lowering/width-lift.ts b/packages/compiler/src/frontend/lowering/width-lift.ts index 40c533d72..6b1ad8c84 100644 --- a/packages/compiler/src/frontend/lowering/width-lift.ts +++ b/packages/compiler/src/frontend/lowering/width-lift.ts @@ -6,7 +6,7 @@ import type { IrType } from "../../ir/ir.js"; export type WidthLift = | { how: "copy" } | { how: "wrap"; tag: number } - | { how: "discriminantWrap" } + | { how: "discriminantWrap"; width?: true } | { how: "retag" } | { how: "liftWrap"; tag: number; arm: IrType } | { how: "width" } diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index bde168c38..5270f7bb7 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -2042,7 +2042,8 @@ function stableCreateRequireBindingReason7( decl: ts.VariableDeclaration, ): string | null { const cache = program.analysis.createRequireReasons; - if (cache.has(decl)) return cache.get(decl)!; + const cached = cache.get(decl); + if (cached !== undefined) return cached; const check = (): string | null => { const stmt = decl.parent?.parent; if ( diff --git a/packages/compiler/src/frontend/ts7/program-host.ts b/packages/compiler/src/frontend/ts7/program-host.ts index 2f2fdf76b..fa1eeab8f 100644 --- a/packages/compiler/src/frontend/ts7/program-host.ts +++ b/packages/compiler/src/frontend/ts7/program-host.ts @@ -21,9 +21,13 @@ import { dirname, join, resolve } from "node:path"; import { Ts7Api } from "./api.js"; import type { Ts7TimingInfo } from "./session-timing.js"; import type { Ts7FileSystem } from "./rpc-filesystem.js"; -import type { CompilerOptions, Diagnostic } from "./semantic-types.js"; +import type { Diagnostic } from "./semantic-types.js"; import type { SourceFile } from "./ast-types.js"; -import type { Ts7SessionProject as Project, Ts7SessionSnapshot as Snapshot } from "./session.js"; +import type { + Ts7ProjectCompilerOptions, + Ts7SessionProject as Project, + Ts7SessionSnapshot as Snapshot, +} from "./session.js"; import { CheckerFacade } from "./checker.js"; import { moduleDetectionKindName, @@ -44,8 +48,9 @@ import { /** The compiler options our createProgram accepts: TS7's CompilerOptions * shape (numeric enums for target/module/moduleResolution — the enums module * generates them from the pinned SDK) with the 5.9.3 "lib.es2025.d.ts" lib - * spelling also accepted. */ -export type Ts7CompilerOptions = CompilerOptions; + * spelling also accepted, plus the project options scriptc adopts that the + * TS7 schema no longer declares (Ts7ProjectCompilerOptions). */ +export type Ts7CompilerOptions = Ts7ProjectCompilerOptions; /* tsconfig JSON wants enum NAMES; the options object carries TS7's numeric * enum values. Generated name lookups preserve the SDK's reverse mappings @@ -282,7 +287,7 @@ export class Ts7Program { private readonly configPath: string, ) {} - getCompilerOptions(): CompilerOptions { + getCompilerOptions(): Ts7CompilerOptions { return this.project.program.getCompilerOptions(); } diff --git a/packages/compiler/src/frontend/ts7/session.ts b/packages/compiler/src/frontend/ts7/session.ts index 4933da9d6..bc4c09496 100644 --- a/packages/compiler/src/frontend/ts7/session.ts +++ b/packages/compiler/src/frontend/ts7/session.ts @@ -17,6 +17,24 @@ import type { Ts7SourceMetadata, } from "./session-schema.generated.js"; +/** Project options tsgo still reports for a tsconfig but the TS 7 SDK + * schema no longer declares. scriptc adopts them (ADOPTED_OPTIONS), so the + * options a project reports are parsed with them declared: a native + * compiler keeps only declared fields when it parses the response. */ +export interface Ts7ProjectCompilerOptions extends Ts7CompilerOptionsData { + alwaysStrict?: boolean; + esModuleInterop?: boolean; + allowSyntheticDefaultImports?: boolean; +} + +interface Ts7ReportedProjectData extends Ts7ProjectData { + compilerOptions: Ts7ProjectCompilerOptions; +} + +interface Ts7ReportedSnapshotData extends Ts7SnapshotData { + projects: Ts7ReportedProjectData[]; +} + export interface Ts7FileChanges { changed?: SemanticDocument[]; created?: SemanticDocument[]; @@ -103,7 +121,7 @@ export class Ts7Session { updateSnapshot(params: Ts7Update = {}): Ts7SessionSnapshot { const paths = this.initialize(); - const data = parseSemanticJson( + const data = parseSemanticJson( this.text("updateSnapshot", JSON.stringify(params)), ); const snapshot = new Ts7SessionSnapshot(data, this, paths); @@ -159,7 +177,7 @@ export class Ts7SessionSnapshot { private disposed = false; constructor( - data: Ts7SnapshotData, + data: Ts7ReportedSnapshotData, private readonly session: Ts7Session, readonly paths: Ts7Paths, ) { @@ -188,7 +206,7 @@ export class Ts7SessionSnapshot { } getDefaultProjectForFile(file: SemanticDocument): Ts7SessionProject | undefined { this.ensureActive(); - const data = this.session.request("getDefaultProjectForFile", { + const data = this.session.request("getDefaultProjectForFile", { snapshot: this.id, file, }); @@ -214,12 +232,12 @@ export class Ts7SessionSnapshot { export class Ts7SessionProject { readonly id: string; readonly configFileName: string; - readonly compilerOptions: Ts7CompilerOptionsData; + readonly compilerOptions: Ts7ProjectCompilerOptions; readonly rootFiles: string[]; readonly program: Ts7SessionProgram; readonly checker: SemanticChecker; - constructor(data: Ts7ProjectData, snapshot: Ts7SessionSnapshot, session: Ts7Session) { + constructor(data: Ts7ReportedProjectData, snapshot: Ts7SessionSnapshot, session: Ts7Session) { this.id = data.id; this.configFileName = data.configFileName; this.compilerOptions = data.compilerOptions; @@ -260,7 +278,7 @@ export class Ts7SessionProgram { ...(file === undefined ? {} : { file }), }; } - getCompilerOptions(): Ts7CompilerOptionsData { + getCompilerOptions(): Ts7ProjectCompilerOptions { this.ensureActive(); return this.project.compilerOptions; } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6022-width-lift-discriminant.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6022-width-lift-discriminant.ts.json new file mode 100644 index 000000000..38c0cb787 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6022-width-lift-discriminant.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6022-width-lift-discriminant.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6024-object-literal-method-slot-return.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6024-object-literal-method-slot-return.ts.json new file mode 100644 index 000000000..c04cbf304 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6024-object-literal-method-slot-return.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6024-object-literal-method-slot-return.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6022-width-lift-discriminant.ts b/tests/corpus/6022-width-lift-discriminant.ts new file mode 100644 index 000000000..73bb5059b --- /dev/null +++ b/tests/corpus/6022-width-lift-discriminant.ts @@ -0,0 +1,54 @@ +// A record built in a map callback whose fields width-lift into several +// members of a discriminated union (a nested literal with a narrowed field, +// and a member that only needs `kind` and `loc`): its discriminant selects +// the member. +interface Loc { + start: number; +} +type Expr = + | { kind: "get"; obj: Expr; field: string; loc: Loc } + | { kind: "ref"; name: string; loc: Loc } + | { kind: "undef"; loc: Loc }; +type Stmt = + | { kind: "set"; obj: Expr; field: string; value: Expr; loc: Loc } + | { kind: "break"; label?: string; loc: Loc } + | { kind: "return"; value: Expr | null; loc: Loc }; + +function showExpr(expr: Expr): string { + switch (expr.kind) { + case "get": + return `${showExpr(expr.obj)}.${expr.field}`; + case "ref": + return expr.name; + case "undef": + return "undefined"; + } +} + +function show(stmt: Stmt): string { + switch (stmt.kind) { + case "set": + return `${showExpr(stmt.obj)}.${stmt.field} = ${showExpr(stmt.value)}`; + case "break": + return `break${stmt.label === undefined ? "" : " " + stmt.label}`; + case "return": + return `return ${stmt.value === null ? "-" : showExpr(stmt.value)}`; + } +} + +function copies(fields: string[], source: Expr & { kind: "ref" }, dst: Expr, loc: Loc): Stmt[] { + return fields.map((field) => ({ + kind: "set", + obj: dst, + field, + value: { kind: "get", obj: source, field, loc }, + loc, + })); +} + +const loc: Loc = { start: 0 }; +const out: Expr = { kind: "ref", name: "out", loc }; +const span: Expr = { kind: "ref", name: "span", loc }; +if (span.kind === "ref") console.log(copies(["lo", "hi"], span, out, loc).map(show).join("; ")); +const stops: Stmt[] = ["a", "b"].map((label) => ({ kind: "break", label, loc })); +console.log(stops.map(show).join("; ")); diff --git a/tests/corpus/6024-object-literal-method-slot-return.ts b/tests/corpus/6024-object-literal-method-slot-return.ts new file mode 100644 index 000000000..b5fa7ddd5 --- /dev/null +++ b/tests/corpus/6024-object-literal-method-slot-return.ts @@ -0,0 +1,114 @@ +// An object-literal method returns the type its slot declares. The literal +// statements below have their own inferred type, a union of records whose +// `init` fields are `Expr` or `null` and whose tryCatch member has fields +// the declared `Stmt` does not; the method still returns `Stmt[]`. +type Expr = + | { kind: "num"; value: number } + | { kind: "str"; text: string } + | { kind: "ref"; name: string }; +type Stmt = + | { kind: "varDecl"; name: string; init: Expr | null } + | { kind: "exprStmt"; expr: Expr } + | { kind: "if"; cond: Expr; then: Stmt[]; else_: Stmt[] | null } + | { kind: "loop"; init: Stmt | null; body: Stmt[] } + | { + kind: "tryCatch"; + tryBody: Stmt[]; + catchBody: Stmt[] | null; + catchName: string | null; + finallyBody: Stmt[] | null; + }; + +interface Step { + label: string; + build(source: Expr, append: (value: Expr) => Stmt[]): Stmt[]; + first(source: Expr): Stmt | Expr; +} + +const ref = (name: string): Expr => ({ kind: "ref", name }); + +function arrayStep(label: string): Step { + return { + label, + build(source, append) { + const loop: Stmt = { + kind: "loop", + init: { kind: "varDecl", name: "cursor", init: { kind: "num", value: 0 } }, + body: [...append(ref("value"))], + }; + return [ + { kind: "varDecl", name: "array", init: source }, + { kind: "varDecl", name: "close", init: ref("flag") }, + { kind: "varDecl", name: "value", init: null }, + { + kind: "tryCatch", + tryBody: [loop], + catchBody: null, + catchName: null, + finallyBody: [{ kind: "if", cond: ref("close"), then: [], else_: null }], + }, + ]; + }, + first(source) { + if (source.kind === "num") return { kind: "varDecl", name: "n", init: null }; + return source; + }, + }; +} + +function show(expr: Expr | null): string { + if (expr === null) return "null"; + switch (expr.kind) { + case "num": + return String(expr.value); + case "str": + return JSON.stringify(expr.text); + case "ref": + return expr.name; + } +} + +function print(stmts: Stmt[], depth: number): void { + const pad = " ".repeat(depth); + for (const s of stmts) { + switch (s.kind) { + case "varDecl": + console.log(`${pad}let ${s.name} = ${show(s.init)}`); + break; + case "exprStmt": + console.log(`${pad}${show(s.expr)}`); + break; + case "if": + console.log(`${pad}if ${show(s.cond)} (else: ${s.else_ === null ? "none" : s.else_.length})`); + print(s.then, depth + 1); + break; + case "loop": + console.log(`${pad}loop`); + if (s.init) print([s.init], depth + 1); + print(s.body, depth + 1); + break; + case "tryCatch": + console.log(`${pad}try (catch: ${s.catchName ?? "none"})`); + print(s.tryBody, depth + 1); + if (s.catchBody) print(s.catchBody, depth + 1); + if (s.finallyBody) { + console.log(`${pad}finally`); + print(s.finallyBody, depth + 1); + } + break; + } + } +} + +const step = arrayStep("array"); +console.log(step.label); +const stmts = step.build({ kind: "str", text: "items" }, (value) => [ + { kind: "exprStmt", expr: value }, + { kind: "varDecl", name: "done", init: null }, +]); +print(stmts, 0); +console.log(stmts.length, JSON.stringify(stmts[2])); +for (const source of [{ kind: "num", value: 1 }, ref("x")] satisfies Expr[]) { + const head = step.first(source); + console.log(head.kind, "name" in head ? head.name : "", JSON.stringify(head)); +} diff --git a/tests/harness/corpus-costs/6022-width-lift-discriminant.ts.json b/tests/harness/corpus-costs/6022-width-lift-discriminant.ts.json new file mode 100644 index 000000000..c0f25a6f7 --- /dev/null +++ b/tests/harness/corpus-costs/6022-width-lift-discriminant.ts.json @@ -0,0 +1 @@ +{ "plain": 3800, "san": 7400 } diff --git a/tests/harness/corpus-costs/6024-object-literal-method-slot-return.ts.json b/tests/harness/corpus-costs/6024-object-literal-method-slot-return.ts.json new file mode 100644 index 000000000..80c95a135 --- /dev/null +++ b/tests/harness/corpus-costs/6024-object-literal-method-slot-return.ts.json @@ -0,0 +1 @@ +{ "plain": 3000, "san": 4400 } diff --git a/tests/harness/native-frontend.ts b/tests/harness/native-frontend.ts index 475db54aa..048a08251 100644 --- a/tests/harness/native-frontend.ts +++ b/tests/harness/native-frontend.ts @@ -20,6 +20,7 @@ import { moduleUsesBigInt, moduleUsesCopying, moduleUsesDynInvoke, + moduleUsesDynAsync, moduleUsesInspect, moduleUsesRegex, moduleUsesSymbol, @@ -65,7 +66,13 @@ export const programs = [ "nullish-long-chain.ts", "class-array-optional-return.ts", "contextual-array-union-write.ts", + "2391-default-builtin-imports/main.ts", + "3055-default-builtin-nodenext/main.ts", + "5854-array-from-async.ts", "6020-class-extends-function-constructor.js", + "5585-record-results-inlined.ts", + "2631-create-require/main.ts", + "4970-int32-call-abi.ts", ]; interface LowerRequest { @@ -224,6 +231,7 @@ export async function checkProgram(frontend: NativeFrontend, file: string): Prom copying: moduleUsesCopying(module), inspect: moduleUsesInspect(module), dynInvoke: moduleUsesDynInvoke(module), + dynAsync: moduleUsesDynAsync(module), symbol: moduleUsesSymbol(module), bigint: moduleUsesBigInt(module), zlib: moduleUsesZlib(module),