From 77c72c81075c0dc84d3613fa10417221503874bb Mon Sep 17 00:00:00 2001 From: Perryvw Date: Thu, 22 May 2025 21:57:54 +0200 Subject: [PATCH] Fix root level using statement not disposing object --- .../pre-transformers/using-transformer.ts | 20 ++++++++++++++----- test/unit/using.spec.ts | 16 +++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/transformation/pre-transformers/using-transformer.ts b/src/transformation/pre-transformers/using-transformer.ts index d78f6206a..1229b71c2 100644 --- a/src/transformation/pre-transformers/using-transformer.ts +++ b/src/transformation/pre-transformers/using-transformer.ts @@ -5,11 +5,13 @@ import { LuaLibFeature, importLuaLibFeature } from "../utils/lualib"; export function usingTransformer(context: TransformationContext): ts.TransformerFactory { return ctx => sourceFile => { function visit(node: ts.Node): ts.Node { - if (ts.isBlock(node)) { + if (ts.isBlock(node) || ts.isSourceFile(node)) { const [hasUsings, newStatements] = transformBlockWithUsing(context, node.statements, node); if (hasUsings) { // Recurse visitor into updated block to find further usings - const updatedBlock = ts.factory.updateBlock(node, newStatements); + const updatedBlock = ts.isBlock(node) + ? ts.factory.updateBlock(node, newStatements) + : ts.factory.updateSourceFile(node, newStatements); const result = ts.visitEachChild(updatedBlock, visit, ctx); // Set all the synthetic node parents to something that makes sense @@ -29,7 +31,8 @@ export function usingTransformer(context: TransformationContext): ts.Transformer } return ts.visitEachChild(node, visit, ctx); } - return ts.visitEachChild(sourceFile, visit, ctx); + const transformedSourceFile = ts.visitEachChild(sourceFile, visit, ctx); + return visit(transformedSourceFile) as ts.SourceFile; }; } @@ -40,7 +43,7 @@ function isUsingDeclarationList(node: ts.Node): node is ts.VariableStatement { function transformBlockWithUsing( context: TransformationContext, statements: ts.NodeArray | ts.Statement[], - block: ts.Block + block: ts.Block | ts.SourceFile ): [true, ts.Statement[]] | [false] { const newStatements: ts.Statement[] = []; @@ -102,7 +105,14 @@ function transformBlockWithUsing( call = ts.factory.createAwaitExpression(call); } - if (ts.isBlock(block.parent) && block.parent.statements[block.parent.statements.length - 1] !== block) { + if (ts.isSourceFile(block)) { + // If block is a sourcefile, don't insert a return statement into root code + newStatements.push(ts.factory.createExpressionStatement(call)); + } else if ( + block.parent && + ts.isBlock(block.parent) && + block.parent.statements[block.parent.statements.length - 1] !== block + ) { // If this is a free-standing block in a function (not the last statement), dont return the value newStatements.push(ts.factory.createExpressionStatement(call)); } else { diff --git a/test/unit/using.spec.ts b/test/unit/using.spec.ts index 34b4fef67..bfe5312b0 100644 --- a/test/unit/using.spec.ts +++ b/test/unit/using.spec.ts @@ -217,3 +217,19 @@ test("works with disposable classes (#1584)", () => { return log; `.expectToEqual(["action", "cleanup"]); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1632 +test("works on root level (#1632)", () => { + util.testModule` + export let disposed = false; + + class A { + [Symbol.dispose] = function (this: A) { + disposed = true; + } + } + using a = new A(); + `.expectToEqual({ + disposed: true, + }); +});