From 4eed7c1fcb337a565475cfe4ef8871f504704fcd Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 10 Jan 2017 13:31:36 +0300 Subject: [PATCH] JS: fix translation of augmented assignment in class initializer. See KT-15569 --- .../augmentedAssignmentInInitializer.kt | 45 +++++++++++++++++++ .../augmentedAssignmentInInitializer.txt | 32 +++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ ...LightAnalysisModeCodegenTestGenerated.java | 6 +++ .../semantics/JsCodegenBoxTestGenerated.java | 6 +++ .../operation/AssignmentTranslator.java | 30 +++++-------- .../IntrinsicAssignmentTranslator.java | 11 ++--- .../OverloadedAssignmentTranslator.java | 19 ++++---- 9 files changed, 130 insertions(+), 31 deletions(-) create mode 100644 compiler/testData/codegen/box/operatorConventions/augmentedAssignmentInInitializer.kt create mode 100644 compiler/testData/codegen/light-analysis/operatorConventions/augmentedAssignmentInInitializer.txt diff --git a/compiler/testData/codegen/box/operatorConventions/augmentedAssignmentInInitializer.kt b/compiler/testData/codegen/box/operatorConventions/augmentedAssignmentInInitializer.kt new file mode 100644 index 00000000000..4592c96c7ae --- /dev/null +++ b/compiler/testData/codegen/box/operatorConventions/augmentedAssignmentInInitializer.kt @@ -0,0 +1,45 @@ +abstract class A { + val b = B("O") + + open val c: B + + val d: B + get() = field + + var e: String + get() = field + + init { + c = B("O") + d = B("O") + e = "O" + + b += "," + c += "." + d += ";" + e += "|" + } +} + +class B(var value: String) { + operator fun plusAssign(o: String) { + value += o + } +} + +class C : A() { + init { + b += "K" + c += "K" + d += "K" + e += "K" + } +} + +fun box(): String { + val c = C() + val result = "${c.b.value} ${c.c.value} ${c.d.value} ${c.e}" + if (result != "O,K O.K O;K O|K") return "fail: $result" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/light-analysis/operatorConventions/augmentedAssignmentInInitializer.txt b/compiler/testData/codegen/light-analysis/operatorConventions/augmentedAssignmentInInitializer.txt new file mode 100644 index 00000000000..f74c40198fe --- /dev/null +++ b/compiler/testData/codegen/light-analysis/operatorConventions/augmentedAssignmentInInitializer.txt @@ -0,0 +1,32 @@ +@kotlin.Metadata +public abstract class A { + private final @org.jetbrains.annotations.NotNull field b: B + private final @org.jetbrains.annotations.NotNull field c: B + private final @org.jetbrains.annotations.NotNull field d: B + private @org.jetbrains.annotations.NotNull field e: java.lang.String + public method (): void + public final @org.jetbrains.annotations.NotNull method getB(): B + public @org.jetbrains.annotations.NotNull method getC(): B + public final @org.jetbrains.annotations.NotNull method getD(): B + public final @org.jetbrains.annotations.NotNull method getE(): java.lang.String + public final method setE(@org.jetbrains.annotations.NotNull p0: java.lang.String): void +} + +@kotlin.Metadata +public final class AugmentedAssignmentInInitializerKt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +@kotlin.Metadata +public final class B { + private @org.jetbrains.annotations.NotNull field value: java.lang.String + public method (@org.jetbrains.annotations.NotNull p0: java.lang.String): void + public final @org.jetbrains.annotations.NotNull method getValue(): java.lang.String + public final method plusAssign(@org.jetbrains.annotations.NotNull p0: java.lang.String): void + public final method setValue(@org.jetbrains.annotations.NotNull p0: java.lang.String): void +} + +@kotlin.Metadata +public final class C { + public method (): void +} 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 c5c7f7e008e..3cd7e412bf7 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 @@ -10655,6 +10655,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("augmentedAssignmentInInitializer.kt") + public void testAugmentedAssignmentInInitializer() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/augmentedAssignmentInInitializer.kt"); + doTest(fileName); + } + @TestMetadata("augmentedAssignmentWithArrayLHS.kt") public void testAugmentedAssignmentWithArrayLHS() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/augmentedAssignmentWithArrayLHS.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 3b81b9256c0..2794b647799 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10655,6 +10655,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("augmentedAssignmentInInitializer.kt") + public void testAugmentedAssignmentInInitializer() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/augmentedAssignmentInInitializer.kt"); + doTest(fileName); + } + @TestMetadata("augmentedAssignmentWithArrayLHS.kt") public void testAugmentedAssignmentWithArrayLHS() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/augmentedAssignmentWithArrayLHS.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java index 51899487095..22d39a4acda 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java @@ -10655,6 +10655,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis doTest(fileName); } + @TestMetadata("augmentedAssignmentInInitializer.kt") + public void testAugmentedAssignmentInInitializer() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/augmentedAssignmentInInitializer.kt"); + doTest(fileName); + } + @TestMetadata("augmentedAssignmentWithArrayLHS.kt") public void testAugmentedAssignmentWithArrayLHS() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/augmentedAssignmentWithArrayLHS.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 e8c78ed62f9..a2cbf709525 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 @@ -12450,6 +12450,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("augmentedAssignmentInInitializer.kt") + public void testAugmentedAssignmentInInitializer() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/augmentedAssignmentInInitializer.kt"); + doTest(fileName); + } + @TestMetadata("augmentedAssignmentWithArrayLHS.kt") public void testAugmentedAssignmentWithArrayLHS() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/augmentedAssignmentWithArrayLHS.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/AssignmentTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/AssignmentTranslator.java index cc4abee3b76..518d4888668 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/AssignmentTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/AssignmentTranslator.java @@ -16,12 +16,12 @@ package org.jetbrains.kotlin.js.translate.operation; -import org.jetbrains.kotlin.js.backend.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.PropertyDescriptor; +import org.jetbrains.kotlin.js.backend.ast.JsExpression; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.reference.AccessTranslationUtils; @@ -44,8 +44,7 @@ public abstract class AssignmentTranslator extends AbstractTranslator { } @NotNull - public static JsExpression translate(@NotNull KtBinaryExpression expression, - @NotNull TranslationContext context) { + public static JsExpression translate(@NotNull KtBinaryExpression expression, @NotNull TranslationContext context) { if (hasCorrespondingFunctionIntrinsic(context, expression)) { return IntrinsicAssignmentTranslator.doTranslate(expression, context); } @@ -56,8 +55,7 @@ public abstract class AssignmentTranslator extends AbstractTranslator { protected final KtBinaryExpression expression; protected final boolean isVariableReassignment; - protected AssignmentTranslator(@NotNull KtBinaryExpression expression, - @NotNull TranslationContext context) { + protected AssignmentTranslator(@NotNull KtBinaryExpression expression, @NotNull TranslationContext context) { super(context); this.expression = expression; this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression); @@ -65,12 +63,13 @@ public abstract class AssignmentTranslator extends AbstractTranslator { assert left != null : "No left-hand side: " + expression.getText(); } - protected final AccessTranslator createAccessTranslator(KtExpression left, boolean forceOrderOfEvaluation) { + protected final AccessTranslator createAccessTranslator(@NotNull KtExpression left, boolean forceOrderOfEvaluation) { if (isReferenceToBackingFieldFromConstructor(left, context())) { KtSimpleNameExpression simpleName = getSimpleName(left); assert simpleName != null; return BackingFieldAccessTranslator.newInstance(simpleName, context()); - } else { + } + else { return AccessTranslationUtils.getAccessTranslator(left, context(), forceOrderOfEvaluation); } } @@ -87,7 +86,8 @@ public abstract class AssignmentTranslator extends AbstractTranslator { else if (expression instanceof KtDotQualifiedExpression) { KtDotQualifiedExpression qualifiedExpression = (KtDotQualifiedExpression) expression; if (qualifiedExpression.getReceiverExpression() instanceof KtThisExpression && - qualifiedExpression.getSelectorExpression() instanceof KtSimpleNameExpression) { + qualifiedExpression.getSelectorExpression() instanceof KtSimpleNameExpression + ) { KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) qualifiedExpression.getSelectorExpression(); DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), nameExpression); return isReferenceToBackingFieldFromConstructor(descriptor, context); @@ -100,19 +100,13 @@ public abstract class AssignmentTranslator extends AbstractTranslator { @Nullable DeclarationDescriptor descriptor, @NotNull TranslationContext context ) { - if (!(descriptor instanceof PropertyDescriptor)) { - return false; - } + if (!(descriptor instanceof PropertyDescriptor)) return false; + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + if (!(context.getDeclarationDescriptor() instanceof ClassDescriptor)) return false; - if (!(context.getDeclarationDescriptor() instanceof ClassDescriptor)) { - return false; - } ClassDescriptor classDescriptor = (ClassDescriptor) context.getDeclarationDescriptor(); - - if (classDescriptor != propertyDescriptor.getContainingDeclaration()) { - return false; - } + if (classDescriptor != propertyDescriptor.getContainingDeclaration()) return false; return !propertyDescriptor.isVar(); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IntrinsicAssignmentTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IntrinsicAssignmentTranslator.java index 05ba0da8016..4aacdb099ef 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IntrinsicAssignmentTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/IntrinsicAssignmentTranslator.java @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.js.translate.reference.AccessTranslator; import org.jetbrains.kotlin.lexer.KtSingleValueToken; import org.jetbrains.kotlin.lexer.KtToken; import org.jetbrains.kotlin.psi.KtBinaryExpression; +import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.types.expressions.OperatorConventions; import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken; @@ -40,18 +41,18 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator { private final JsBlock rightBlock = new JsBlock(); @NotNull - public static JsExpression doTranslate(@NotNull KtBinaryExpression expression, - @NotNull TranslationContext context) { + public static JsExpression doTranslate(@NotNull KtBinaryExpression expression, @NotNull TranslationContext context) { return (new IntrinsicAssignmentTranslator(expression, context)).translate(); } - private IntrinsicAssignmentTranslator(@NotNull KtBinaryExpression expression, - @NotNull TranslationContext context) { + private IntrinsicAssignmentTranslator(@NotNull KtBinaryExpression expression, @NotNull TranslationContext context) { super(expression, context); right = translateRightExpression(context, expression, rightBlock); rightExpressionTrivial = rightBlock.isEmpty(); - accessTranslator = createAccessTranslator(expression.getLeft(), !rightExpressionTrivial); + KtExpression left = expression.getLeft(); + assert left != null; + accessTranslator = createAccessTranslator(left, !rightExpressionTrivial); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/OverloadedAssignmentTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/OverloadedAssignmentTranslator.java index 0e82734bd66..ea65cd46afb 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/OverloadedAssignmentTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/OverloadedAssignmentTranslator.java @@ -16,13 +16,14 @@ package org.jetbrains.kotlin.js.translate.operation; -import org.jetbrains.kotlin.js.backend.ast.JsBlock; -import org.jetbrains.kotlin.js.backend.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; +import org.jetbrains.kotlin.js.backend.ast.JsBlock; +import org.jetbrains.kotlin.js.backend.ast.JsExpression; import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.Translation; +import org.jetbrains.kotlin.js.translate.reference.AccessTranslationUtils; import org.jetbrains.kotlin.js.translate.reference.AccessTranslator; import org.jetbrains.kotlin.psi.KtBinaryExpression; import org.jetbrains.kotlin.psi.KtExpression; @@ -34,16 +35,14 @@ import java.util.Map; public final class OverloadedAssignmentTranslator extends AssignmentTranslator { @NotNull - public static JsExpression doTranslate(@NotNull KtBinaryExpression expression, - @NotNull TranslationContext context) { + public static JsExpression doTranslate(@NotNull KtBinaryExpression expression, @NotNull TranslationContext context) { return (new OverloadedAssignmentTranslator(expression, context)).translate(); } @NotNull private final ResolvedCall resolvedCall; - private OverloadedAssignmentTranslator(@NotNull KtBinaryExpression expression, - @NotNull TranslationContext context) { + private OverloadedAssignmentTranslator(@NotNull KtBinaryExpression expression, @NotNull TranslationContext context) { super(expression, context); resolvedCall = CallUtilKt.getFunctionResolvedCallWithAssert(expression, context.bindingContext()); } @@ -53,12 +52,16 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator { if (isVariableReassignment) { return reassignment(); } - return overloadedMethodInvocation(createAccessTranslator(expression.getLeft(), false)); + KtExpression left = expression.getLeft(); + assert left != null; + return overloadedMethodInvocation(AccessTranslationUtils.getAccessTranslator(left, context())); } @NotNull private JsExpression reassignment() { - AccessTranslator accessTranslator = createAccessTranslator(expression.getLeft(), false).getCached(); + KtExpression left = expression.getLeft(); + assert left != null; + AccessTranslator accessTranslator = AccessTranslationUtils.getAccessTranslator(left, context()).getCached(); JsExpression newValue = overloadedMethodInvocation(accessTranslator); return accessTranslator.translateAsSet(newValue); }