JS: fix translation of augmented assignment when RHS changes value of LHS

This commit is contained in:
Alexey Andreev
2016-11-21 18:47:09 +03:00
parent be196789d2
commit 40e00a62f5
7 changed files with 77 additions and 13 deletions
@@ -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"
}
@@ -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");
@@ -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
@@ -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);
} }
} }