diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt b/compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt index 295f1240e1c..ef4268e0689 100644 --- a/compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt +++ b/compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt @@ -1,9 +1,6 @@ // WITH_RUNTIME // NO_INTERCEPT_RESUME_TESTS -// TODO: fix bug in JVM backend and remove this directive -// TARGET_BACKEND: JS - class Controller { var result = "" @@ -29,7 +26,7 @@ fun box(): String { } } } - if (value != "A;[B][C]!") return "fail: suspend as if condition: $value" + if (value != "A;B]C]!") return "fail: suspend as if condition: $value" return "OK" } diff --git a/compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt b/compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt new file mode 100644 index 00000000000..479121f3683 --- /dev/null +++ b/compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt @@ -0,0 +1,23 @@ +// WITH_RUNTIME +import kotlin.test.* + +var log = "" +var result = 20 + +fun id(value: T) = value + +fun box(): String { + result += if (id("true") == "true") { + result += 10 + log += "true chosen" + 3 + } + else { + 4 + } + + assertEquals(23, result) + assertEquals("true chosen", log) + + 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 bb58cd28ef5..ebb9faf3ba4 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 @@ -4768,6 +4768,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("switchLikeWhen.kt") + public void testSwitchLikeWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt"); + doTest(fileName); + } + @TestMetadata("throwFromCatch.kt") public void testThrowFromCatch() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt"); @@ -7679,6 +7685,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("augmentedAssignmentWithComplexRhs.kt") + public void testAugmentedAssignmentWithComplexRhs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt"); + doTest(fileName); + } + @TestMetadata("classNaryGetSet.kt") public void testClassNaryGetSet() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 233881acc7c..d1d868c7014 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4768,6 +4768,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("switchLikeWhen.kt") + public void testSwitchLikeWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/switchLikeWhen.kt"); + doTest(fileName); + } + @TestMetadata("throwFromCatch.kt") public void testThrowFromCatch() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt"); @@ -7679,6 +7685,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("augmentedAssignmentWithComplexRhs.kt") + public void testAugmentedAssignmentWithComplexRhs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt"); + doTest(fileName); + } + @TestMetadata("classNaryGetSet.kt") public void testClassNaryGetSet() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.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 f70b0fe17ac..87c877b96ce 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 @@ -8838,6 +8838,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("augmentedAssignmentWithComplexRhs.kt") + public void testAugmentedAssignmentWithComplexRhs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt"); + doTest(fileName); + } + @TestMetadata("classNaryGetSet.kt") public void testClassNaryGetSet() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt index 26d37271aff..3d7a6c34370 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt @@ -91,7 +91,11 @@ object DefaultVariableAccessCase : VariableAccessCase() { getCapturedVarAccessor(functionRef) } else { - functionRef + functionRef.apply { + if (isGetAccess()) { + sideEffects = SideEffectKind.DEPENDS_ON_STATE + } + } } val localVariableDescriptor = resolvedCall.resultingDescriptor as? LocalVariableDescriptor 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 aeb775221a4..b522e30ca75 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 @@ -23,6 +23,7 @@ import com.google.dart.compiler.backend.js.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.js.translate.context.TranslationContext; 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.types.expressions.OperatorConventions; @@ -33,8 +34,10 @@ import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.isSimpleN import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateRightExpression; public final class IntrinsicAssignmentTranslator extends AssignmentTranslator { - private JsExpression right; - private AccessTranslator accessTranslator; + private final JsExpression right; + private final AccessTranslator accessTranslator; + private final boolean rightExpressionTrivial; + private final JsBlock rightBlock = new JsBlock(); @NotNull public static JsExpression doTranslate(@NotNull KtBinaryExpression expression, @@ -46,10 +49,9 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator { @NotNull TranslationContext context) { super(expression, context); - JsBlock rightBlock = new JsBlock(); right = translateRightExpression(context, expression, rightBlock); - accessTranslator = createAccessTranslator(expression.getLeft(), !rightBlock.isEmpty()); - context.addStatementsToCurrentBlockFrom(rightBlock); + rightExpressionTrivial = rightBlock.isEmpty(); + accessTranslator = createAccessTranslator(expression.getLeft(), !rightExpressionTrivial); } @NotNull @@ -62,7 +64,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator { @NotNull private JsExpression translateAsAssignmentOperation() { - if (isSimpleNameExpressionNotDelegatedLocalVar(expression.getLeft(), context())) { + if (isSimpleNameExpressionNotDelegatedLocalVar(expression.getLeft(), context()) && rightExpressionTrivial) { return translateAsPlainAssignmentOperation(); } return translateAsAssignToCounterpart(); @@ -71,14 +73,19 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator { @NotNull private JsExpression translateAsAssignToCounterpart() { JsBinaryOperator operator = getCounterpartOperator(); - JsBinaryOperation counterpartOperation = - new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right); + JsExpression oldValue = accessTranslator.translateAsGet(); + if (!rightExpressionTrivial) { + oldValue = context().defineTemporary(oldValue); + } + JsBinaryOperation counterpartOperation = new JsBinaryOperation(operator, oldValue, right); + context().addStatementsToCurrentBlockFrom(rightBlock); return accessTranslator.translateAsSet(counterpartOperation); } @NotNull private JsBinaryOperator getCounterpartOperator() { KtToken assignmentOperationToken = getOperationToken(expression); + assert assignmentOperationToken instanceof KtSingleValueToken; assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(assignmentOperationToken); KtToken counterpartToken = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(assignmentOperationToken); assert OperatorTable.hasCorrespondingBinaryOperator(counterpartToken) : @@ -88,6 +95,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator { @NotNull private JsExpression translateAsPlainAssignmentOperation() { + context().addStatementsToCurrentBlockFrom(rightBlock); JsBinaryOperator operator = getAssignmentOperator(); return new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right); } @@ -95,6 +103,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator { @NotNull private JsBinaryOperator getAssignmentOperator() { KtToken token = getOperationToken(expression); + assert token instanceof KtSingleValueToken; assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(token); assert OperatorTable.hasCorrespondingBinaryOperator(token) : "Unsupported token encountered: " + token.toString(); @@ -103,6 +112,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator { @NotNull private JsExpression translateAsPlainAssignment() { + context().addStatementsToCurrentBlockFrom(rightBlock); return accessTranslator.translateAsSet(right); } }