From eb5c79c70d160676cf0fa5b5c04e72a747c65e54 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 7 Dec 2016 15:03:46 +0300 Subject: [PATCH] JS: support int overflow behaviour in augmented assignment --- .../augmentedAssignmentWithComplexRhs.kt | 16 ++++++++++-- .../assignmentOperations.kt | 3 --- .../js/test/semantics/BoxJsTestGenerated.java | 6 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 8 +----- .../OverloadedAssignmentTranslator.java | 20 +++++++++++++++ .../js/translate/utils/TranslationUtils.java | 5 +++- .../testData/box/inline/inlineNoReturn.kt | 2 +- .../box/number/assignmentIntOverflow.kt | 25 +++++++++++++++++++ 8 files changed, 71 insertions(+), 14 deletions(-) create mode 100644 js/js.translator/testData/box/number/assignmentIntOverflow.kt diff --git a/compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt b/compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt index 479121f3683..cc9dccf660b 100644 --- a/compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt +++ b/compiler/testData/codegen/box/increment/augmentedAssignmentWithComplexRhs.kt @@ -3,13 +3,14 @@ import kotlin.test.* var log = "" var result = 20 +var doubleResult = 40.0 fun id(value: T) = value fun box(): String { result += if (id("true") == "true") { result += 10 - log += "true chosen" + log += "true chosen;" 3 } else { @@ -17,7 +18,18 @@ fun box(): String { } assertEquals(23, result) - assertEquals("true chosen", log) + + doubleResult += if (id("true") == "true") { + doubleResult += 100 + log += "true chosen;" + 2 + } + else { + 5 + } + + assertEquals(42, (doubleResult + 0.1).toInt()) + assertEquals("true chosen;true chosen;", log) return "OK" } \ No newline at end of file diff --git a/compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt b/compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt index ca63e016b98..edbd763154e 100644 --- a/compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt +++ b/compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - class A() { var x = 0 } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 03e43b84829..8eee9443661 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -5951,6 +5951,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/number"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("assignmentIntOverflow.kt") + public void testAssignmentIntOverflow() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/number/assignmentIntOverflow.kt"); + doTest(fileName); + } + @TestMetadata("byteAndShortConversions.kt") public void testByteAndShortConversions() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/number/byteAndShortConversions.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 bd41fb50e75..d69677c0a58 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 @@ -12366,13 +12366,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("assignmentOperations.kt") public void testAssignmentOperations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("incDecOnObject.kt") 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 02264ff4644..265b331e308 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 @@ -22,11 +22,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; 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.AccessTranslator; import org.jetbrains.kotlin.psi.KtBinaryExpression; +import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; +import java.util.HashMap; +import java.util.Map; + public final class OverloadedAssignmentTranslator extends AssignmentTranslator { @NotNull public static JsExpression doTranslate(@NotNull KtBinaryExpression expression, @@ -63,6 +68,21 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator { JsBlock innerBlock = new JsBlock(); TranslationContext innerContext = context().innerBlock(innerBlock); JsExpression oldValue = accessTranslator.translateAsGet(); + + JsBlock argumentBlock = new JsBlock(); + TranslationContext argumentContext = innerContext.innerBlock(argumentBlock); + KtExpression argumentPsi = expression.getRight(); + assert argumentPsi != null; + JsExpression argument = Translation.translateAsExpression(argumentPsi, argumentContext); + if (!argumentBlock.isEmpty()) { + oldValue = innerContext.defineTemporary(oldValue); + innerContext.addStatementsToCurrentBlockFrom(argumentBlock); + } + + Map aliases = new HashMap(); + aliases.put(argumentPsi, argument); + innerContext = innerContext.innerContextWithAliasesForExpressions(aliases); + JsExpression result = CallTranslator.translate(innerContext, resolvedCall, oldValue); context().addStatementsToCurrentBlockFrom(innerBlock); return result; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index 304b99c6a8a..f795bec21da 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -242,7 +242,10 @@ public final class TranslationUtils { if (operationDescriptor == null || !(operationDescriptor instanceof FunctionDescriptor)) return true; KotlinType returnType = operationDescriptor.getReturnType(); - if (returnType != null && (KotlinBuiltIns.isChar(returnType) || KotlinBuiltIns.isLong(returnType))) return false; + if (returnType != null && + (KotlinBuiltIns.isChar(returnType) || KotlinBuiltIns.isLong(returnType) || KotlinBuiltIns.isInt(returnType))) { + return false; + } if (context.intrinsics().getFunctionIntrinsic((FunctionDescriptor) operationDescriptor).exists()) return true; diff --git a/js/js.translator/testData/box/inline/inlineNoReturn.kt b/js/js.translator/testData/box/inline/inlineNoReturn.kt index 5fb1db05a38..7fd105dfbb9 100644 --- a/js/js.translator/testData/box/inline/inlineNoReturn.kt +++ b/js/js.translator/testData/box/inline/inlineNoReturn.kt @@ -1,6 +1,6 @@ package foo -// CHECK_CONTAINS_NO_CALLS: factAbsNoInline1 +// CHECK_CONTAINS_NO_CALLS: factAbsNoInline1 except=imul internal class State(value: Int) { public var value: Int = value diff --git a/js/js.translator/testData/box/number/assignmentIntOverflow.kt b/js/js.translator/testData/box/number/assignmentIntOverflow.kt new file mode 100644 index 00000000000..aa49c09dec3 --- /dev/null +++ b/js/js.translator/testData/box/number/assignmentIntOverflow.kt @@ -0,0 +1,25 @@ +package foo + +fun bigValue() = 0x7FFFFFFC + +fun mediumValue() = 0x12345 + +fun box(): String { + var v = bigValue() + v += 1 + if (v != 0x7FFFFFFD) return "fail1: $v" + + v = bigValue() + v += 8 + if (v != -0x7FFFFFFC) return "fail2: $v" + + v = mediumValue() + v *= 0x23456 + if (v != -2112496338) return "fail3: $v" + + v = bigValue() + v *= bigValue() + if (v != 16) return "fail4: $v" + + return "OK" +} \ No newline at end of file