JS: support int overflow behaviour in augmented assignment
This commit is contained in:
+14
-2
@@ -3,13 +3,14 @@ import kotlin.test.*
|
|||||||
|
|
||||||
var log = ""
|
var log = ""
|
||||||
var result = 20
|
var result = 20
|
||||||
|
var doubleResult = 40.0
|
||||||
|
|
||||||
fun <T> id(value: T) = value
|
fun <T> id(value: T) = value
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
result += if (id("true") == "true") {
|
result += if (id("true") == "true") {
|
||||||
result += 10
|
result += 10
|
||||||
log += "true chosen"
|
log += "true chosen;"
|
||||||
3
|
3
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -17,7 +18,18 @@ fun box(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(23, result)
|
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"
|
return "OK"
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
|
||||||
// IGNORE_BACKEND: JS
|
|
||||||
|
|
||||||
class A() {
|
class A() {
|
||||||
var x = 0
|
var x = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
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")
|
@TestMetadata("byteAndShortConversions.kt")
|
||||||
public void testByteAndShortConversions() throws Exception {
|
public void testByteAndShortConversions() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/number/byteAndShortConversions.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/number/byteAndShortConversions.kt");
|
||||||
|
|||||||
+1
-7
@@ -12366,13 +12366,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("assignmentOperations.kt")
|
@TestMetadata("assignmentOperations.kt")
|
||||||
public void testAssignmentOperations() throws Exception {
|
public void testAssignmentOperations() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("incDecOnObject.kt")
|
@TestMetadata("incDecOnObject.kt")
|
||||||
|
|||||||
+20
@@ -22,11 +22,16 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
|
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
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.js.translate.reference.AccessTranslator;
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpression;
|
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.callUtil.CallUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public final class OverloadedAssignmentTranslator extends AssignmentTranslator {
|
public final class OverloadedAssignmentTranslator extends AssignmentTranslator {
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression doTranslate(@NotNull KtBinaryExpression expression,
|
public static JsExpression doTranslate(@NotNull KtBinaryExpression expression,
|
||||||
@@ -63,6 +68,21 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator {
|
|||||||
JsBlock innerBlock = new JsBlock();
|
JsBlock innerBlock = new JsBlock();
|
||||||
TranslationContext innerContext = context().innerBlock(innerBlock);
|
TranslationContext innerContext = context().innerBlock(innerBlock);
|
||||||
JsExpression oldValue = accessTranslator.translateAsGet();
|
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<KtExpression, JsExpression> aliases = new HashMap<KtExpression, JsExpression>();
|
||||||
|
aliases.put(argumentPsi, argument);
|
||||||
|
innerContext = innerContext.innerContextWithAliasesForExpressions(aliases);
|
||||||
|
|
||||||
JsExpression result = CallTranslator.translate(innerContext, resolvedCall, oldValue);
|
JsExpression result = CallTranslator.translate(innerContext, resolvedCall, oldValue);
|
||||||
context().addStatementsToCurrentBlockFrom(innerBlock);
|
context().addStatementsToCurrentBlockFrom(innerBlock);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -242,7 +242,10 @@ public final class TranslationUtils {
|
|||||||
if (operationDescriptor == null || !(operationDescriptor instanceof FunctionDescriptor)) return true;
|
if (operationDescriptor == null || !(operationDescriptor instanceof FunctionDescriptor)) return true;
|
||||||
|
|
||||||
KotlinType returnType = operationDescriptor.getReturnType();
|
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;
|
if (context.intrinsics().getFunctionIntrinsic((FunctionDescriptor) operationDescriptor).exists()) return true;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package foo
|
package foo
|
||||||
|
|
||||||
// CHECK_CONTAINS_NO_CALLS: factAbsNoInline1
|
// CHECK_CONTAINS_NO_CALLS: factAbsNoInline1 except=imul
|
||||||
|
|
||||||
internal class State(value: Int) {
|
internal class State(value: Int) {
|
||||||
public var value: Int = value
|
public var value: Int = value
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user