From 70176dfacc0cc8cc4d5aa7f7e96b09deb44ee1fc Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 30 Dec 2016 14:57:59 +0300 Subject: [PATCH] JS: translate call arguments in the order the occur in source code, not in order of parameters in descriptor. See KT-15506 --- .../codegen/box/argumentOrder/arguments.kt | 3 - .../codegen/box/argumentOrder/captured.kt | 3 - .../codegen/box/argumentOrder/simple.kt | 3 - .../box/argumentOrder/simpleInClass.kt | 3 - .../box/intrinsics/throwableParamOrder.kt | 3 - .../semantics/JsCodegenBoxTestGenerated.java | 40 +--- .../declaration/PropertyTranslator.kt | 22 ++- .../operation/IncrementTranslator.java | 32 ++- .../reference/CallArgumentTranslator.kt | 187 ++++++++---------- .../js/translate/utils/TranslationUtils.java | 27 ++- 10 files changed, 161 insertions(+), 162 deletions(-) diff --git a/compiler/testData/codegen/box/argumentOrder/arguments.kt b/compiler/testData/codegen/box/argumentOrder/arguments.kt index 11146076909..f3d4d9b9b33 100644 --- a/compiler/testData/codegen/box/argumentOrder/arguments.kt +++ b/compiler/testData/codegen/box/argumentOrder/arguments.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - fun test(a: String, b: String): String { return a + b; diff --git a/compiler/testData/codegen/box/argumentOrder/captured.kt b/compiler/testData/codegen/box/argumentOrder/captured.kt index 35d8c0e02b7..f4f35913a07 100644 --- a/compiler/testData/codegen/box/argumentOrder/captured.kt +++ b/compiler/testData/codegen/box/argumentOrder/captured.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - fun box(): String { var invokeOrder = ""; val expectedResult = "0_1_9" diff --git a/compiler/testData/codegen/box/argumentOrder/simple.kt b/compiler/testData/codegen/box/argumentOrder/simple.kt index 60f7f292cbf..112891c4d9a 100644 --- a/compiler/testData/codegen/box/argumentOrder/simple.kt +++ b/compiler/testData/codegen/box/argumentOrder/simple.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - fun box(): String { var res = ""; var call = test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}(), c = {res += "L"; "L"}) diff --git a/compiler/testData/codegen/box/argumentOrder/simpleInClass.kt b/compiler/testData/codegen/box/argumentOrder/simpleInClass.kt index faa071bc275..71bc1f7452c 100644 --- a/compiler/testData/codegen/box/argumentOrder/simpleInClass.kt +++ b/compiler/testData/codegen/box/argumentOrder/simpleInClass.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - fun box(): String { var res = ""; var call = Z("Z").test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}(), c = {res += "L"; "L"}) diff --git a/compiler/testData/codegen/box/intrinsics/throwableParamOrder.kt b/compiler/testData/codegen/box/intrinsics/throwableParamOrder.kt index 04ce96e10ae..7708a6de220 100644 --- a/compiler/testData/codegen/box/intrinsics/throwableParamOrder.kt +++ b/compiler/testData/codegen/box/intrinsics/throwableParamOrder.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - var res = "" fun getM(): String { diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 6f53a609726..de6d9d64231 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -323,25 +323,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("arguments.kt") public void testArguments() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/arguments.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("captured.kt") public void testCaptured() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/captured.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("capturedInExtension.kt") @@ -413,25 +401,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("simple.kt") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/simple.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("simpleInClass.kt") public void testSimpleInClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } } @@ -9900,13 +9876,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("throwableParamOrder.kt") public void testThrowableParamOrder() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/intrinsics/throwableParamOrder.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("tostring.kt") diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt index 1481f30d7f3..8d1103960e3 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.translate.declaration import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator import org.jetbrains.kotlin.js.translate.context.Namer @@ -100,7 +101,10 @@ class DefaultPropertyTranslator( function: JsFunction ) { val host = translateHost(getterDescriptor, function) - val delegateContext = context().contextWithPropertyMetadataCreationIntrinsified(delegatedCall, descriptor, host) + val delegateContext = context() + .newDeclarationIfNecessary(getterDescriptor, function) + .contextWithPropertyMetadataCreationIntrinsified(delegatedCall, descriptor, host) + val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference) val returnResult = JsReturn(delegatedJsCall) @@ -116,7 +120,9 @@ class DefaultPropertyTranslator( if (delegatedCall != null) { val host = translateHost(setterDescriptor, function) - val delegateContext = withAliased.contextWithPropertyMetadataCreationIntrinsified(delegatedCall, descriptor, host) + val delegateContext = withAliased + .newDeclarationIfNecessary(setterDescriptor, function) + .contextWithPropertyMetadataCreationIntrinsified(delegatedCall, descriptor, host) val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference) function.addStatement(delegatedJsCall.makeStmt()) } @@ -128,6 +134,18 @@ class DefaultPropertyTranslator( } } + private fun TranslationContext.newDeclarationIfNecessary( + descriptor: VariableAccessorDescriptor, + function: JsFunction + ): TranslationContext { + return if (descriptor.correspondingVariable !is LocalVariableDescriptor) { + newDeclaration(descriptor) + } + else { + innerBlock(function.body) + } + } + private fun translateHost(accessorDescriptor: VariableAccessorDescriptor, function: JsFunction): JsExpression { return if (accessorDescriptor.isExtension) { function.addParameter(getReceiverParameterName(), 0).name.makeRef() diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IncrementTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IncrementTranslator.java index c80b0adf793..d806093c89c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IncrementTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IncrementTranslator.java @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.translate.operation; import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation; import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator; +import org.jetbrains.kotlin.js.backend.ast.JsBlock; import org.jetbrains.kotlin.js.backend.ast.JsExpression; import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties; import org.jetbrains.kotlin.js.util.AstUtil; @@ -28,6 +29,7 @@ import org.jetbrains.kotlin.js.translate.context.TemporaryVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.reference.AccessTranslator; +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtUnaryExpression; import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt; @@ -64,12 +66,15 @@ public abstract class IncrementTranslator extends AbstractTranslator { @NotNull protected final AccessTranslator accessTranslator; + @NotNull + private final JsBlock accessBlock = new JsBlock(); + protected IncrementTranslator(@NotNull KtUnaryExpression expression, @NotNull TranslationContext context) { super(context); this.expression = expression; KtExpression baseExpression = getBaseExpression(expression); - this.accessTranslator = getAccessTranslator(baseExpression, context()).getCached(); + this.accessTranslator = getAccessTranslator(baseExpression, context().innerBlock(accessBlock)).getCached(); } @NotNull @@ -87,8 +92,17 @@ public abstract class IncrementTranslator extends AbstractTranslator { // generate: expr(a = a.inc(), a) JsExpression getExpression = accessTranslator.translateAsGet(); JsExpression reassignment = variableReassignment(getExpression); + accessBlock.getStatements().add(JsAstUtils.asSyntheticStatement(reassignment)); JsExpression getNewValue = accessTranslator.translateAsGet(); - JsExpression result = new JsBinaryOperation(JsBinaryOperator.COMMA, reassignment, getNewValue); + + JsExpression result; + if (accessBlock.getStatements().size() == 1) { + result = new JsBinaryOperation(JsBinaryOperator.COMMA, reassignment, getNewValue); + } + else { + context().getCurrentBlock().getStatements().addAll(accessBlock.getStatements()); + result = getNewValue; + } MetadataProperties.setSynthetic(result, true); return result; } @@ -99,8 +113,19 @@ public abstract class IncrementTranslator extends AbstractTranslator { // code fragment: expr(a++) // generate: expr( (t1 = a, t2 = t1, a = t1.inc(), t2) ) TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet()); + accessBlock.getStatements().add(t1.assignmentStatement()); JsExpression variableReassignment = variableReassignment(t1.reference()); - JsExpression result = AstUtil.newSequence(t1.assignmentExpression(), variableReassignment, t1.reference()); + accessBlock.getStatements().add(JsAstUtils.asSyntheticStatement(variableReassignment)); + + JsExpression result; + if (accessBlock.getStatements().size() == 2) { + result = AstUtil.newSequence(t1.assignmentExpression(), variableReassignment, t1.reference()); + } + else { + context().getCurrentBlock().getStatements().addAll(accessBlock.getStatements()); + result = t1.reference(); + } + MetadataProperties.setSynthetic(result, true); return result; } @@ -116,6 +141,7 @@ public abstract class IncrementTranslator extends AbstractTranslator { private static boolean isDynamic(TranslationContext context, KtUnaryExpression expression) { CallableDescriptor operationDescriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression); + assert operationDescriptor != null; return DynamicCallsKt.isDynamic(operationDescriptor); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt index 0855b9f462f..aa07dc995ff 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.js.translate.reference import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects -import com.intellij.util.SmartList import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.js.backend.ast.* @@ -78,20 +77,16 @@ class CallArgumentTranslator private constructor( val valueArgumentsByIndex = resolvedCall.valueArgumentsByIndex ?: throw IllegalStateException( "Failed to arrange value arguments by index: " + resolvedCall.resultingDescriptor) var argsBeforeVararg: List? = null - var argumentsShouldBeExtractedToTmpVars = false - val argContexts = SmartList() var concatArguments: MutableList? = null + val argsToJsExpr = translateUnresolvedArguments(context(), resolvedCall) for (parameterDescriptor in valueParameters) { val actualArgument = valueArgumentsByIndex[parameterDescriptor.index] - val argContext = context().innerBlock() - if (actualArgument is VarargValueArgument) { val arguments = actualArgument.getArguments() - val size = arguments.size if (!hasSpreadOperator) { hasSpreadOperator = arguments.any { it.getSpreadElement() != null } } @@ -99,35 +94,25 @@ class CallArgumentTranslator private constructor( if (hasSpreadOperator) { if (isNativeFunctionCall) { argsBeforeVararg = result - result = SmartList() - val list = SmartList() - translateValueArguments(arguments, list, argContext) - concatArguments = prepareConcatArguments(arguments, list) + result = mutableListOf() + concatArguments = prepareConcatArguments(arguments, translateResolvedArgument(actualArgument, argsToJsExpr)) } else { - translateVarargArgument(arguments, result, argContext, size > 1) + result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, actualArgument.arguments.size > 1)) } } else { if (isNativeFunctionCall) { - translateValueArguments(arguments, result, argContext) + result.addAll(translateResolvedArgument(actualArgument, argsToJsExpr)) } else { - translateVarargArgument(arguments, result, argContext, true) + result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, true)) } } } else { - translateSingleArgument(parameterDescriptor, actualArgument, result, argContext) + result.addAll(translateResolvedArgument(actualArgument, argsToJsExpr)) } - - context().moveVarsFrom(argContext) - argContexts.add(argContext) - argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty() - } - - if (argumentsShouldBeExtractedToTmpVars) { - extractArguments(result, argContexts, context()) } if (isNativeFunctionCall && hasSpreadOperator) { @@ -140,7 +125,7 @@ class CallArgumentTranslator private constructor( concatArguments.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) } - result = SmartList(concatArgumentsIfNeeded(concatArguments)) + result = mutableListOf(concatArgumentsIfNeeded(concatArguments)) if (receiver != null) { cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver) @@ -162,6 +147,54 @@ class CallArgumentTranslator private constructor( return ArgumentsInfo(result, hasSpreadOperator, cachedReceiver) } + private fun translateUnresolvedArguments( + context: TranslationContext, + resolvedCall: ResolvedCall<*> + ): Map { + val argsToParameters = resolvedCall.valueArguments + .flatMap { (param, args) -> args.arguments.map { param to it } } + .associate { (param, arg) -> arg to param } + + val argumentContexts = resolvedCall.call.valueArguments.associate { it to context.innerBlock() } + + var result = resolvedCall.call.valueArguments.associate { arg -> + val argumentContext = argumentContexts[arg]!! + val argumentExpression = KtPsiUtil.deparenthesize(arg.getArgumentExpression()) + + val lambdaDescriptor = argumentExpression?.let { argumentContext.extractLambda(it) } + val jsExpr = if (lambdaDescriptor?.isSuspendLambda == true) { + val lambdaExpression = (argumentExpression as KtLambdaExpression).functionLiteral + val param = argsToParameters[arg]!! + LiteralFunctionTranslator(argumentContext).translate(lambdaExpression, param.type) + } + else { + Translation.translateAsExpression(arg.getArgumentExpression()!!, argumentContext) + } + + arg to jsExpr + } + + val resolvedOrder = resolvedCall.valueArgumentsByIndex.orEmpty() + .flatMap { it.arguments } + .withIndex() + .associate { (index, arg) -> arg to index } + val argumentsAreOrdered = resolvedCall.call.valueArguments.withIndex().none { (index, arg) -> resolvedOrder[arg] != index } + + if (argumentContexts.values.any { !it.currentBlockIsEmpty() } || !argumentsAreOrdered) { + result = result.map { (arg, expr) -> + val argumentContext = argumentContexts[arg]!! + arg to argumentContext.cacheExpressionIfNeeded(expr) + }.toMap() + } + + argumentContexts.values.forEach { + context.moveVarsFrom(it) + context.addStatementsToCurrentBlockFrom(it) + } + + return result + } + companion object { @JvmStatic fun translate(resolvedCall: ResolvedCall<*>, receiver: JsExpression?, context: TranslationContext): ArgumentsInfo { @@ -184,33 +217,12 @@ class CallArgumentTranslator private constructor( return result } - private fun translateSingleArgument( - parameterDescriptor: ValueParameterDescriptor, - actualArgument: ResolvedValueArgument, - result: MutableList, - context: TranslationContext - ) { - val valueArguments = actualArgument.arguments - - if (actualArgument is DefaultValueArgument) { - result += Namer.getUndefinedExpression() - return - } - - assert(actualArgument is ExpressionValueArgument) - assert(valueArguments.size == 1) - - val parenthesizedArgumentExpression = valueArguments[0].getArgumentExpression()!! - val argumentExpression = KtPsiUtil.deparenthesize(parenthesizedArgumentExpression) - - val lambdaDescriptor = argumentExpression?.let { context.extractLambda(it) } - if (lambdaDescriptor?.isSuspendLambda == true) { - val lambdaExpression = (argumentExpression as KtLambdaExpression).functionLiteral - result += LiteralFunctionTranslator(context).translate(lambdaExpression, parameterDescriptor.type) - } - else { - result += Translation.translateAsExpression(parenthesizedArgumentExpression, context) - } + private fun translateResolvedArgument( + resolvedArgument: ResolvedValueArgument, + translatedArgs: Map + ): List { + if (resolvedArgument is DefaultValueArgument) return listOf(Namer.getUndefinedExpression()) + return resolvedArgument.arguments.map { translatedArgs[it]!! } } private fun TranslationContext.extractLambda(expression: KtExpression): CallableDescriptor? { @@ -218,49 +230,30 @@ class CallArgumentTranslator private constructor( return BindingUtils.getFunctionDescriptor(bindingContext(), lambdaExpression.functionLiteral) } - private fun translateVarargArgument(arguments: List, result: MutableList, - context: TranslationContext, shouldWrapVarargInArray: Boolean) { + private fun translateVarargArgument( + resolvedArgument: ResolvedValueArgument, + translatedArgs: Map, + shouldWrapVarargInArray: Boolean + ): List { + val arguments = resolvedArgument.arguments if (arguments.isEmpty()) { - if (shouldWrapVarargInArray) { - result.add(JsArrayLiteral(listOf()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) + return if (shouldWrapVarargInArray) { + return listOf(JsArrayLiteral(listOf()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) + } + else { + listOf() } - return } - val list: MutableList = if (shouldWrapVarargInArray) { - if (arguments.size == 1) SmartList() else ArrayList(arguments.size) - } - else { - result - } + val list = translateResolvedArgument(resolvedArgument, translatedArgs) - translateValueArguments(arguments, list, context) - - if (shouldWrapVarargInArray) { + return if (shouldWrapVarargInArray) { val concatArguments = prepareConcatArguments(arguments, list) val concatExpression = concatArgumentsIfNeeded(concatArguments) - result.add(concatExpression) + listOf(concatExpression) } - else if (result.size == 1) { - result[0] = JsAstUtils.invokeMethod(result[0], "slice") - } - } - - private fun translateValueArguments(arguments: List, list: MutableList, - context: TranslationContext) { - val argContexts = SmartList() - var argumentsShouldBeExtractedToTmpVars = false - for (argument in arguments) { - val argumentExpression = argument.getArgumentExpression()!! - val argContext = context.innerBlock() - val argExpression = Translation.translateAsExpression(argumentExpression, argContext) - list.add(argExpression) - context.moveVarsFrom(argContext) - argContexts.add(argContext) - argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty() - } - if (argumentsShouldBeExtractedToTmpVars) { - extractArguments(list, argContexts, context) + else { + listOf(JsAstUtils.invokeMethod(list[0], "slice")) } } @@ -280,8 +273,8 @@ class CallArgumentTranslator private constructor( assert(arguments.isNotEmpty()) { "arguments.size should not be 0" } assert(arguments.size == list.size) { "arguments.size: " + arguments.size + " != list.size: " + list.size } - val concatArguments = SmartList() - var lastArrayContent: MutableList = SmartList() + val concatArguments = mutableListOf() + var lastArrayContent = mutableListOf() val size = arguments.size for (index in 0..size - 1) { @@ -292,7 +285,7 @@ class CallArgumentTranslator private constructor( if (lastArrayContent.size > 0) { concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) concatArguments.add(expressionArgument) - lastArrayContent = SmartList() + lastArrayContent = mutableListOf() } else { concatArguments.add(expressionArgument) @@ -308,27 +301,11 @@ class CallArgumentTranslator private constructor( return concatArguments } - - private fun extractArguments(argExpressions: MutableList, argContexts: List, - context: TranslationContext) { - for (i in argExpressions.indices) { - val argContext = argContexts[i] - val jsArgExpression = argExpressions[i] - if (argContext.currentBlockIsEmpty() && TranslationUtils.isCacheNeeded(jsArgExpression)) { - argExpressions[i] = context.defineTemporary(jsArgExpression) - } - else { - context.addStatementsToCurrentBlockFrom(argContext) - } - } - } } - } fun Map.buildReifiedTypeArgs(context: TranslationContext): List { - - val reifiedTypeArguments = SmartList() + val reifiedTypeArguments = mutableListOf() val patternTranslator = PatternTranslator.newInstance(context) for (param in keys.sortedBy { it.index }) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index b1832b2ecea..74ca7eedbd1 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -259,8 +259,31 @@ public final class TranslationUtils { } public static boolean isCacheNeeded(@NotNull JsExpression expression) { - return !(expression instanceof JsLiteral.JsValueLiteral) && - (!(expression instanceof JsNameRef) || ((JsNameRef) expression).getQualifier() != null); + if (expression instanceof JsLiteral.JsValueLiteral) return false; + if (expression instanceof JsNameRef && ((JsNameRef) expression).getQualifier() == null) return false; + if (expression instanceof JsBinaryOperation) { + JsBinaryOperation operation = (JsBinaryOperation) expression; + JsBinaryOperator operator = operation.getOperator(); + if (operator.isAssignment() || operator == COMMA) return true; + return isCacheNeeded(operation.getArg1()) || isCacheNeeded(operation.getArg2()); + } + if (expression instanceof JsUnaryOperation) { + JsUnaryOperation operation = (JsUnaryOperation) expression; + JsUnaryOperator operator = operation.getOperator(); + switch (operator) { + case BIT_NOT: + case NEG: + case POS: + case NOT: + case TYPEOF: + case VOID: + return isCacheNeeded(operation.getArg()); + default: + return true; + } + } + + return true; } @NotNull