Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/transformation/builtins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,10 @@ export function checkForLuaLibType(context: TransformationContext, type: ts.Type
}
}

function tryGetStandardLibrarySymbolOfType(context: TransformationContext, type: ts.Type): ts.Symbol | undefined {
export function tryGetStandardLibrarySymbolOfType(
context: TransformationContext,
type: ts.Type
): ts.Symbol | undefined {
if (type.isUnionOrIntersection()) {
for (const subType of type.types) {
const symbol = tryGetStandardLibrarySymbolOfType(context, subType);
Expand Down
4 changes: 4 additions & 0 deletions src/transformation/utils/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,7 @@ export const cannotAssignToNodeOfKind = createErrorDiagnosticFactory(
export const incompleteFieldDecoratorWarning = createWarningDiagnosticFactory(
"You are using a class field decorator, note that tstl ignores returned value initializers!"
);

export const unsupportedArrayWithLengthConstructor = createErrorDiagnosticFactory(
`Constructing new Array with length is not supported.`
);
28 changes: 27 additions & 1 deletion src/transformation/visitors/class/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,42 @@ import * as ts from "typescript";
import * as lua from "../../../LuaAST";
import { FunctionVisitor } from "../../context";
import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations";
import { annotationInvalidArgumentCount } from "../../utils/diagnostics";
import { annotationInvalidArgumentCount, unsupportedArrayWithLengthConstructor } from "../../utils/diagnostics";
import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib";
import { transformArguments, transformCallAndArguments } from "../call";
import { isTableNewCall } from "../language-extensions/table";
import { tryGetStandardLibrarySymbolOfType } from "../../builtins";

export const transformNewExpression: FunctionVisitor<ts.NewExpression> = (node, context) => {
if (isTableNewCall(context, node)) {
return lua.createTableExpression(undefined, node);
}

const constructorType = context.checker.getTypeAtLocation(node.expression);
if (tryGetStandardLibrarySymbolOfType(context, constructorType)?.name === "ArrayConstructor") {
if (node.arguments === undefined || node.arguments.length === 0) {
// turn new Array<>() into a simple {}
return lua.createTableExpression([], node);
} else {
// More than one argument, check if items constructor
const signature = context.checker.getResolvedSignature(node);
const signatureDeclaration = signature?.getDeclaration();
if (
signatureDeclaration?.parameters.length === 1 &&
signatureDeclaration.parameters[0].dotDotDotToken === undefined
) {
context.diagnostics.push(unsupportedArrayWithLengthConstructor(node));
return lua.createTableExpression([], node);
} else {
const callArguments = transformArguments(context, node.arguments, signature);
return lua.createTableExpression(
callArguments.map(e => lua.createTableFieldExpression(e)),
node
);
}
}
}

const signature = context.checker.getResolvedSignature(node);
const [name, params] = transformCallAndArguments(context, node.expression, node.arguments ?? [], signature);

Expand Down
33 changes: 32 additions & 1 deletion test/unit/builtins/array.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { undefinedInArrayLiteral } from "../../../src/transformation/utils/diagnostics";
import {
undefinedInArrayLiteral,
unsupportedArrayWithLengthConstructor,
} from "../../../src/transformation/utils/diagnostics";
import * as util from "../../util";

test("omitted expression", () => {
Expand Down Expand Up @@ -898,3 +901,31 @@ test("array indexing in optional chain (#1605)", () => {
.setOptions({ strict: true }) // crucial to reproducing for some reason
.expectToMatchJsResult();
});

test("new Array()", () => {
util.testFunction`
const arr = new Array();
arr.push(1,2,3);
return arr;
`
.debug()
.expectToMatchJsResult();
});

test("new Array<T>()", () => {
util.testFunction`
const arr = new Array<number>();
arr.push(1,2,3);
return arr;
`.expectToMatchJsResult();
});

test("new Array<T>(length)", () => {
util.testFunction`
const arr = new Array<string>(10);
`.expectToHaveDiagnostics([unsupportedArrayWithLengthConstructor.code]);
});

test("new Array<T>(...items)", () => {
util.testExpression`new Array(1,2,3,4,5) `.expectToMatchJsResult();
});
Loading