diff --git a/src/typecheck/typecheck.ts b/src/typecheck/typecheck.ts index 9756cfbd..1ff4f387 100644 --- a/src/typecheck/typecheck.ts +++ b/src/typecheck/typecheck.ts @@ -48,7 +48,7 @@ import { UnboundTypeParam, } from "../errors"; import { castAst, findFieldInModule } from "./resolutionStep"; -import { topologicalSort } from "../utils/topsort"; +import { createRecordGraph, topsort } from "../data/graph"; export type TypeMeta = { $: TVar }; @@ -957,7 +957,8 @@ function topSortedModules( dependencyGraph[ns] = deps; } - return topologicalSort(dependencyGraph); + const graph = createRecordGraph(dependencyGraph); + return topsort(graph); } function getDependencies(program: UntypedModule): string[] { diff --git a/src/utils/topsort.test.ts b/src/utils/topsort.test.ts deleted file mode 100644 index 5a503ec6..00000000 --- a/src/utils/topsort.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { expect, test } from "vitest"; -import { DepsMap, topologicalSort, CyclicDepError } from "./topsort"; - -test("returns an empty list if there are no items", () => { - const deps: DepsMap = {}; - expect(topologicalSort(deps)).toEqual([]); -}); - -test("returns a singleton if there are no deps", () => { - const deps: DepsMap = { x: [] }; - expect(topologicalSort(deps)).toEqual(["x"]); -}); - -test("chain dep", () => { - const deps: DepsMap = { z: [], y: ["z"], x: ["y"] }; - const res = topologicalSort(deps); - - expect(res).toEqual(["z", "y", "x"]); -}); - -test("two deps", () => { - const deps: DepsMap = { x: ["y", "z"], y: [], z: [] }; - const res = topologicalSort(deps); - expect(res[2]).toEqual("x"); -}); - -test("does not visit twice", () => { - const deps: DepsMap = { x: ["y", "z"], y: ["z"], z: [] }; - const res = topologicalSort(deps); - - expect(res).toEqual([..."zyx"]); -}); - -test("throws on cyclic deps", () => { - const deps: DepsMap = { x: ["y"], y: ["z"], z: ["x"] }; - - expect(() => topologicalSort(deps)).toThrow(CyclicDepError); -}); diff --git a/src/utils/topsort.ts b/src/utils/topsort.ts deleted file mode 100644 index 6f517e2f..00000000 --- a/src/utils/topsort.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* eslint-disable no-constant-condition */ -export type DepsMap = Record; - -export class CyclicDepError extends Error { - constructor( - public sorted: string[], - public deps: string[], - ) { - super("Cyclic deps detected"); - } -} - -export function topologicalSort( - dependencies: Record, -): string[] { - const sources = new Set(Object.keys(dependencies)); - for (const deps of Object.values(dependencies)) { - for (const dep of deps) { - sources.delete(dep); - } - } - - // Now `sources` only contains nodes without deps - - const visited = new Set(); - const sorted: string[] = []; - - function visit(node: string) { - visited.add(node); - const adjs = dependencies[node] ?? []; - for (const adj of adjs) { - if (!visited.has(adj)) { - visit(adj); - } - } - sorted.push(node); - } - - for (const source of sources) { - visit(source); - } - - if (sorted.length < Object.keys(dependencies).length) { - throw new CyclicDepError(sorted, Object.keys(dependencies)); - } - - return sorted; -}