mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-05 08:13:06 +08:00
Prefer the union arm that keeps every field of a converted record (#2259)
This commit is contained in:
@@ -128,6 +128,25 @@ export function widthLiftPlan(lowerer: Lowerer, src: IrType, dst: IrType): Width
|
||||
const route = presenceRoute(lowerer, src.shapeId, selected[0]!, selected[1]!);
|
||||
if (route) return route;
|
||||
}
|
||||
// A record whose fields some arm keeps EVERY one of, each lifting
|
||||
// (`{ id; limit; opts?: A | B }` into `{ id; limit; opts?: A | B | C } |
|
||||
// { id; opts?: C }`): that arm is the value's own layout, widened; the
|
||||
// others hold it only by dropping fields. Prefer the unique lossless arm.
|
||||
if (selected.length > 1 && src.kind === "record") {
|
||||
const source = lowerer.shapes.get(src.shapeId);
|
||||
const lossless = selected.filter(({ arm }) => {
|
||||
const target = arm.kind === "record" ? lowerer.shapes.get(arm.shapeId) : undefined;
|
||||
return (
|
||||
source !== undefined &&
|
||||
target !== undefined &&
|
||||
!source.tuple &&
|
||||
!target.tuple &&
|
||||
target.fields.length === source.fields.length &&
|
||||
source.fields.every((field) => target.fields.some((kept) => kept.name === field.name))
|
||||
);
|
||||
});
|
||||
if (lossless.length === 1) selected = lossless;
|
||||
}
|
||||
if (selected.length !== 1) return null;
|
||||
return { how: "liftWrap", tag: selected[0]!.tag, arm: selected[0]!.arm };
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/union-record-lossless-arm.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// A record flowing into a union where several record arms can hold it by a
|
||||
// width conversion: the arm that keeps every one of its fields is the
|
||||
// value's own layout, widened, and wins over arms that drop fields.
|
||||
|
||||
interface FastOpts {
|
||||
fast?: boolean;
|
||||
strict?: boolean;
|
||||
}
|
||||
interface DepthOpts {
|
||||
depth?: number;
|
||||
}
|
||||
interface StrictOpts {
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
interface Wide {
|
||||
id: string;
|
||||
window: number;
|
||||
kind?: string;
|
||||
limit: number;
|
||||
opts?: FastOpts | DepthOpts | StrictOpts;
|
||||
}
|
||||
|
||||
interface Judge {
|
||||
id: string;
|
||||
window: number;
|
||||
kind: string;
|
||||
opts?: StrictOpts;
|
||||
}
|
||||
|
||||
interface Narrow {
|
||||
id: string;
|
||||
window: number;
|
||||
kind?: string;
|
||||
limit: number;
|
||||
opts?: FastOpts | DepthOpts;
|
||||
}
|
||||
|
||||
function show(entry: Wide | Judge): string {
|
||||
const limit = "limit" in entry ? ` limit=${entry.limit}` : "";
|
||||
return `${entry.kind ?? "wide"} ${entry.id} window=${entry.window}${limit} ${JSON.stringify(entry.opts ?? null)}`;
|
||||
}
|
||||
|
||||
const narrow: Narrow = { id: "n1", window: 4, limit: 2, opts: { depth: 3 } };
|
||||
console.log(show(narrow));
|
||||
|
||||
const entries: (Wide | Judge)[] = [narrow, { id: "j1", window: 1, kind: "judge", opts: { strict: true } }];
|
||||
const plain: Narrow = { id: "n2", window: 8, kind: "custom", limit: 5 };
|
||||
entries.push(plain);
|
||||
for (const entry of entries) console.log(show(entry));
|
||||
|
||||
let latest: Wide | Judge | undefined;
|
||||
for (const item of [narrow, plain]) latest = item;
|
||||
console.log(latest === undefined ? "none" : show(latest));
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{ "plain": 11809, "san": 13580 }
|
||||
Reference in New Issue
Block a user