JS: fix translation of augmented assignment when RHS changes value of LHS
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// NO_INTERCEPT_RESUME_TESTS
|
// NO_INTERCEPT_RESUME_TESTS
|
||||||
|
|
||||||
// TODO: fix bug in JVM backend and remove this directive
|
|
||||||
// TARGET_BACKEND: JS
|
|
||||||
|
|
||||||
class Controller {
|
class Controller {
|
||||||
var result = ""
|
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"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
var log = ""
|
||||||
|
var result = 20
|
||||||
|
|
||||||
|
fun <T> 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"
|
||||||
|
}
|
||||||
+12
@@ -4768,6 +4768,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("throwFromCatch.kt")
|
||||||
public void testThrowFromCatch() throws Exception {
|
public void testThrowFromCatch() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt");
|
||||||
@@ -7679,6 +7685,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("classNaryGetSet.kt")
|
||||||
public void testClassNaryGetSet() throws Exception {
|
public void testClassNaryGetSet() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
|
|||||||
@@ -4768,6 +4768,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("throwFromCatch.kt")
|
||||||
public void testThrowFromCatch() throws Exception {
|
public void testThrowFromCatch() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwFromCatch.kt");
|
||||||
@@ -7679,6 +7685,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("classNaryGetSet.kt")
|
||||||
public void testClassNaryGetSet() throws Exception {
|
public void testClassNaryGetSet() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
|
|||||||
@@ -8838,6 +8838,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("classNaryGetSet.kt")
|
||||||
public void testClassNaryGetSet() throws Exception {
|
public void testClassNaryGetSet() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/classNaryGetSet.kt");
|
||||||
|
|||||||
+5
-1
@@ -91,7 +91,11 @@ object DefaultVariableAccessCase : VariableAccessCase() {
|
|||||||
getCapturedVarAccessor(functionRef)
|
getCapturedVarAccessor(functionRef)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
functionRef
|
functionRef.apply {
|
||||||
|
if (isGetAccess()) {
|
||||||
|
sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val localVariableDescriptor = resolvedCall.resultingDescriptor as? LocalVariableDescriptor
|
val localVariableDescriptor = resolvedCall.resultingDescriptor as? LocalVariableDescriptor
|
||||||
|
|||||||
+18
-8
@@ -23,6 +23,7 @@ import com.google.dart.compiler.backend.js.ast.JsExpression;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.js.translate.reference.AccessTranslator;
|
import org.jetbrains.kotlin.js.translate.reference.AccessTranslator;
|
||||||
|
import org.jetbrains.kotlin.lexer.KtSingleValueToken;
|
||||||
import org.jetbrains.kotlin.lexer.KtToken;
|
import org.jetbrains.kotlin.lexer.KtToken;
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpression;
|
import org.jetbrains.kotlin.psi.KtBinaryExpression;
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
|
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;
|
import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateRightExpression;
|
||||||
|
|
||||||
public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
||||||
private JsExpression right;
|
private final JsExpression right;
|
||||||
private AccessTranslator accessTranslator;
|
private final AccessTranslator accessTranslator;
|
||||||
|
private final boolean rightExpressionTrivial;
|
||||||
|
private final JsBlock rightBlock = new JsBlock();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression doTranslate(@NotNull KtBinaryExpression expression,
|
public static JsExpression doTranslate(@NotNull KtBinaryExpression expression,
|
||||||
@@ -46,10 +49,9 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
|||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
super(expression, context);
|
super(expression, context);
|
||||||
|
|
||||||
JsBlock rightBlock = new JsBlock();
|
|
||||||
right = translateRightExpression(context, expression, rightBlock);
|
right = translateRightExpression(context, expression, rightBlock);
|
||||||
accessTranslator = createAccessTranslator(expression.getLeft(), !rightBlock.isEmpty());
|
rightExpressionTrivial = rightBlock.isEmpty();
|
||||||
context.addStatementsToCurrentBlockFrom(rightBlock);
|
accessTranslator = createAccessTranslator(expression.getLeft(), !rightExpressionTrivial);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -62,7 +64,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateAsAssignmentOperation() {
|
private JsExpression translateAsAssignmentOperation() {
|
||||||
if (isSimpleNameExpressionNotDelegatedLocalVar(expression.getLeft(), context())) {
|
if (isSimpleNameExpressionNotDelegatedLocalVar(expression.getLeft(), context()) && rightExpressionTrivial) {
|
||||||
return translateAsPlainAssignmentOperation();
|
return translateAsPlainAssignmentOperation();
|
||||||
}
|
}
|
||||||
return translateAsAssignToCounterpart();
|
return translateAsAssignToCounterpart();
|
||||||
@@ -71,14 +73,19 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateAsAssignToCounterpart() {
|
private JsExpression translateAsAssignToCounterpart() {
|
||||||
JsBinaryOperator operator = getCounterpartOperator();
|
JsBinaryOperator operator = getCounterpartOperator();
|
||||||
JsBinaryOperation counterpartOperation =
|
JsExpression oldValue = accessTranslator.translateAsGet();
|
||||||
new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right);
|
if (!rightExpressionTrivial) {
|
||||||
|
oldValue = context().defineTemporary(oldValue);
|
||||||
|
}
|
||||||
|
JsBinaryOperation counterpartOperation = new JsBinaryOperation(operator, oldValue, right);
|
||||||
|
context().addStatementsToCurrentBlockFrom(rightBlock);
|
||||||
return accessTranslator.translateAsSet(counterpartOperation);
|
return accessTranslator.translateAsSet(counterpartOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsBinaryOperator getCounterpartOperator() {
|
private JsBinaryOperator getCounterpartOperator() {
|
||||||
KtToken assignmentOperationToken = getOperationToken(expression);
|
KtToken assignmentOperationToken = getOperationToken(expression);
|
||||||
|
assert assignmentOperationToken instanceof KtSingleValueToken;
|
||||||
assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(assignmentOperationToken);
|
assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(assignmentOperationToken);
|
||||||
KtToken counterpartToken = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(assignmentOperationToken);
|
KtToken counterpartToken = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(assignmentOperationToken);
|
||||||
assert OperatorTable.hasCorrespondingBinaryOperator(counterpartToken) :
|
assert OperatorTable.hasCorrespondingBinaryOperator(counterpartToken) :
|
||||||
@@ -88,6 +95,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateAsPlainAssignmentOperation() {
|
private JsExpression translateAsPlainAssignmentOperation() {
|
||||||
|
context().addStatementsToCurrentBlockFrom(rightBlock);
|
||||||
JsBinaryOperator operator = getAssignmentOperator();
|
JsBinaryOperator operator = getAssignmentOperator();
|
||||||
return new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right);
|
return new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right);
|
||||||
}
|
}
|
||||||
@@ -95,6 +103,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private JsBinaryOperator getAssignmentOperator() {
|
private JsBinaryOperator getAssignmentOperator() {
|
||||||
KtToken token = getOperationToken(expression);
|
KtToken token = getOperationToken(expression);
|
||||||
|
assert token instanceof KtSingleValueToken;
|
||||||
assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(token);
|
assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(token);
|
||||||
assert OperatorTable.hasCorrespondingBinaryOperator(token) :
|
assert OperatorTable.hasCorrespondingBinaryOperator(token) :
|
||||||
"Unsupported token encountered: " + token.toString();
|
"Unsupported token encountered: " + token.toString();
|
||||||
@@ -103,6 +112,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression translateAsPlainAssignment() {
|
private JsExpression translateAsPlainAssignment() {
|
||||||
|
context().addStatementsToCurrentBlockFrom(rightBlock);
|
||||||
return accessTranslator.translateAsSet(right);
|
return accessTranslator.translateAsSet(right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user