Skip to content

Commit 0d22c0d

Browse files
authored
Vararg Update (#992)
* wip vararg extension * vararg spread optimization working with handling for hoisting * refactoring and tests * deprecation test * updates from feedback * clarity for isOptimizableVarargSpread Co-authored-by: Tom <tomblind@users.noreply.github.com>
1 parent b84686f commit 0d22c0d

File tree

34 files changed

+914
-172
lines changed

34 files changed

+914
-172
lines changed

language-extensions/index.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ declare type LuaMultiReturn<T extends any[]> = T & LuaExtension<"__luaMultiRetur
3434
declare const $range: ((start: number, limit: number, step?: number) => Iterable<number>) &
3535
LuaExtension<"__luaRangeFunctionBrand">;
3636

37+
/**
38+
* Transpiles to the global vararg (`...`)
39+
* For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions
40+
*/
41+
declare const $vararg: string[] & LuaExtension<"__luaVarargConstantBrand">;
42+
3743
/**
3844
* Represents a Lua-style iterator which is returned from a LuaIterable.
3945
* For simple iterators (with no state), this is just a function.

src/lualib/ArrayReduce.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ function __TS__ArrayReduce<T>(
33
this: void,
44
arr: T[],
55
callbackFn: (accumulator: T, currentValue: T, index: number, array: T[]) => T,
6-
...initial: Vararg<T[]>
6+
...initial: T[]
77
): T {
88
const len = arr.length;
99

src/lualib/ArrayReduceRight.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ function __TS__ArrayReduceRight<T>(
33
this: void,
44
arr: T[],
55
callbackFn: (accumulator: T, currentValue: T, index: number, array: T[]) => T,
6-
...initial: Vararg<T[]>
6+
...initial: T[]
77
): T {
88
const len = arr.length;
99

src/lualib/ArraySplice.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.splice
2-
function __TS__ArraySplice<T>(this: void, list: T[], ...args: Vararg<unknown[]>): T[] {
2+
function __TS__ArraySplice<T>(this: void, list: T[], ...args: unknown[]): T[] {
33
const len = list.length;
44

55
const actualArgumentCount = select("#", ...args);

src/lualib/Generator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function __TS__GeneratorIterator(this: GeneratorIterator) {
88
return this;
99
}
1010

11-
function __TS__GeneratorNext(this: GeneratorIterator, ...args: Vararg<any[]>) {
11+
function __TS__GeneratorNext(this: GeneratorIterator, ...args: any[]) {
1212
const co = this.____coroutine;
1313
if (coroutine.status(co) === "dead") return { done: true };
1414

@@ -19,7 +19,7 @@ function __TS__GeneratorNext(this: GeneratorIterator, ...args: Vararg<any[]>) {
1919
}
2020

2121
function __TS__Generator(this: void, fn: (this: void, ...args: any[]) => any) {
22-
return function (this: void, ...args: Vararg<any[]>): GeneratorIterator {
22+
return function (this: void, ...args: any[]): GeneratorIterator {
2323
const argsLength = select("#", ...args);
2424
return {
2525
// Using explicit this there, since we don't pass arguments after the first nil and context is likely to be nil

src/lualib/New.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function __TS__New(this: void, target: LuaClass, ...args: Vararg<any[]>): any {
1+
function __TS__New(this: void, target: LuaClass, ...args: any[]): any {
22
const instance: any = setmetatable({}, target.prototype);
33
instance.____constructor(...args);
44
return instance;

src/lualib/declarations/tstl.d.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
/** @noSelfInFile */
22

3-
/** @vararg */
4-
type Vararg<T extends unknown[]> = T & { __luaVararg?: never };
5-
63
interface Metatable {
74
_descriptors?: Record<string, PropertyDescriptor>;
85
__index?: any;

src/transformation/utils/diagnostics.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ export const invalidForRangeCall = createErrorDiagnosticFactory(
6464

6565
export const invalidRangeUse = createErrorDiagnosticFactory("$range can only be used in a for...of loop.");
6666

67+
export const invalidVarargUse = createErrorDiagnosticFactory(
68+
"$vararg can only be used in a spread element ('...$vararg') in global scope."
69+
);
70+
6771
export const invalidRangeControlVariable = createErrorDiagnosticFactory(
6872
"For loop using $range must declare a single control variable."
6973
);

src/transformation/utils/language-extensions.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export enum ExtensionKind {
55
MultiFunction = "MultiFunction",
66
MultiType = "MultiType",
77
RangeFunction = "RangeFunction",
8+
VarargConstant = "VarargConstant",
89
IterableType = "IterableType",
910
AdditionOperatorType = "AdditionOperatorType",
1011
AdditionOperatorMethodType = "AdditionOperatorMethodType",
@@ -49,15 +50,17 @@ export enum ExtensionKind {
4950
TableSetMethodType = "TableSetMethodType",
5051
}
5152

52-
const extensionKindToFunctionName: { [T in ExtensionKind]?: string } = {
53+
const extensionKindToValueName: { [T in ExtensionKind]?: string } = {
5354
[ExtensionKind.MultiFunction]: "$multi",
5455
[ExtensionKind.RangeFunction]: "$range",
56+
[ExtensionKind.VarargConstant]: "$vararg",
5557
};
5658

5759
const extensionKindToTypeBrand: { [T in ExtensionKind]: string } = {
5860
[ExtensionKind.MultiFunction]: "__luaMultiFunctionBrand",
5961
[ExtensionKind.MultiType]: "__luaMultiReturnBrand",
6062
[ExtensionKind.RangeFunction]: "__luaRangeFunctionBrand",
63+
[ExtensionKind.VarargConstant]: "__luaVarargConstantBrand",
6164
[ExtensionKind.IterableType]: "__luaIterableBrand",
6265
[ExtensionKind.AdditionOperatorType]: "__luaAdditionBrand",
6366
[ExtensionKind.AdditionOperatorMethodType]: "__luaAdditionMethodBrand",
@@ -107,13 +110,13 @@ export function isExtensionType(type: ts.Type, extensionKind: ExtensionKind): bo
107110
return typeBrand !== undefined && type.getProperty(typeBrand) !== undefined;
108111
}
109112

110-
export function isExtensionFunction(
113+
export function isExtensionValue(
111114
context: TransformationContext,
112115
symbol: ts.Symbol,
113116
extensionKind: ExtensionKind
114117
): boolean {
115118
return (
116-
symbol.getName() === extensionKindToFunctionName[extensionKind] &&
119+
symbol.getName() === extensionKindToValueName[extensionKind] &&
117120
symbol.declarations.some(d => isExtensionType(context.checker.getTypeAtLocation(d), extensionKind))
118121
);
119122
}

src/transformation/utils/lua-ast.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ export function getNumberLiteralValue(expression?: lua.Expression) {
6262
return undefined;
6363
}
6464

65+
// Prefer use of transformToImmediatelyInvokedFunctionExpression to maintain correct scope. If you use this directly,
66+
// ensure you push/pop a function scope appropriately to avoid incorrect vararg optimization.
6567
export function createImmediatelyInvokedFunctionExpression(
6668
statements: lua.Statement[],
6769
result: lua.Expression | lua.Expression[],

0 commit comments

Comments
 (0)