JS: translate call arguments in the order the occur in source code, not in order of parameters in descriptor. See KT-15506
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"})
|
||||
|
||||
@@ -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"})
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
var res = ""
|
||||
|
||||
fun getM(): String {
|
||||
|
||||
+5
-35
@@ -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")
|
||||
|
||||
+20
-2
@@ -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()
|
||||
|
||||
+29
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+82
-105
@@ -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<JsExpression>? = null
|
||||
var argumentsShouldBeExtractedToTmpVars = false
|
||||
val argContexts = SmartList<TranslationContext>()
|
||||
var concatArguments: MutableList<JsExpression>? = 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<JsExpression>()
|
||||
val list = SmartList<JsExpression>()
|
||||
translateValueArguments(arguments, list, argContext)
|
||||
concatArguments = prepareConcatArguments(arguments, list)
|
||||
result = mutableListOf<JsExpression>()
|
||||
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<ValueArgument, JsExpression> {
|
||||
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<JsExpression>,
|
||||
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<ValueArgument, JsExpression>
|
||||
): List<JsExpression> {
|
||||
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<ValueArgument>, result: MutableList<JsExpression>,
|
||||
context: TranslationContext, shouldWrapVarargInArray: Boolean) {
|
||||
private fun translateVarargArgument(
|
||||
resolvedArgument: ResolvedValueArgument,
|
||||
translatedArgs: Map<ValueArgument, JsExpression>,
|
||||
shouldWrapVarargInArray: Boolean
|
||||
): List<JsExpression> {
|
||||
val arguments = resolvedArgument.arguments
|
||||
if (arguments.isEmpty()) {
|
||||
if (shouldWrapVarargInArray) {
|
||||
result.add(JsArrayLiteral(listOf<JsExpression>()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
|
||||
return if (shouldWrapVarargInArray) {
|
||||
return listOf(JsArrayLiteral(listOf<JsExpression>()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
|
||||
}
|
||||
else {
|
||||
listOf()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val list: MutableList<JsExpression> = if (shouldWrapVarargInArray) {
|
||||
if (arguments.size == 1) SmartList<JsExpression>() else ArrayList<JsExpression>(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<ValueArgument>, list: MutableList<JsExpression>,
|
||||
context: TranslationContext) {
|
||||
val argContexts = SmartList<TranslationContext>()
|
||||
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<JsExpression>()
|
||||
var lastArrayContent: MutableList<JsExpression> = SmartList()
|
||||
val concatArguments = mutableListOf<JsExpression>()
|
||||
var lastArrayContent = mutableListOf<JsExpression>()
|
||||
|
||||
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<JsExpression>()
|
||||
lastArrayContent = mutableListOf<JsExpression>()
|
||||
}
|
||||
else {
|
||||
concatArguments.add(expressionArgument)
|
||||
@@ -308,27 +301,11 @@ class CallArgumentTranslator private constructor(
|
||||
|
||||
return concatArguments
|
||||
}
|
||||
|
||||
private fun extractArguments(argExpressions: MutableList<JsExpression>, argContexts: List<TranslationContext>,
|
||||
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<TypeParameterDescriptor, KotlinType>.buildReifiedTypeArgs(context: TranslationContext): List<JsExpression> {
|
||||
|
||||
val reifiedTypeArguments = SmartList<JsExpression>()
|
||||
val reifiedTypeArguments = mutableListOf<JsExpression>()
|
||||
val patternTranslator = PatternTranslator.newInstance(context)
|
||||
|
||||
for (param in keys.sortedBy { it.index }) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user