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 {
|
fun test(a: String, b: String): String {
|
||||||
return a + b;
|
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 {
|
fun box(): String {
|
||||||
var invokeOrder = "";
|
var invokeOrder = "";
|
||||||
val expectedResult = "0_1_9"
|
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 {
|
fun box(): String {
|
||||||
var res = "";
|
var res = "";
|
||||||
var call = test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}(), c = {res += "L"; "L"})
|
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 {
|
fun box(): String {
|
||||||
var res = "";
|
var res = "";
|
||||||
var call = Z("Z").test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}(), c = {res += "L"; "L"})
|
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 = ""
|
var res = ""
|
||||||
|
|
||||||
fun getM(): String {
|
fun getM(): String {
|
||||||
|
|||||||
+5
-35
@@ -323,25 +323,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("arguments.kt")
|
@TestMetadata("arguments.kt")
|
||||||
public void testArguments() throws Exception {
|
public void testArguments() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/arguments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/arguments.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("captured.kt")
|
@TestMetadata("captured.kt")
|
||||||
public void testCaptured() throws Exception {
|
public void testCaptured() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/captured.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/captured.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("capturedInExtension.kt")
|
@TestMetadata("capturedInExtension.kt")
|
||||||
@@ -413,25 +401,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/simple.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("simpleInClass.kt")
|
@TestMetadata("simpleInClass.kt")
|
||||||
public void testSimpleInClass() throws Exception {
|
public void testSimpleInClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/simpleInClass.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9900,13 +9876,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("throwableParamOrder.kt")
|
@TestMetadata("throwableParamOrder.kt")
|
||||||
public void testThrowableParamOrder() throws Exception {
|
public void testThrowableParamOrder() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/intrinsics/throwableParamOrder.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/intrinsics/throwableParamOrder.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("tostring.kt")
|
@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.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor
|
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.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
@@ -100,7 +101,10 @@ class DefaultPropertyTranslator(
|
|||||||
function: JsFunction
|
function: JsFunction
|
||||||
) {
|
) {
|
||||||
val host = translateHost(getterDescriptor, function)
|
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 delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference)
|
||||||
|
|
||||||
val returnResult = JsReturn(delegatedJsCall)
|
val returnResult = JsReturn(delegatedJsCall)
|
||||||
@@ -116,7 +120,9 @@ class DefaultPropertyTranslator(
|
|||||||
|
|
||||||
if (delegatedCall != null) {
|
if (delegatedCall != null) {
|
||||||
val host = translateHost(setterDescriptor, function)
|
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)
|
val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference)
|
||||||
function.addStatement(delegatedJsCall.makeStmt())
|
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 {
|
private fun translateHost(accessorDescriptor: VariableAccessorDescriptor, function: JsFunction): JsExpression {
|
||||||
return if (accessorDescriptor.isExtension) {
|
return if (accessorDescriptor.isExtension) {
|
||||||
function.addParameter(getReceiverParameterName(), 0).name.makeRef()
|
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.JsBinaryOperation;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator;
|
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.JsExpression;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||||
import org.jetbrains.kotlin.js.util.AstUtil;
|
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.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.kotlin.js.translate.reference.AccessTranslator;
|
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.KtExpression;
|
||||||
import org.jetbrains.kotlin.psi.KtUnaryExpression;
|
import org.jetbrains.kotlin.psi.KtUnaryExpression;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
|
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
|
||||||
@@ -64,12 +66,15 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
|||||||
@NotNull
|
@NotNull
|
||||||
protected final AccessTranslator accessTranslator;
|
protected final AccessTranslator accessTranslator;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final JsBlock accessBlock = new JsBlock();
|
||||||
|
|
||||||
protected IncrementTranslator(@NotNull KtUnaryExpression expression,
|
protected IncrementTranslator(@NotNull KtUnaryExpression expression,
|
||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
KtExpression baseExpression = getBaseExpression(expression);
|
KtExpression baseExpression = getBaseExpression(expression);
|
||||||
this.accessTranslator = getAccessTranslator(baseExpression, context()).getCached();
|
this.accessTranslator = getAccessTranslator(baseExpression, context().innerBlock(accessBlock)).getCached();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -87,8 +92,17 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
|||||||
// generate: expr(a = a.inc(), a)
|
// generate: expr(a = a.inc(), a)
|
||||||
JsExpression getExpression = accessTranslator.translateAsGet();
|
JsExpression getExpression = accessTranslator.translateAsGet();
|
||||||
JsExpression reassignment = variableReassignment(getExpression);
|
JsExpression reassignment = variableReassignment(getExpression);
|
||||||
|
accessBlock.getStatements().add(JsAstUtils.asSyntheticStatement(reassignment));
|
||||||
JsExpression getNewValue = accessTranslator.translateAsGet();
|
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);
|
MetadataProperties.setSynthetic(result, true);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -99,8 +113,19 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
|||||||
// code fragment: expr(a++)
|
// code fragment: expr(a++)
|
||||||
// generate: expr( (t1 = a, t2 = t1, a = t1.inc(), t2) )
|
// generate: expr( (t1 = a, t2 = t1, a = t1.inc(), t2) )
|
||||||
TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet());
|
TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet());
|
||||||
|
accessBlock.getStatements().add(t1.assignmentStatement());
|
||||||
JsExpression variableReassignment = variableReassignment(t1.reference());
|
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);
|
MetadataProperties.setSynthetic(result, true);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -116,6 +141,7 @@ public abstract class IncrementTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
private static boolean isDynamic(TranslationContext context, KtUnaryExpression expression) {
|
private static boolean isDynamic(TranslationContext context, KtUnaryExpression expression) {
|
||||||
CallableDescriptor operationDescriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression);
|
CallableDescriptor operationDescriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||||
|
assert operationDescriptor != null;
|
||||||
return DynamicCallsKt.isDynamic(operationDescriptor);
|
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.SideEffectKind
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
||||||
import com.intellij.util.SmartList
|
|
||||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
@@ -78,20 +77,16 @@ class CallArgumentTranslator private constructor(
|
|||||||
val valueArgumentsByIndex = resolvedCall.valueArgumentsByIndex ?: throw IllegalStateException(
|
val valueArgumentsByIndex = resolvedCall.valueArgumentsByIndex ?: throw IllegalStateException(
|
||||||
"Failed to arrange value arguments by index: " + resolvedCall.resultingDescriptor)
|
"Failed to arrange value arguments by index: " + resolvedCall.resultingDescriptor)
|
||||||
var argsBeforeVararg: List<JsExpression>? = null
|
var argsBeforeVararg: List<JsExpression>? = null
|
||||||
var argumentsShouldBeExtractedToTmpVars = false
|
|
||||||
val argContexts = SmartList<TranslationContext>()
|
|
||||||
var concatArguments: MutableList<JsExpression>? = null
|
var concatArguments: MutableList<JsExpression>? = null
|
||||||
|
val argsToJsExpr = translateUnresolvedArguments(context(), resolvedCall)
|
||||||
|
|
||||||
for (parameterDescriptor in valueParameters) {
|
for (parameterDescriptor in valueParameters) {
|
||||||
val actualArgument = valueArgumentsByIndex[parameterDescriptor.index]
|
val actualArgument = valueArgumentsByIndex[parameterDescriptor.index]
|
||||||
|
|
||||||
val argContext = context().innerBlock()
|
|
||||||
|
|
||||||
if (actualArgument is VarargValueArgument) {
|
if (actualArgument is VarargValueArgument) {
|
||||||
|
|
||||||
val arguments = actualArgument.getArguments()
|
val arguments = actualArgument.getArguments()
|
||||||
|
|
||||||
val size = arguments.size
|
|
||||||
if (!hasSpreadOperator) {
|
if (!hasSpreadOperator) {
|
||||||
hasSpreadOperator = arguments.any { it.getSpreadElement() != null }
|
hasSpreadOperator = arguments.any { it.getSpreadElement() != null }
|
||||||
}
|
}
|
||||||
@@ -99,35 +94,25 @@ class CallArgumentTranslator private constructor(
|
|||||||
if (hasSpreadOperator) {
|
if (hasSpreadOperator) {
|
||||||
if (isNativeFunctionCall) {
|
if (isNativeFunctionCall) {
|
||||||
argsBeforeVararg = result
|
argsBeforeVararg = result
|
||||||
result = SmartList<JsExpression>()
|
result = mutableListOf<JsExpression>()
|
||||||
val list = SmartList<JsExpression>()
|
concatArguments = prepareConcatArguments(arguments, translateResolvedArgument(actualArgument, argsToJsExpr))
|
||||||
translateValueArguments(arguments, list, argContext)
|
|
||||||
concatArguments = prepareConcatArguments(arguments, list)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
translateVarargArgument(arguments, result, argContext, size > 1)
|
result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, actualArgument.arguments.size > 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (isNativeFunctionCall) {
|
if (isNativeFunctionCall) {
|
||||||
translateValueArguments(arguments, result, argContext)
|
result.addAll(translateResolvedArgument(actualArgument, argsToJsExpr))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
translateVarargArgument(arguments, result, argContext, true)
|
result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
if (isNativeFunctionCall && hasSpreadOperator) {
|
||||||
@@ -140,7 +125,7 @@ class CallArgumentTranslator private constructor(
|
|||||||
concatArguments.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
|
concatArguments.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
|
||||||
}
|
}
|
||||||
|
|
||||||
result = SmartList(concatArgumentsIfNeeded(concatArguments))
|
result = mutableListOf(concatArgumentsIfNeeded(concatArguments))
|
||||||
|
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver)
|
cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver)
|
||||||
@@ -162,6 +147,54 @@ class CallArgumentTranslator private constructor(
|
|||||||
return ArgumentsInfo(result, hasSpreadOperator, cachedReceiver)
|
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 {
|
companion object {
|
||||||
|
|
||||||
@JvmStatic fun translate(resolvedCall: ResolvedCall<*>, receiver: JsExpression?, context: TranslationContext): ArgumentsInfo {
|
@JvmStatic fun translate(resolvedCall: ResolvedCall<*>, receiver: JsExpression?, context: TranslationContext): ArgumentsInfo {
|
||||||
@@ -184,33 +217,12 @@ class CallArgumentTranslator private constructor(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateSingleArgument(
|
private fun translateResolvedArgument(
|
||||||
parameterDescriptor: ValueParameterDescriptor,
|
resolvedArgument: ResolvedValueArgument,
|
||||||
actualArgument: ResolvedValueArgument,
|
translatedArgs: Map<ValueArgument, JsExpression>
|
||||||
result: MutableList<JsExpression>,
|
): List<JsExpression> {
|
||||||
context: TranslationContext
|
if (resolvedArgument is DefaultValueArgument) return listOf(Namer.getUndefinedExpression())
|
||||||
) {
|
return resolvedArgument.arguments.map { translatedArgs[it]!! }
|
||||||
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 TranslationContext.extractLambda(expression: KtExpression): CallableDescriptor? {
|
private fun TranslationContext.extractLambda(expression: KtExpression): CallableDescriptor? {
|
||||||
@@ -218,49 +230,30 @@ class CallArgumentTranslator private constructor(
|
|||||||
return BindingUtils.getFunctionDescriptor(bindingContext(), lambdaExpression.functionLiteral)
|
return BindingUtils.getFunctionDescriptor(bindingContext(), lambdaExpression.functionLiteral)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateVarargArgument(arguments: List<ValueArgument>, result: MutableList<JsExpression>,
|
private fun translateVarargArgument(
|
||||||
context: TranslationContext, shouldWrapVarargInArray: Boolean) {
|
resolvedArgument: ResolvedValueArgument,
|
||||||
|
translatedArgs: Map<ValueArgument, JsExpression>,
|
||||||
|
shouldWrapVarargInArray: Boolean
|
||||||
|
): List<JsExpression> {
|
||||||
|
val arguments = resolvedArgument.arguments
|
||||||
if (arguments.isEmpty()) {
|
if (arguments.isEmpty()) {
|
||||||
if (shouldWrapVarargInArray) {
|
return if (shouldWrapVarargInArray) {
|
||||||
result.add(JsArrayLiteral(listOf<JsExpression>()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
|
return listOf(JsArrayLiteral(listOf<JsExpression>()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
listOf()
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val list: MutableList<JsExpression> = if (shouldWrapVarargInArray) {
|
val list = translateResolvedArgument(resolvedArgument, translatedArgs)
|
||||||
if (arguments.size == 1) SmartList<JsExpression>() else ArrayList<JsExpression>(arguments.size)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
translateValueArguments(arguments, list, context)
|
return if (shouldWrapVarargInArray) {
|
||||||
|
|
||||||
if (shouldWrapVarargInArray) {
|
|
||||||
val concatArguments = prepareConcatArguments(arguments, list)
|
val concatArguments = prepareConcatArguments(arguments, list)
|
||||||
val concatExpression = concatArgumentsIfNeeded(concatArguments)
|
val concatExpression = concatArgumentsIfNeeded(concatArguments)
|
||||||
result.add(concatExpression)
|
listOf(concatExpression)
|
||||||
}
|
}
|
||||||
else if (result.size == 1) {
|
else {
|
||||||
result[0] = JsAstUtils.invokeMethod(result[0], "slice")
|
listOf(JsAstUtils.invokeMethod(list[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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,8 +273,8 @@ class CallArgumentTranslator private constructor(
|
|||||||
assert(arguments.isNotEmpty()) { "arguments.size should not be 0" }
|
assert(arguments.isNotEmpty()) { "arguments.size should not be 0" }
|
||||||
assert(arguments.size == list.size) { "arguments.size: " + arguments.size + " != list.size: " + list.size }
|
assert(arguments.size == list.size) { "arguments.size: " + arguments.size + " != list.size: " + list.size }
|
||||||
|
|
||||||
val concatArguments = SmartList<JsExpression>()
|
val concatArguments = mutableListOf<JsExpression>()
|
||||||
var lastArrayContent: MutableList<JsExpression> = SmartList()
|
var lastArrayContent = mutableListOf<JsExpression>()
|
||||||
|
|
||||||
val size = arguments.size
|
val size = arguments.size
|
||||||
for (index in 0..size - 1) {
|
for (index in 0..size - 1) {
|
||||||
@@ -292,7 +285,7 @@ class CallArgumentTranslator private constructor(
|
|||||||
if (lastArrayContent.size > 0) {
|
if (lastArrayContent.size > 0) {
|
||||||
concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
|
concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
|
||||||
concatArguments.add(expressionArgument)
|
concatArguments.add(expressionArgument)
|
||||||
lastArrayContent = SmartList<JsExpression>()
|
lastArrayContent = mutableListOf<JsExpression>()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
concatArguments.add(expressionArgument)
|
concatArguments.add(expressionArgument)
|
||||||
@@ -308,27 +301,11 @@ class CallArgumentTranslator private constructor(
|
|||||||
|
|
||||||
return concatArguments
|
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> {
|
fun Map<TypeParameterDescriptor, KotlinType>.buildReifiedTypeArgs(context: TranslationContext): List<JsExpression> {
|
||||||
|
val reifiedTypeArguments = mutableListOf<JsExpression>()
|
||||||
val reifiedTypeArguments = SmartList<JsExpression>()
|
|
||||||
val patternTranslator = PatternTranslator.newInstance(context)
|
val patternTranslator = PatternTranslator.newInstance(context)
|
||||||
|
|
||||||
for (param in keys.sortedBy { it.index }) {
|
for (param in keys.sortedBy { it.index }) {
|
||||||
|
|||||||
@@ -259,8 +259,31 @@ public final class TranslationUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isCacheNeeded(@NotNull JsExpression expression) {
|
public static boolean isCacheNeeded(@NotNull JsExpression expression) {
|
||||||
return !(expression instanceof JsLiteral.JsValueLiteral) &&
|
if (expression instanceof JsLiteral.JsValueLiteral) return false;
|
||||||
(!(expression instanceof JsNameRef) || ((JsNameRef) expression).getQualifier() != null);
|
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
|
@NotNull
|
||||||
|
|||||||
Reference in New Issue
Block a user