JS backend: fix KT-5738 JS backend: result of toByte() should be in the range of bytes
#KT-5738 Fixed
This commit is contained in:
@@ -69,4 +69,12 @@ public final class NumberTest extends SingleFileTranslationTest {
|
||||
public void testNumberCompareTo() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testConversionsWithoutTruncation() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testConversionsWithTruncation() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
}
|
||||
|
||||
+59
-33
@@ -16,47 +16,32 @@
|
||||
|
||||
package org.jetbrains.k2js.translate.intrinsic.functions.factories;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic;
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate;
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.*;
|
||||
import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern;
|
||||
|
||||
//TODO: support longs and chars
|
||||
public final class NumberConversionFIF extends CompositeFIF {
|
||||
@NotNull
|
||||
private static final NamePredicate SUPPORTED_CONVERSIONS;
|
||||
|
||||
static {
|
||||
Set<Name> supportedConversions = Sets.newHashSet(NUMBER_CONVERSIONS);
|
||||
//TODO: support longs and chars
|
||||
supportedConversions.remove(CHAR);
|
||||
supportedConversions.remove(LONG);
|
||||
SUPPORTED_CONVERSIONS = new NamePredicate(supportedConversions);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static final NamePredicate FLOATING_POINT_CONVERSIONS = new NamePredicate(FLOAT, DOUBLE);
|
||||
|
||||
@NotNull
|
||||
private static final NamePredicate INTEGER_CONVERSIONS = new NamePredicate(INT, SHORT, BYTE);
|
||||
|
||||
@NotNull
|
||||
private static final FunctionIntrinsic RETURN_RECEIVER = new FunctionIntrinsic() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver,
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
assert receiver != null;
|
||||
assert arguments.isEmpty();
|
||||
return receiver;
|
||||
@@ -65,27 +50,68 @@ public final class NumberConversionFIF extends CompositeFIF {
|
||||
|
||||
@NotNull
|
||||
public static final String INTEGER_NUMBER_TYPES = "Int|Byte|Short";
|
||||
//NOTE: treat Number as if it is floating point type
|
||||
|
||||
@NotNull
|
||||
private static final String FLOATING_POINT_NUMBER_TYPES = "Float|Double|Number";
|
||||
@NotNull
|
||||
private static final FunctionIntrinsic GET_INTEGER_PART = new FunctionIntrinsic() {
|
||||
private static final FunctionIntrinsic TO_INT32 = new FunctionIntrinsic() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver,
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
assert receiver != null;
|
||||
assert arguments.isEmpty();
|
||||
return JsAstUtils.toInt32(receiver, context);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private static final FunctionIntrinsic TO_SHORT = new FunctionIntrinsic() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
assert receiver != null;
|
||||
assert arguments.isEmpty();
|
||||
return JsAstUtils.toShort(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private static final FunctionIntrinsic TO_BYTE = new FunctionIntrinsic() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
assert receiver != null;
|
||||
assert arguments.isEmpty();
|
||||
return JsAstUtils.toByte(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private static final Predicate<FunctionDescriptor> returnReceiverPredicate = Predicates.or(
|
||||
pattern("Int.toInt|toFloat|toDouble"),
|
||||
pattern("Short.toShort|toInt|toFloat|toDouble"),
|
||||
pattern("Byte.toByte|toShort|toInt|toFloat|toDouble"),
|
||||
pattern("Float|Double|Number.toFloat|toDouble")
|
||||
);
|
||||
|
||||
@NotNull
|
||||
public static final FunctionIntrinsicFactory INSTANCE = new NumberConversionFIF();
|
||||
|
||||
//NOTE: treat Number as if it is floating point type
|
||||
private NumberConversionFIF() {
|
||||
add(pattern(INTEGER_NUMBER_TYPES, SUPPORTED_CONVERSIONS), RETURN_RECEIVER);
|
||||
add(pattern(FLOATING_POINT_NUMBER_TYPES, INTEGER_CONVERSIONS), GET_INTEGER_PART);
|
||||
add(pattern(FLOATING_POINT_NUMBER_TYPES, FLOATING_POINT_CONVERSIONS), RETURN_RECEIVER);
|
||||
add(returnReceiverPredicate, RETURN_RECEIVER);
|
||||
add(pattern("Float|Double|Number.toInt"), TO_INT32);
|
||||
add(pattern("Int|Float|Double|Number.toShort"), TO_SHORT);
|
||||
add(pattern("Short|Int|Float|Double|Number.toByte"), TO_BYTE);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -87,7 +87,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 1;
|
||||
return JsAstUtils.compareTo(receiver, arguments.get(0), context);
|
||||
return JsAstUtils.compareTo(receiver, arguments.get(0));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -123,6 +123,16 @@ public final class JsAstUtils {
|
||||
return new JsBinaryOperation(JsBinaryOperator.BIT_OR, expression, context.program().getNumberLiteral(0));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression toShort(@NotNull JsExpression expression) {
|
||||
return new JsInvocation(new JsNameRef(OperatorConventions.SHORT.getIdentifier(), Namer.KOTLIN_OBJECT_REF), expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression toByte(@NotNull JsExpression expression) {
|
||||
return new JsInvocation(new JsNameRef(OperatorConventions.BYTE.getIdentifier(), Namer.KOTLIN_OBJECT_REF), expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression compareTo(@NotNull JsExpression left, @NotNull JsExpression right) {
|
||||
return new JsInvocation(new JsNameRef(OperatorConventions.COMPARE_TO.getIdentifier(), Namer.KOTLIN_OBJECT_REF), left, right);
|
||||
|
||||
@@ -89,6 +89,14 @@
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
};
|
||||
|
||||
Kotlin.toShort = function(a) {
|
||||
return (a & 0xFFFF) << 16 >> 16;
|
||||
};
|
||||
|
||||
Kotlin.toByte = function(a) {
|
||||
return (a & 0xFF) << 24 >> 24;
|
||||
};
|
||||
|
||||
Kotlin.intUpto = function (from, to) {
|
||||
return new Kotlin.NumberRange(from, to);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package foo
|
||||
|
||||
fun box(): String {
|
||||
|
||||
assertEquals(65, 321.0.toByte())
|
||||
assertEquals(-56, 200.0.toByte())
|
||||
|
||||
assertEquals(65, 321.0f.toByte())
|
||||
assertEquals(-56, 200.0f.toByte())
|
||||
|
||||
assertEquals(65, 321.toByte())
|
||||
assertEquals(-56, 200.toByte())
|
||||
|
||||
assertEquals(65, (321: Short).toByte())
|
||||
assertEquals(-56, (200: Short).toByte())
|
||||
|
||||
assertEquals(-1, 65535.0.toShort())
|
||||
assertEquals(-1, 65535.0f.toShort())
|
||||
assertEquals(-1, 65535.toShort())
|
||||
|
||||
assertEquals(65535, 65535.2.toInt())
|
||||
assertEquals(23, 23.6f.toInt())
|
||||
assertEquals(-12, -12.4.toShort())
|
||||
assertEquals(-12, -12.4.toByte())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package foo
|
||||
|
||||
fun testForNumber(numberX: Number) {
|
||||
assertEquals(true, 65.0 == numberX.toDouble())
|
||||
assertEquals(true, 65.0f == numberX.toFloat())
|
||||
assertEquals(true, 65 == numberX.toInt())
|
||||
assertEquals(true, (65: Short) == numberX.toShort())
|
||||
assertEquals(true, (65: Byte) == numberX.toByte())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
|
||||
testForNumber(65.0)
|
||||
testForNumber(65.0f)
|
||||
testForNumber(65)
|
||||
testForNumber(65: Short)
|
||||
testForNumber(65: Byte)
|
||||
|
||||
var doubleX: Double = 65.0
|
||||
assertEquals(true, 65.0 == doubleX.toDouble())
|
||||
assertEquals(true, 65.0f == doubleX.toFloat())
|
||||
assertEquals(true, 65 == doubleX.toInt())
|
||||
assertEquals(true, (65: Short) == doubleX.toShort())
|
||||
assertEquals(true, (65: Byte) == doubleX.toByte())
|
||||
|
||||
var floatX: Float = 65.0f
|
||||
assertEquals(true, 65.0 == floatX.toDouble())
|
||||
assertEquals(true, 65.0f == floatX.toFloat())
|
||||
assertEquals(true, 65 == floatX.toInt())
|
||||
assertEquals(true, (65: Short) == floatX.toShort())
|
||||
assertEquals(true, (65: Byte) == floatX.toByte())
|
||||
|
||||
val intX: Int = 65
|
||||
assertEquals(true, 65.0 == intX.toDouble())
|
||||
assertEquals(true, 65.0f == intX.toFloat())
|
||||
assertEquals(true, 65 == intX.toInt())
|
||||
assertEquals(true, (65: Short) == intX.toShort())
|
||||
assertEquals(true, (65: Byte) == intX.toByte())
|
||||
|
||||
val shortX: Short = 65: Short
|
||||
assertEquals(true, 65.0 == shortX.toDouble())
|
||||
assertEquals(true, 65.0f == shortX.toFloat())
|
||||
assertEquals(true, 65 == shortX.toInt())
|
||||
assertEquals(true, (65: Short) == shortX.toShort())
|
||||
assertEquals(true, (65: Byte) == shortX.toByte())
|
||||
|
||||
val byteX: Byte = 65: Byte
|
||||
assertEquals(true, 65.0 == byteX.toDouble())
|
||||
assertEquals(true, 65.0f == byteX.toFloat())
|
||||
assertEquals(true, 65 == byteX.toInt())
|
||||
assertEquals(true, (65: Short) == byteX.toShort())
|
||||
assertEquals(true, (65: Byte) == byteX.toByte())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user