GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — ts.transform output may have inconsistent node.parent pointers, observed around usingTransformer · Issue #1685 · TypeScriptToLua/TypeScriptToLua Open DescriptionContextWhile working on a regression test for In short: when building a tree via This issue is not about runtime Lua output; it’s about the shape/invariants of the transformed TS AST and what invariants TSTL expects/relies on. Repro (copy/paste test)This is an exact test which can place into
// https://github.com/TypeScriptToLua/TypeScriptToLua/pull/1613 test("using transformer keeps parent chain for recursively transformed nested usings", () => { const code = ` declare function disposable(): Disposable; function f() { using a = disposable(); { using b = disposable(); } } `; const program = createVirtualProgram({ "main.ts": code }, { target: ts.ScriptTarget.ESNext, lib: ["lib.esnext.d.ts"] }); const sourceFile = program.getSourceFile("main.ts"); util.assert(sourceFile); const context = new TransformationContext(program, sourceFile, createVisitorMap([])); const transformed = ts.transform(sourceFile, [usingTransformer(context)]).transformed[0]; type NodeRelation = { id: number; kind: ts.SyntaxKind; text?: string; parent: string; children: number[]; }; const nodeToId = new Map<ts.Node, number>(); const relations: NodeRelation[] = []; const visit = (node: ts.Node) => { const id = relations.length; nodeToId.set(node, id); relations.push({ id, kind: node.kind, text: ts.isIdentifier(node) ? node.text : undefined, parent: "-", children: [] }); ts.forEachChild(node, child => { const childId = visit(child); relations[id].children.push(childId); }); return id; }; visit(transformed); for (const [node, id] of nodeToId.entries()) { if (!node.parent) { relations[id].parent = "-"; continue; } const parentId = nodeToId.get(node.parent); relations[id].parent = parentId !== undefined ? String(parentId) : `outside:${ts.SyntaxKind[node.parent.kind]}`; } const usingIds = relations.filter(r => r.kind === ts.SyntaxKind.Identifier && r.text === "__TS__Using").map(r => r.id); expect(usingIds).toHaveLength(2); const functionId = relations.find(r => r.kind === ts.SyntaxKind.FunctionDeclaration && r.children.some(childId => relations[childId].kind === ts.SyntaxKind.Identifier && relations[childId].text === "f"))?.id; util.assert(functionId !== undefined); const functionBlockId = relations[functionId].children.find(childId => relations[childId].kind === ts.SyntaxKind.Block); util.assert(functionBlockId !== undefined); const formatNodeLine = (id: number, depth: number) => { const r = relations[id]; const text = r.text ?? "-"; return `${" ".repeat(depth)}- ${r.id} ${ts.SyntaxKind[r.kind]} ${text} parent=${r.parent}`; }; const renderTree = (id: number, depth: number): string[] => { const lines = [formatNodeLine(id, depth)]; for (const childId of relations[id].children) { lines.push(...renderTree(childId, depth + 1)); } return lines; }; const subtreeIds = new Set<number>(); const collectSubtree = (id: number) => { if (subtreeIds.has(id)) return; subtreeIds.add(id); for (const childId of relations[id].children) collectSubtree(childId); }; collectSubtree(functionBlockId); const mismatchLines: string[] = []; for (const relation of relations) { if (!subtreeIds.has(relation.id)) continue; for (const childId of relation.children) { if (!subtreeIds.has(childId)) continue; const child = relations[childId]; const expectedParent = String(relation.id); if (child.parent !== expectedParent) { mismatchLines.push(`- child ${child.id} ${ts.SyntaxKind[child.kind]} expectedParent=${expectedParent} actualParent=${child.parent}`); } } } const treeDump = renderTree(functionBlockId, 0).join("\n"); const mismatchesDump = mismatchLines.length > 0 ? mismatchLines.join("\n") : "none"; const dump = `tree:\n${treeDump}\nparentMismatches:\n${mismatchesDump}`; expect(dump).toBe(`...`) }); CommandsRun the single test: npx jest --runInBand --runTestsByPath test/unit/using.spec.ts \
--testNamePattern "using transformer keeps parent chain for recursively transformed nested usings"To compare transformer behavior, I checked out two revisions of:
# fixed git checkout 316f968 -- src/transformation/pre-transformers/using-transformer.ts # pre-fix git checkout 7ebbff5 -- src/transformation/pre-transformers/using-transformer.ts Observed behaviorFixed transformer (316f968)Within the function-body block subtree, Pre-fix transformer (7ebbff5)Many nodes inside the function-body block subtree have missing or outside parents ( Representative diff (fixed vs pre-fix): tree: - - 8 Block - parent=outside:FunctionDeclaration + - 8 Block - parent=- - - 9 ReturnStatement - parent=8 + - 9 ReturnStatement - parent=- - - 10 CallExpression - parent=9 + - 10 CallExpression - parent=- - - 11 Identifier __TS__Using parent=10 + - 11 Identifier __TS__Using parent=outside:CallExpression - - 12 FunctionExpression - parent=10 + - 12 FunctionExpression - parent=- - - 13 Parameter - parent=12 + - 13 Parameter - parent=outside:FunctionExpression ... - - 34 CallExpression - parent=10 + - 34 CallExpression - parent=outside:CallExpression ... parentMismatches: - - none + - child 11 Identifier expectedParent=10 actualParent=outside:CallExpression + - child 12 FunctionExpression expectedParent=10 actualParent=- + - child 34 CallExpression expectedParent=10 actualParent=outside:CallExpression + ... Expected / Questions
Activity
MetadataMetadataAssigneesLabelsNo labels TypeProjectsMilestoneRelationshipsDevelopmentIssue actions |
| You are visitor 01402520 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |