JS: support int overflow behaviour in augmented assignment

This commit is contained in:
Alexey Andreev
2016-12-07 15:03:46 +03:00
parent c411a8febe
commit eb5c79c70d
8 changed files with 71 additions and 14 deletions
@@ -3,13 +3,14 @@ import kotlin.test.*
var log = ""
var result = 20
var doubleResult = 40.0
fun <T> 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"
}
@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
class A() {
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);
}
@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");
@@ -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")
@@ -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<KtExpression, JsExpression> aliases = new HashMap<KtExpression, JsExpression>();
aliases.put(argumentPsi, argument);
innerContext = innerContext.innerContextWithAliasesForExpressions(aliases);
JsExpression result = CallTranslator.translate(innerContext, resolvedCall, oldValue);
context().addStatementsToCurrentBlockFrom(innerBlock);
return result;
@@ -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;
+1 -1
View File
@@ -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
@@ -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"
}