X Tutup
Skip to content

Commit c8d8c73

Browse files
authored
Fix optimized vararg spread with casts (#1193)
Also fixes for other outer expressions.
1 parent 2429e26 commit c8d8c73

File tree

4 files changed

+51
-10
lines changed

4 files changed

+51
-10
lines changed

src/transformation/visitors/spread.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,15 @@ import { isMultiReturnCall } from "./language-extensions/multi";
1616
import { annotationRemoved } from "../utils/diagnostics";
1717
import { isGlobalVarargConstant } from "./language-extensions/vararg";
1818

19+
function skipOuterExpressionParents(node: ts.Node) {
20+
while (ts.isOuterExpression(node)) {
21+
node = node.parent;
22+
}
23+
return node;
24+
}
25+
1926
export function isOptimizedVarArgSpread(context: TransformationContext, symbol: ts.Symbol, identifier: ts.Identifier) {
20-
if (!ts.isSpreadElement(identifier.parent)) {
27+
if (!ts.isSpreadElement(skipOuterExpressionParents(identifier.parent))) {
2128
return false;
2229
}
2330

@@ -63,20 +70,21 @@ export function isOptimizedVarArgSpread(context: TransformationContext, symbol:
6370

6471
// TODO: Currently it's also used as an array member
6572
export const transformSpreadElement: FunctionVisitor<ts.SpreadElement> = (node, context) => {
66-
if (ts.isIdentifier(node.expression)) {
67-
if (isVarargType(context, node.expression)) {
73+
const tsInnerExpression = ts.skipOuterExpressions(node.expression);
74+
if (ts.isIdentifier(tsInnerExpression)) {
75+
if (isVarargType(context, tsInnerExpression)) {
6876
context.diagnostics.push(annotationRemoved(node, AnnotationKind.Vararg));
6977
}
70-
const symbol = context.checker.getSymbolAtLocation(node.expression);
71-
if (symbol && isOptimizedVarArgSpread(context, symbol, node.expression)) {
78+
const symbol = context.checker.getSymbolAtLocation(tsInnerExpression);
79+
if (symbol && isOptimizedVarArgSpread(context, symbol, tsInnerExpression)) {
7280
return lua.createDotsLiteral(node);
7381
}
7482
}
7583

7684
const innerExpression = context.transformExpression(node.expression);
77-
if (isMultiReturnCall(context, node.expression)) return innerExpression;
85+
if (isMultiReturnCall(context, tsInnerExpression)) return innerExpression;
7886

79-
const type = context.checker.getTypeAtLocation(node.expression);
87+
const type = context.checker.getTypeAtLocation(node.expression); // not ts-inner expression, in case of casts
8088
if (isArrayType(context, type)) {
8189
return createUnpackCall(context, innerExpression, node);
8290
}

src/typescript-internal.d.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { DiagnosticsProducingTypeChecker } from "./transformation/context";
2-
32
export {};
43

54
declare module "typescript" {
@@ -31,6 +30,13 @@ declare module "typescript" {
3130

3231
function transformJsx(context: TransformationContext): (x: SourceFile) => SourceFile;
3332

34-
function skipParentheses(node: Expression): Expression;
35-
function skipParentheses(node: Node): Node;
33+
export type OuterExpression =
34+
| ParenthesizedExpression
35+
| TypeAssertion
36+
| AsExpression
37+
| NonNullExpression
38+
| PartiallyEmittedExpression;
39+
40+
function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression;
41+
export function isOuterExpression(node: Node, kinds?: OuterExpressionKinds): node is OuterExpression;
3642
}

test/unit/__snapshots__/spread.spec.ts.snap

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,21 @@ end
1717
return ____exports"
1818
`;
1919

20+
exports[`vararg spread optimization With cast 1`] = `
21+
"local ____exports = {}
22+
function ____exports.__main(self)
23+
local function pick(self, ...)
24+
local args = {...}
25+
return args[2]
26+
end
27+
local function test(self, ...)
28+
return pick(nil, ...)
29+
end
30+
return test(nil, \\"a\\", \\"b\\", \\"c\\")
31+
end
32+
return ____exports"
33+
`;
34+
2035
exports[`vararg spread optimization basic use 1`] = `
2136
"local ____exports = {}
2237
function ____exports.__main(self)

test/unit/spread.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,18 @@ describe("vararg spread optimization", () => {
265265
.expectLuaToMatchSnapshot()
266266
.expectToMatchJsResult();
267267
});
268+
269+
test("With cast", () => {
270+
util.testFunction`
271+
function pick(...args: any[]) { return args[1]; }
272+
function test<F extends (...args: any)=>any>(...args: Parameters<F>) {
273+
return pick(...(args as any[]));
274+
}
275+
return test<(...args: string[])=>void>("a", "b", "c");
276+
`
277+
.expectLuaToMatchSnapshot()
278+
.expectToMatchJsResult();
279+
});
268280
});
269281

270282
describe("vararg spread de-optimization", () => {

0 commit comments

Comments
 (0)
X Tutup