diff --git a/compiler/testData/codegen/box/objects/compoundAssignmentToObjectFromCall.kt b/compiler/testData/codegen/box/objects/compoundAssignmentToObjectFromCall.kt new file mode 100644 index 00000000000..b58ec446156 --- /dev/null +++ b/compiler/testData/codegen/box/objects/compoundAssignmentToObjectFromCall.kt @@ -0,0 +1,31 @@ +var log = "" + +class A(p: String) { + var pp = p + + init { + log += "init($p);" + } +} + +operator fun A.plusAssign(s: String) { + pp += s + log += "pp = $pp;" +} + +inline fun T.foo(f: (T) -> R) = f(this) + +fun T.bar(f: (T) -> R) = f(this) + +fun box(): String { + "rrr".foo { A(it) } += "aaa" + + if (log != "init(rrr);pp = rrraaa;") return "1: log = \"$log\"" + + log = "" + "foo".bar { A(it) } += "baaar" + + if (log != "init(foo);pp = foobaaar;") return "2: log = \"$log\"" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/objects/compoundAssignmentToPropertyWithQualifier.kt b/compiler/testData/codegen/box/objects/compoundAssignmentToPropertyWithQualifier.kt new file mode 100644 index 00000000000..bc00799ec27 --- /dev/null +++ b/compiler/testData/codegen/box/objects/compoundAssignmentToPropertyWithQualifier.kt @@ -0,0 +1,48 @@ +var log = "" + +class A(p: String) { + var pp = p + + init { + log += "init($p);" + } +} + +operator fun A.plusAssign(s: String) { + pp += s + log += "pp = $pp;" +} + +class D { + val a = A("D") +} + +object E { + val t = A("E") +} + +fun box(): String { + log = "" + val d = D() + d.a += "foo" + + if (log != "init(D);pp = Dfoo;") return "1: log = \"$log\"" + + log = "" + E.t += "ET" + + if (log != "init(E);pp = EET;") return "2: log = \"$log\"" + + log = "" + val c = object { val b = object { val a = A("xcv") } } + c.b.a += "eee" + + if (log != "init(xcv);pp = xcveee;") return "3: log = \"$log\"" + + val b = object { val a = A("qwe") } + b.a.pp += "ui" + + if (b.a.pp != "qweui") return "4: b.a.pp = \"${b.a.pp}\"" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 7974060704a..a9aa14c20e2 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -13451,12 +13451,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("compoundAssignmentToObjectFromCall.kt") + public void testCompoundAssignmentToObjectFromCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToObjectFromCall.kt"); + doTest(fileName); + } + @TestMetadata("compoundAssignmentToPropertyImportedFromObject.kt") public void testCompoundAssignmentToPropertyImportedFromObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToPropertyImportedFromObject.kt"); doTest(fileName); } + @TestMetadata("compoundAssignmentToPropertyWithQualifier.kt") + public void testCompoundAssignmentToPropertyWithQualifier() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToPropertyWithQualifier.kt"); + doTest(fileName); + } + @TestMetadata("flist.kt") public void testFlist() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 4c8649a1172..e5d937b8d5b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13451,12 +13451,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("compoundAssignmentToObjectFromCall.kt") + public void testCompoundAssignmentToObjectFromCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToObjectFromCall.kt"); + doTest(fileName); + } + @TestMetadata("compoundAssignmentToPropertyImportedFromObject.kt") public void testCompoundAssignmentToPropertyImportedFromObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToPropertyImportedFromObject.kt"); doTest(fileName); } + @TestMetadata("compoundAssignmentToPropertyWithQualifier.kt") + public void testCompoundAssignmentToPropertyWithQualifier() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToPropertyWithQualifier.kt"); + doTest(fileName); + } + @TestMetadata("flist.kt") public void testFlist() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index aedfbdac1b7..ffe2e3853be 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13451,12 +13451,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("compoundAssignmentToObjectFromCall.kt") + public void testCompoundAssignmentToObjectFromCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToObjectFromCall.kt"); + doTest(fileName); + } + @TestMetadata("compoundAssignmentToPropertyImportedFromObject.kt") public void testCompoundAssignmentToPropertyImportedFromObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToPropertyImportedFromObject.kt"); doTest(fileName); } + @TestMetadata("compoundAssignmentToPropertyWithQualifier.kt") + public void testCompoundAssignmentToPropertyWithQualifier() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToPropertyWithQualifier.kt"); + doTest(fileName); + } + @TestMetadata("flist.kt") public void testFlist() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt"); 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 6f3ae6da31f..9d802c0bad6 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 @@ -15979,12 +15979,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("compoundAssignmentToObjectFromCall.kt") + public void testCompoundAssignmentToObjectFromCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToObjectFromCall.kt"); + doTest(fileName); + } + @TestMetadata("compoundAssignmentToPropertyImportedFromObject.kt") public void testCompoundAssignmentToPropertyImportedFromObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToPropertyImportedFromObject.kt"); doTest(fileName); } + @TestMetadata("compoundAssignmentToPropertyWithQualifier.kt") + public void testCompoundAssignmentToPropertyWithQualifier() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/compoundAssignmentToPropertyWithQualifier.kt"); + doTest(fileName); + } + @TestMetadata("flist.kt") public void testFlist() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/QualifiedExpressionTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/QualifiedExpressionTranslator.java index cb0ae6a0532..f271595b84e 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/QualifiedExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/QualifiedExpressionTranslator.java @@ -16,12 +16,12 @@ package org.jetbrains.kotlin.js.translate.reference; -import org.jetbrains.kotlin.js.backend.ast.JsExpression; -import org.jetbrains.kotlin.js.backend.ast.JsNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.PackageViewDescriptor; +import org.jetbrains.kotlin.js.backend.ast.JsExpression; +import org.jetbrains.kotlin.js.backend.ast.JsNode; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils; import org.jetbrains.kotlin.psi.*; @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsExpression; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; -import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getNotNullSimpleNameSelector; import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getSelector; public final class QualifiedExpressionTranslator { @@ -45,7 +44,16 @@ public final class QualifiedExpressionTranslator { if (forceOrderOfEvaluation && receiver != null) { receiver = context.defineTemporary(receiver); } - return VariableAccessTranslator.newInstance(context, getNotNullSimpleNameSelector(expression), receiver); + + KtExpression selector = getSelector(expression); + if (selector instanceof KtSimpleNameExpression) { + return VariableAccessTranslator.newInstance(context, (KtSimpleNameExpression) selector, receiver); + } + if (selector instanceof KtCallExpression) { + return new QualifiedExpressionWithCallSelectorAccessTranslator((KtCallExpression) selector, receiver, context); + } + + throw new AssertionError("Unexpected qualified expression: " + expression.getText()); } @NotNull @@ -73,7 +81,7 @@ public final class QualifiedExpressionTranslator { return VariableAccessTranslator.newInstance(context, (KtSimpleNameExpression)selector, receiver).translateAsGet(); } if (selector instanceof KtCallExpression) { - return invokeCallExpressionTranslator(receiver, selector, context); + return invokeCallExpressionTranslator(receiver, (KtCallExpression) selector, context); } //TODO: never get there if (selector instanceof KtSimpleNameExpression) { @@ -83,13 +91,13 @@ public final class QualifiedExpressionTranslator { } @NotNull - private static JsNode invokeCallExpressionTranslator( + static JsNode invokeCallExpressionTranslator( @Nullable JsExpression receiver, - @NotNull KtExpression selector, + @NotNull KtCallExpression selector, @NotNull TranslationContext context ) { try { - return CallExpressionTranslator.translate((KtCallExpression) selector, receiver, context); + return CallExpressionTranslator.translate(selector, receiver, context); } catch (RuntimeException e) { throw ErrorReportingUtils.reportErrorWithLocation(selector, e); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/QualifiedExpressionWithCallSelectorAccessTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/QualifiedExpressionWithCallSelectorAccessTranslator.kt new file mode 100644 index 00000000000..cc7ee98b9cd --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/QualifiedExpressionWithCallSelectorAccessTranslator.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.js.translate.reference + +import org.jetbrains.kotlin.js.backend.ast.JsExpression +import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.psi.KtCallExpression + +class QualifiedExpressionWithCallSelectorAccessTranslator( + private val selector: KtCallExpression, + private val receiver: JsExpression?, + private val context: TranslationContext +) : AccessTranslator { + + override fun translateAsGet(): JsExpression { + return QualifiedExpressionTranslator.invokeCallExpressionTranslator(receiver, selector, context) as JsExpression + } + + override fun translateAsSet(setTo: JsExpression): JsExpression { + throw IllegalStateException("Set access is not supported for " + this::class.java.simpleName) + } + + override fun getCached(): AccessTranslator { + throw IllegalStateException("Cashed access is not supported for " + this::class.java.simpleName) + } +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/PsiUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/PsiUtils.java index 567e1632586..3081fbb68aa 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/PsiUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/PsiUtils.java @@ -31,11 +31,10 @@ import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; -import java.io.*; -import java.nio.charset.Charset; +import java.io.File; +import java.io.IOException; import java.util.Collections; import java.util.List; -import java.util.function.Supplier; public final class PsiUtils { @@ -71,13 +70,6 @@ public final class PsiUtils { return selectorExpression; } - @NotNull - public static KtSimpleNameExpression getNotNullSimpleNameSelector(@NotNull KtQualifiedExpression expression) { - KtSimpleNameExpression selectorAsSimpleName = getSelectorAsSimpleName(expression); - assert selectorAsSimpleName != null; - return selectorAsSimpleName; - } - @NotNull public static KtToken getOperationToken(@NotNull KtOperationExpression expression) { KtSimpleNameExpression operationExpression = expression.getOperationReference();