Skip to content
Closed
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
2 changes: 1 addition & 1 deletion src/lualib/Await.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function __TS__AsyncAwaiter(this: void, generator: (this: void) => void)
return __TS__Promise.resolve(result).addCallbacks(fulfilled, reject);
}

const [success, resultOrError] = coresume(asyncCoroutine, (v: unknown) => {
const [success, resultOrError] = coresume(asyncCoroutine, function (v: unknown) {
resolved = true;
return __TS__Promise.resolve(v).addCallbacks(resolve, reject);
});
Expand Down
7 changes: 1 addition & 6 deletions src/lualib/Promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,7 @@ export class __TS__Promise<T> implements Promise<T> {

constructor(executor: PromiseExecutor<T>) {
// Avoid unnecessary local functions allocations by using `pcall` explicitly
const [success, error] = pcall(
executor,
undefined,
v => this.resolve(v),
err => this.reject(err)
);
const [success, error] = pcall(executor, undefined, this.resolve.bind(this), this.reject.bind(this));
if (!success) {
// When a promise executor throws, the promise should be rejected with the thrown object as reason
this.reject(error);
Expand Down
7 changes: 1 addition & 6 deletions src/transformation/builtins/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as ts from "typescript";
import { LuaTarget } from "../../CompilerOptions";
import * as lua from "../../LuaAST";
import { TransformationContext } from "../context";
import { unsupportedForTarget, unsupportedProperty, unsupportedSelfFunctionConversion } from "../utils/diagnostics";
import { unsupportedForTarget, unsupportedProperty } from "../utils/diagnostics";
import { ContextType, getFunctionContextType } from "../utils/function-context";
import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib";
import { transformCallAndArguments } from "../visitors/call";
Expand All @@ -13,11 +13,6 @@ export function transformFunctionPrototypeCall(
node: ts.CallExpression,
calledMethod: ts.PropertyAccessExpression
): lua.CallExpression | undefined {
const callerType = context.checker.getTypeAtLocation(calledMethod.expression);
if (getFunctionContextType(context, callerType) === ContextType.Void) {
context.diagnostics.push(unsupportedSelfFunctionConversion(node));
}

const signature = context.checker.getResolvedSignature(node);
const [caller, params] = transformCallAndArguments(context, calledMethod.expression, node.arguments, signature);
const expressionName = calledMethod.name.text;
Expand Down
9 changes: 8 additions & 1 deletion src/transformation/utils/function-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as ts from "typescript";
import { CompilerOptions } from "../../CompilerOptions";
import { TransformationContext } from "../context";
import { AnnotationKind, getFileAnnotations, getNodeAnnotations } from "./annotations";
import { findFirstNodeAbove, getAllCallSignatures, inferAssignedType } from "./typescript";
import { findFirstNodeAbove, findFirstNonOuterParent, getAllCallSignatures, inferAssignedType } from "./typescript";

export enum ContextType {
None = 0,
Expand Down Expand Up @@ -118,6 +118,13 @@ function computeDeclarationContextType(context: TransformationContext, signature
return ContextType.Void;
}

if (
ts.isArrowFunction(signatureDeclaration) &&
ts.isCallExpression(findFirstNonOuterParent(signatureDeclaration))
) {
return ContextType.Void;
}

if (
ts.isMethodSignature(signatureDeclaration) ||
ts.isMethodDeclaration(signatureDeclaration) ||
Expand Down
11 changes: 8 additions & 3 deletions test/unit/functions/validation/functionPermutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,13 +351,18 @@ const noSelfInFileTestFunctions: TestFunction[] = [
},
];

export const anonTestFunctionExpressions: TestFunction[] = [
{ value: "s => s" },
{ value: "(s => s)" },
export const anonArrowFunctionExpressions: TestFunction[] = [{ value: "s => s" }, { value: "(s => s)" }];

export const anonNonArrowFunctionExpressions: TestFunction[] = [
{ value: "function(s) { return s; }" },
{ value: "(function(s) { return s; })" },
];

export const anonTestFunctionExpressions: TestFunction[] = [
...anonArrowFunctionExpressions,
...anonNonArrowFunctionExpressions,
];

export const selfTestFunctionExpressions: TestFunction[] = [
{ value: "function(this: any, s) { return s; }" },
{ value: "(function(this: any, s) { return s; })" },
Expand Down
41 changes: 37 additions & 4 deletions test/unit/functions/validation/validFunctionAssignments.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as util from "../../../util";
import {
anonTestFunctionExpressions,
anonArrowFunctionExpressions,
anonNonArrowFunctionExpressions,
anonTestFunctionType,
noSelfTestFunctionExpressions,
noSelfTestFunctions,
Expand Down Expand Up @@ -133,10 +134,10 @@ test.each([
});

test.each([
...anonTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]),
...selfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]),
...anonNonArrowFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["'context'", "'foobar'"]]),
...selfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["'context'", "'foobar'"]]),
...noSelfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["'foobar'"]]),
])("Valid function expression argument with no signature (%p, %p)", (testFunction, args) => {
])("Valid function expression argument with no signature have context (%p, %p)", (testFunction, args) => {
util.testFunction`
const takesFunction: any = (fn: (this: void, ...args: any[]) => any, ...args: any[]) => {
return fn(...args);
Expand All @@ -147,6 +148,20 @@ test.each([
.expectToEqual("foobar");
});

test.each([...anonArrowFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["'foobar'"]])])(
"Valid arrow function expression argument with no signature do not have context (%p, %p)",
(testFunction, args) => {
util.testFunction`
const takesFunction: any = (fn: (this: void, ...args: any[]) => any, ...args: any[]) => {
return fn(...args);
}
return takesFunction(${testFunction.value}, ${args.join(", ")});
`
.setTsHeader(testFunction.definition ?? "")
.expectToEqual("foobar");
}
);

test.each(validTestFunctionAssignments)("Valid function return (%p)", (testFunction, functionType) => {
util.testFunction`
function returnsFunction(): ${functionType} {
Expand Down Expand Up @@ -248,3 +263,21 @@ test("Does not fail on union type signatures (#896)", () => {
)
.expectToHaveNoDiagnostics();
});

// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1568
test("No false positives when using generic functions (#1568)", () => {
util.testModule`
/** @noSelf */
declare namespace Test {
export function testCallback<T extends (...args: any[]) => void>(
callback: T,
): void;
export function testCallback2(
callback: (...args: any[]) => void,
): void;
}

Test.testCallback(() => {});
Test.testCallback2(() => {});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`.expectToHaveNoDiagnostics();
});