mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-04 08:04:37 +08:00
Let boxable function arms ride a checked-dynamic union
A union with a checked-dynamic arm (`unknown`, fetch's AbortSignal) maps to the checked-dynamic value when every other arm is one the checked-dynamic tree holds faithfully. Function arms were excluded, so `Progress | AbortSignal | undefined` was refused (SC2009). The tree boxes a function whose parameters check in and whose result converts out by reference (canBoxFuncIntoDyn), and `typeof x === "function"` narrows it back out to the typed function. Such arms now join the collapse. The corpus program checks calls, identity (`===` against the original), and the other arm's members against Node. pi's SessionManager.listAll takes `onProgressOrSignal?: SessionListProgress | AbortSignal`. The refusal rejected the whole SessionManager class. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8a22e0f515
commit
605e312e78
@@ -10,6 +10,7 @@ import {
|
||||
isDynTypedRefType,
|
||||
BOOL,
|
||||
bytesOf,
|
||||
canBoxFuncIntoDyn,
|
||||
canConvertToDyn,
|
||||
canDynCheckTo,
|
||||
CHILD_T,
|
||||
@@ -8341,6 +8342,16 @@ function dynSubsumableUnionArm(arm: IrType, ctx: TypeMapperCtx): boolean {
|
||||
// `string | URL | Request`, fetch's own input type under @types/node.
|
||||
case "url":
|
||||
return true;
|
||||
// A function the checked-dynamic tree can box (each parameter checks
|
||||
// in, the result converts out) is held by reference there, and
|
||||
// `typeof x === "function"` narrows it back out: `Progress | AbortSignal`
|
||||
// beside fetch's handles.
|
||||
case "func":
|
||||
return canBoxFuncIntoDyn(
|
||||
arm,
|
||||
(id) => ctx.shapes.get(id),
|
||||
(id) => ctx.unions.get(id),
|
||||
);
|
||||
case "record":
|
||||
case "array":
|
||||
// `T | Promise<T>` with T bound to `unknown`: the checked-dynamic value
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/dyn-union-function-arms.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// A union of a function type with a value the checked-dynamic tree holds
|
||||
// (AbortSignal, `unknown`) rides that representation: the function is held
|
||||
// by reference, `typeof x === "function"` narrows it back out, and calls,
|
||||
// identity and the other arm's members behave as in Node.
|
||||
|
||||
type Progress = (loaded: number, total: number) => void;
|
||||
|
||||
function listAll(
|
||||
dirOrProgress?: string | Progress,
|
||||
progressOrSignal?: Progress | AbortSignal,
|
||||
signal?: AbortSignal,
|
||||
): string {
|
||||
const dir = typeof dirOrProgress === "string" ? dirOrProgress : "/default";
|
||||
const progress =
|
||||
typeof dirOrProgress === "function"
|
||||
? dirOrProgress
|
||||
: typeof progressOrSignal === "function"
|
||||
? progressOrSignal
|
||||
: undefined;
|
||||
const abortSignal =
|
||||
typeof dirOrProgress === "string" || typeof progressOrSignal === "function"
|
||||
? signal
|
||||
: (progressOrSignal ?? signal);
|
||||
progress?.(1, 3);
|
||||
progress?.(3, 3);
|
||||
return `${dir} aborted=${abortSignal?.aborted ?? "none"}`;
|
||||
}
|
||||
|
||||
const seen: string[] = [];
|
||||
const report: Progress = (loaded, total) => seen.push(`${loaded}/${total}`);
|
||||
const controller = new AbortController();
|
||||
console.log(listAll());
|
||||
console.log(listAll("/x", report));
|
||||
console.log(listAll(report, controller.signal));
|
||||
controller.abort();
|
||||
console.log(listAll("/y", undefined, controller.signal));
|
||||
console.log(listAll(report, controller.signal), seen.join(" "));
|
||||
|
||||
function same(handler: Progress | AbortSignal | undefined): boolean {
|
||||
return handler === report;
|
||||
}
|
||||
console.log(same(report), same(controller.signal), same(undefined), same((a, b) => void (a + b)));
|
||||
|
||||
function describe(value: unknown | ((n: number) => string)): string {
|
||||
if (typeof value === "function") return `function -> ${(value as (n: number) => string)(7)}`;
|
||||
return `value ${JSON.stringify(value)}`;
|
||||
}
|
||||
console.log(describe((n: number) => `n=${n}`), describe({ a: 1 }), describe("s"));
|
||||
@@ -0,0 +1 @@
|
||||
{ "plain": 4000 }
|
||||
Reference in New Issue
Block a user