mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
- A const that kept its initializer's layout (`const view: Counted[] = entries`)
is typed by its annotation, so a call that passed it compared the annotated
layout with the parameter's and copied it. The const now records its
initializer's type, and a call that passes it binds that type, at function
and module scope.
- Comparing two recursive layouts (`{ kids: Tree[]; note? }` against
`{ kids: Plain[] }`) recursed without end and stopped compilation with
"Maximum call stack size exceeded". A pair already being compared now holds
for the fields that reach it again.
- The divergence scan reported SC6001 for calls and consts whose layout the
lowering kept, which the coverage test refuses for corpus programs. The
lowering records those arguments and initializers, and the scan skips them.
97 lines
2.8 KiB
TypeScript
97 lines
2.8 KiB
TypeScript
// An array or record passed to a parameter whose type lacks some of its
|
|
// optional fields is the caller's value inside the callee: pushes, index
|
|
// stores, element-field writes and removals through the parameter reach the
|
|
// caller's array, as in Node.
|
|
|
|
interface Param {
|
|
id: string;
|
|
name: string;
|
|
owned?: true;
|
|
}
|
|
type Slot = { id: string; name: string };
|
|
|
|
function addSlot(params: Slot[], name: string): void {
|
|
params.push({ id: `${name}.0`, name });
|
|
}
|
|
function rename(params: Slot[], index: number, name: string): void {
|
|
params[index]!.name = name;
|
|
}
|
|
function replace(params: Slot[], index: number, slot: Slot): void {
|
|
params[index] = slot;
|
|
}
|
|
function removeFirst(params: Slot[]): string | undefined {
|
|
return params.shift()?.name;
|
|
}
|
|
function forward(params: Slot[], name: string): void {
|
|
addSlot(params, name);
|
|
addSlot(params, `${name}2`);
|
|
}
|
|
function names(params: Slot[]): string {
|
|
return params.map((p) => p.name).join(",");
|
|
}
|
|
|
|
const params: Param[] = [{ id: "a.0", name: "a", owned: true }];
|
|
addSlot(params, "b");
|
|
rename(params, 0, "first");
|
|
replace(params, 1, { id: "z.0", name: "z" });
|
|
forward(params, "c");
|
|
console.log(params.length, JSON.stringify(params));
|
|
console.log(removeFirst(params), params.length, params[0]?.owned, names(params));
|
|
params.splice(1, 1);
|
|
console.log(names(params));
|
|
|
|
const holder = { list: params };
|
|
addSlot(holder.list, "d");
|
|
console.log(holder.list.length, params.length, holder.list === params);
|
|
|
|
// A record parameter: writes to its fields reach the caller's record, and the
|
|
// optional field the parameter's type lacks stays as the caller left it.
|
|
interface Counter {
|
|
label: string;
|
|
hits: number;
|
|
note?: string;
|
|
}
|
|
function bump(target: { label: string; hits: number }): void {
|
|
target.hits += 1;
|
|
target.label = target.label.toUpperCase();
|
|
}
|
|
const counter: Counter = { label: "c", hits: 1 };
|
|
const noted: Counter = { label: "n", hits: 0, note: "kept" };
|
|
bump(counter);
|
|
bump(counter);
|
|
bump(noted);
|
|
console.log(JSON.stringify(counter), "note" in counter, JSON.stringify(noted));
|
|
|
|
// Recursion through the same parameter.
|
|
function fill(params: Slot[], n: number): void {
|
|
if (n === 0) return;
|
|
addSlot(params, `r${n}`);
|
|
fill(params, n - 1);
|
|
}
|
|
const deep: Param[] = [];
|
|
fill(deep, 3);
|
|
console.log(names(deep), deep.length);
|
|
|
|
// Recursive layouts: a tree with an optional field passed where a tree
|
|
// without it is expected.
|
|
interface Tree {
|
|
label: string;
|
|
kids: Tree[];
|
|
note?: string;
|
|
}
|
|
interface Plain {
|
|
label: string;
|
|
kids: Plain[];
|
|
}
|
|
function addKid(t: Plain, label: string): void {
|
|
t.kids.push({ label, kids: [] });
|
|
}
|
|
function size(t: Plain): number {
|
|
let n = 1;
|
|
for (const k of t.kids) n += size(k);
|
|
return n;
|
|
}
|
|
const tree: Tree = { label: "r", kids: [{ label: "a", kids: [], note: "leaf" }] };
|
|
addKid(tree, "b");
|
|
console.log(size(tree), tree.kids.map((k) => k.label).join(","), tree.kids[0]!.note);
|