From bd87d2e61552e23e1f72ee372d6c4313c9aa750c Mon Sep 17 00:00:00 2001 From: GlassBricks <24237065+GlassBricks@users.noreply.github.com> Date: Sat, 20 Nov 2021 12:21:09 -0800 Subject: [PATCH 1/2] Nullish coalescing with preceding statements --- .../visitors/binary-expression/index.ts | 46 ++++++------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/src/transformation/visitors/binary-expression/index.ts b/src/transformation/visitors/binary-expression/index.ts index df4ef6434..330f51e7d 100644 --- a/src/transformation/visitors/binary-expression/index.ts +++ b/src/transformation/visitors/binary-expression/index.ts @@ -65,7 +65,7 @@ function transformBinaryOperationWithNoPrecedingStatements( if (operator === ts.SyntaxKind.QuestionQuestionToken) { assert(ts.isBinaryExpression(node)); - return transformNullishCoalescingExpression(context, node, left, right); + return transformNullishCoalescingOperationNoPrecedingStatements(context, node, left, right); } let luaOperator = simpleOperatorsToLua[operator]; @@ -138,21 +138,7 @@ function transformShortCircuitBinaryExpression( const [rightPrecedingStatements, rhs] = transformInPrecedingStatementScope(context, () => context.transformExpression(node.right) ); - if (rightPrecedingStatements.length > 0) { - return createShortCircuitBinaryExpressionPrecedingStatements( - context, - lhs, - rhs, - rightPrecedingStatements, - operator, - node - ); - } else { - return [ - rightPrecedingStatements, - transformBinaryOperationWithNoPrecedingStatements(context, lhs, rhs, operator, node), - ]; - } + return transformBinaryOperation(context, lhs, rhs, rightPrecedingStatements, operator, node); } export function transformBinaryOperation( @@ -274,7 +260,7 @@ export function transformBinaryExpressionStatement( } } -function transformNullishCoalescingExpression( +function transformNullishCoalescingOperationNoPrecedingStatements( context: TransformationContext, node: ts.BinaryExpression, transformedLeft: lua.Expression, @@ -287,23 +273,17 @@ function transformNullishCoalescingExpression( (type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Boolean)) !== 0 || (type.flags & ts.TypeFlags.BooleanLiteral & ts.TypeFlags.PossiblyFalsy) !== 0; if (typeCanSatisfy(context, lhsType, typeCanBeFalse)) { - // lhs can be false, transform to IIFE - const lhsIdentifier = lua.createIdentifier("____lhs"); - const nilComparison = lua.createBinaryExpression( - lua.cloneIdentifier(lhsIdentifier), - lua.createNilLiteral(), - lua.SyntaxKind.EqualityOperator - ); - // if ____ == nil then return rhs else return ____ end - const ifStatement = lua.createIfStatement( - nilComparison, - lua.createBlock([lua.createReturnStatement([transformedRight])]), - lua.createBlock([lua.createReturnStatement([lua.cloneIdentifier(lhsIdentifier)])]) - ); - // (function(lhs') if lhs' == nil then return rhs else return lhs' end)(lhs) - return lua.createCallExpression(lua.createFunctionExpression(lua.createBlock([ifStatement]), [lhsIdentifier]), [ + // reuse logic from case with preceding statements + const [precedingStatements, result] = createShortCircuitBinaryExpressionPrecedingStatements( + context, transformedLeft, - ]); + transformedRight, + [], + ts.SyntaxKind.QuestionQuestionToken, + node + ); + context.addPrecedingStatements(precedingStatements); + return result; } else { // lhs or rhs return lua.createBinaryExpression(transformedLeft, transformedRight, lua.SyntaxKind.OrOperator, node); From 26522268a7c5a168a2102a8e4125a573a6f3ae2b Mon Sep 17 00:00:00 2001 From: GlassBricks <24237065+GlassBricks@users.noreply.github.com> Date: Sat, 20 Nov 2021 12:28:05 -0800 Subject: [PATCH 2/2] Add test for #1165 --- test/unit/nullishCoalescing.spec.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/unit/nullishCoalescing.spec.ts b/test/unit/nullishCoalescing.spec.ts index 67dbc1cec..309e43732 100644 --- a/test/unit/nullishCoalescing.spec.ts +++ b/test/unit/nullishCoalescing.spec.ts @@ -40,3 +40,17 @@ test("nullish-coalescing operator with side effect rhs", () => { return [i, undefined ?? incI(), i]; `.expectToMatchJsResult(); }); + +test("nullish-coalescing operator with vararg", () => { + util.testFunction` + + function foo(...args: any[]){ + return args + } + function bar(...args: any[]) { + let x: boolean | undefined = false + const y = x ?? foo(...args) + } + return bar(1, 2) + `.expectToMatchJsResult(); +});