mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-29 07:04:09 +08:00
`class C implements Acyclic`, `interface I extends Acyclic` and
`type T = Acyclic<{ ... }>` promise that no chain of references leads
from such an object back to itself. The check is the cycle analysis that
decides tracing, so a proven type carries no cycle-collector header. When
it does not hold, SC7007 shows the cycle: the path of fields, and why it
can close (a field assigned after construction, with the first such
write; an array, Map or Set; a function, dynamic or promise field; a
subclass sharing the layout). cycle-analysis.ts gains explainCycle over
the same graph with edge labels; computeTraced is unchanged.
Acyclic elsewhere is reported with SC7006. Docs, @scriptc/types,
corpus 4642, diagnostics snapshots and TypeScript baselines included.
60 lines
1.3 KiB
TypeScript
60 lines
1.3 KiB
TypeScript
// Acyclic contracts that do not hold: each diagnostic shows a reference
|
|
// cycle that can form.
|
|
import type { Acyclic } from "@scriptc/types";
|
|
|
|
class ListNode implements Acyclic {
|
|
value: number;
|
|
next: ListNode | undefined = undefined;
|
|
constructor(value: number) {
|
|
this.value = value;
|
|
}
|
|
}
|
|
|
|
class Task implements Acyclic {
|
|
readonly name: string;
|
|
readonly done: () => void;
|
|
constructor(name: string, done: () => void) {
|
|
this.name = name;
|
|
this.done = done;
|
|
}
|
|
}
|
|
|
|
class Graph implements Acyclic {
|
|
readonly nodes: GraphNode[] = [];
|
|
}
|
|
|
|
class GraphNode {
|
|
readonly graph: Graph;
|
|
constructor(graph: Graph) {
|
|
this.graph = graph;
|
|
}
|
|
}
|
|
|
|
class Shape implements Acyclic {
|
|
readonly id: number;
|
|
constructor(id: number) {
|
|
this.id = id;
|
|
}
|
|
}
|
|
|
|
class Group extends Shape {
|
|
readonly members: Shape[] = [];
|
|
}
|
|
|
|
interface Cell extends Acyclic {
|
|
value: number;
|
|
link: Cell | null;
|
|
}
|
|
|
|
const a = new ListNode(1);
|
|
a.next = new ListNode(2);
|
|
a.next.next = a;
|
|
const t: Task = new Task("t", () => console.log(t.name));
|
|
const g = new Graph();
|
|
g.nodes.push(new GraphNode(g));
|
|
const group = new Group(1);
|
|
group.members.push(group);
|
|
const c: Cell = { value: 1, link: null };
|
|
c.link = c;
|
|
console.log(a.value, t.name, g.nodes.length, group.members.length, c.value);
|