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 {
|
public void testNumberCompareTo() throws Exception {
|
||||||
checkFooBoxIsOk();
|
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;
|
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 com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.context.TranslationContext;
|
||||||
import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic;
|
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 org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||||
|
|
||||||
import java.util.List;
|
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;
|
import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern;
|
||||||
|
|
||||||
|
//TODO: support longs and chars
|
||||||
public final class NumberConversionFIF extends CompositeFIF {
|
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
|
@NotNull
|
||||||
private static final FunctionIntrinsic RETURN_RECEIVER = new FunctionIntrinsic() {
|
private static final FunctionIntrinsic RETURN_RECEIVER = new FunctionIntrinsic() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public JsExpression apply(@Nullable JsExpression receiver,
|
public JsExpression apply(
|
||||||
|
@Nullable JsExpression receiver,
|
||||||
@NotNull List<JsExpression> arguments,
|
@NotNull List<JsExpression> arguments,
|
||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context
|
||||||
|
) {
|
||||||
assert receiver != null;
|
assert receiver != null;
|
||||||
assert arguments.isEmpty();
|
assert arguments.isEmpty();
|
||||||
return receiver;
|
return receiver;
|
||||||
@@ -65,27 +50,68 @@ public final class NumberConversionFIF extends CompositeFIF {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static final String INTEGER_NUMBER_TYPES = "Int|Byte|Short";
|
public static final String INTEGER_NUMBER_TYPES = "Int|Byte|Short";
|
||||||
//NOTE: treat Number as if it is floating point type
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static final String FLOATING_POINT_NUMBER_TYPES = "Float|Double|Number";
|
private static final FunctionIntrinsic TO_INT32 = new FunctionIntrinsic() {
|
||||||
@NotNull
|
|
||||||
private static final FunctionIntrinsic GET_INTEGER_PART = new FunctionIntrinsic() {
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public JsExpression apply(@Nullable JsExpression receiver,
|
public JsExpression apply(
|
||||||
|
@Nullable JsExpression receiver,
|
||||||
@NotNull List<JsExpression> arguments,
|
@NotNull List<JsExpression> arguments,
|
||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context
|
||||||
|
) {
|
||||||
assert receiver != null;
|
assert receiver != null;
|
||||||
assert arguments.isEmpty();
|
assert arguments.isEmpty();
|
||||||
return JsAstUtils.toInt32(receiver, context);
|
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
|
@NotNull
|
||||||
public static final FunctionIntrinsicFactory INSTANCE = new NumberConversionFIF();
|
public static final FunctionIntrinsicFactory INSTANCE = new NumberConversionFIF();
|
||||||
|
|
||||||
|
//NOTE: treat Number as if it is floating point type
|
||||||
private NumberConversionFIF() {
|
private NumberConversionFIF() {
|
||||||
add(pattern(INTEGER_NUMBER_TYPES, SUPPORTED_CONVERSIONS), RETURN_RECEIVER);
|
add(returnReceiverPredicate, RETURN_RECEIVER);
|
||||||
add(pattern(FLOATING_POINT_NUMBER_TYPES, INTEGER_CONVERSIONS), GET_INTEGER_PART);
|
add(pattern("Float|Double|Number.toInt"), TO_INT32);
|
||||||
add(pattern(FLOATING_POINT_NUMBER_TYPES, FLOATING_POINT_CONVERSIONS), RETURN_RECEIVER);
|
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 receiver != null;
|
||||||
assert arguments.size() == 1;
|
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));
|
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
|
@NotNull
|
||||||
public static JsExpression compareTo(@NotNull JsExpression left, @NotNull JsExpression right) {
|
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);
|
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;
|
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) {
|
Kotlin.intUpto = function (from, to) {
|
||||||
return new Kotlin.NumberRange(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