Expect the collapsed canonical forms as dynamic slots in the coverage tests

The tools field (Tool[]) and the all global ((number | Callbacks)[]) hold unions that canonical mapping maps to the checked dynamic, so the canonical fallback now degrades them: they are dynamic slots again, with SC6104 warnings and attributed operations, as these tests expected before the fallback classified them as exact.
This commit is contained in:
Chris Tate
2026-10-27 10:46:54 -05:00
parent 06e9672d90
commit b11bc54a2b
+11 -8
View File
@@ -431,10 +431,11 @@ test("--explain-dynamic attributes each refusal to the unit the dynamic tier wou
test("--explain-dynamic lists the type failures localized failure would turn into dynamic slots", async () => {
const { coverage } = analyze(fixture("localized-failure.ts"), { explainDynamic: true });
const report = coverage.tiers!.localizedFailure;
// Locals and parameters degrade (stages L1 and L2), the 'any' field
// compiles, and the `Tool[]` field maps exactly from its canonical form
// (stage N2); only the refused WeakRef field and its construction remain.
// Locals, fields and parameters degrade (stages L1 and L2), and the
// 'any' field compiles; only the refused WeakRef field and its
// construction remain.
expect(coverage.dynamicSlots?.map((s) => [s.slot, s.name])).toEqual([
["field", "tools"],
["param", "progress"],
["local", "callbacks"],
]);
@@ -457,26 +458,28 @@ test("a local or module global whose declared type does not compile becomes a dy
expect(coverage.diagnostics).toEqual([]);
expect(coverage.dynamicSlots?.map((s) => [s.slot, s.name, s.declaredType, s.code])).toEqual([
["global", "current", "Callbacks | undefined", "SC2009"],
["global", "all", "(number | Callbacks)[]", "SC2009"],
["local", "local", "Callbacks | undefined", "SC2009"],
]);
// `all`'s element type maps exactly from its canonical form (stage N2), so
// the array is no dynamic slot.
expect(coverage.dynamicSlots?.find((s) => s.name === "all")).toBeUndefined();
expect(coverage.performance?.filter((d) => d.code === "SC6104")).toHaveLength(2);
// The loop over `all` is top-level code: its dynamic operations count too.
expect(coverage.dynamicSlots?.find((s) => s.name === "all")?.operations).toBeGreaterThan(0);
expect(coverage.performance?.filter((d) => d.code === "SC6104")).toHaveLength(3);
expect(coveragePasses(coverage, "blockers")).toBe(true);
expect(coveragePasses(coverage, "dynamic")).toBe(true);
expect(coveragePasses(coverage, "dynamic-slots")).toBe(false);
const envelope = coverageEnvelope(coverage, { compilerVersion: "test", sourceTexts });
expect(envelope.dynamicSlots?.map((s) => [s.kind, s.name, s.line])).toEqual([
["global", "current", 10],
["global", "all", 36],
["local", "local", 14],
]);
expect(envelope.diagnostics.filter((d) => d.code === "SC6104").map((d) => d.severity)).toEqual([
"warning",
"warning",
"warning",
]);
const text = renderCoverage(coverage, { sourceTexts, root: repoRoot });
expect(text).toContain("dynamic slots 2");
expect(text).toContain("dynamic slots 3");
expect(text).toContain("module global 'current' (declared 'Callbacks | undefined')");
// --tier=static-only keeps every refusal.
const strict = analyze(program, { tier: "static-only" }).coverage;