Skip to content

Commit 8dd12a9

Browse files
tomblindark120202
andauthored
fixed declarations that reference their own identifiers (#910)
* fixed variable declarations that reference their own identifiers in the initializer * Update src/transformation/utils/lua-ast.ts Co-authored-by: ark120202 <ark120202@gmail.com> * compiler error fix * moved tests to assignments Co-authored-by: Tom <tomblind@users.noreply.github.com> Co-authored-by: ark120202 <ark120202@gmail.com>
1 parent 110b56f commit 8dd12a9

File tree

2 files changed

+50
-11
lines changed

2 files changed

+50
-11
lines changed

src/transformation/utils/lua-ast.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import * as lua from "../../LuaAST";
44
import { assert, castArray } from "../../utils";
55
import { TransformationContext } from "../context";
66
import { createExportedIdentifier, getIdentifierExportScope } from "./export";
7-
import { peekScope, ScopeType } from "./scope";
8-
import { isFunctionType } from "./typescript";
7+
import { peekScope, ScopeType, Scope } from "./scope";
98
import { transformLuaLibFunction } from "./lualib";
109
import { LuaLibFeature } from "../../LuaLib";
1110

@@ -129,6 +128,17 @@ export function createHoistableVariableDeclarationStatement(
129128
return declaration;
130129
}
131130

131+
function hasMultipleReferences(scope: Scope, identifiers: lua.Identifier | lua.Identifier[]) {
132+
const scopeSymbols = scope.referencedSymbols;
133+
if (!scopeSymbols) {
134+
return false;
135+
}
136+
137+
const referenceLists = castArray(identifiers).map(i => i.symbolId && scopeSymbols.get(i.symbolId));
138+
139+
return referenceLists.some(symbolRefs => symbolRefs && symbolRefs.length > 1);
140+
}
141+
132142
export function createLocalOrExportedOrGlobalDeclaration(
133143
context: TransformationContext,
134144
lhs: lua.Identifier | lua.Identifier[],
@@ -163,15 +173,8 @@ export function createLocalOrExportedOrGlobalDeclaration(
163173
const isTopLevelVariable = scope.type === ScopeType.File;
164174

165175
if (context.isModule || !isTopLevelVariable) {
166-
const isPossibleWrappedFunction =
167-
!isFunctionDeclaration &&
168-
tsOriginal &&
169-
ts.isVariableDeclaration(tsOriginal) &&
170-
tsOriginal.initializer &&
171-
isFunctionType(context, context.checker.getTypeAtLocation(tsOriginal.initializer));
172-
173-
if (isPossibleWrappedFunction || scope.type === ScopeType.Switch) {
174-
// Split declaration and assignment for wrapped function types to allow recursion
176+
if (scope.type === ScopeType.Switch || (!isFunctionDeclaration && hasMultipleReferences(scope, lhs))) {
177+
// Split declaration and assignment of identifiers that reference themselves in their declaration
175178
declaration = lua.createVariableDeclarationStatement(lhs, undefined, tsOriginal);
176179
assignment = lua.createAssignmentStatement(lhs, rhs, tsOriginal);
177180
} else {

test/unit/assignments.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,39 @@ test.each([
323323
return { r, o, a };
324324
`.expectToMatchJsResult();
325325
});
326+
327+
test("local variable declaration referencing self indirectly", () => {
328+
util.testFunction`
329+
let cb: () => void;
330+
331+
function foo(newCb: () => void) {
332+
cb = newCb;
333+
return "foo";
334+
}
335+
336+
let bar = foo(() => {
337+
bar = "bar";
338+
});
339+
340+
cb();
341+
return bar;
342+
`.expectToMatchJsResult();
343+
});
344+
345+
test("local multiple variable declaration referencing self indirectly", () => {
346+
util.testFunction`
347+
let cb: () => void;
348+
349+
function foo(newCb: () => void) {
350+
cb = newCb;
351+
return ["a", "foo", "c"];
352+
}
353+
354+
let [a, bar, c] = foo(() => {
355+
bar = "bar";
356+
});
357+
358+
cb();
359+
return bar;
360+
`.expectToMatchJsResult();
361+
});

0 commit comments

Comments
 (0)