JS: fixed Double.NaN behaviour (KT-13610).

This commit is contained in:
Anton Bannykh
2017-02-27 18:44:50 +03:00
parent f636ab21f8
commit 9e5ecc11b7
12 changed files with 357 additions and 63 deletions
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS
data class Test(val z1: Double, val z2: Double?)
fun box(): String {
+223
View File
@@ -0,0 +1,223 @@
// WITH_RUNTIME
import kotlin.test.*
object O {
var equalsCalled: Boolean = false
get(): Boolean {
val result = field
field = false
return result
}
set(v: Boolean) {
field = v
}
override fun equals(a: Any?): Boolean {
equalsCalled = true
return true
}
}
val A: Any = O
fun <T: Double> testDouble(d: Double, v: T, vararg va: T) {
assertFalse(d == d, "Double: d != d")
assertFalse(d == v, "Double: d != v")
assertFalse(d == va[0], "Double: d != va[0]")
assertFalse(v == d, "Double: v != d")
assertFalse(v == v, "Double: v != v")
assertFalse(v == va[0], "Double: v != va[0]")
assertFalse(va[0] == d, "Double: va[0] != d")
assertFalse(va[0] == v, "Double: va[0] != v")
assertFalse(va[0] == va[0], "Double: va[0] != va[0]")
assertTrue(d != d, "Double: d == d")
assertTrue(d != v, "Double: d == v")
assertTrue(d != va[0], "Double: d == va[0]")
assertTrue(v != d, "Double: v == d")
assertTrue(v != v, "Double: v == v")
assertTrue(v != va[0], "Double: v == va[0]")
assertTrue(va[0] != d, "Double: va[0] == d")
assertTrue(va[0] != v, "Double: va[0] == v")
assertTrue(va[0] != va[0], "Double: va[0] == va[0]")
}
fun <T: Float> testFloat(d: Float, v: T, vararg va: T) {
assertFalse(d == d, "Float: d != d")
assertFalse(d == v, "Float: d != v")
assertFalse(d == va[0], "Float: d != va[0]")
assertFalse(v == d, "Float: v != d")
assertFalse(v == v, "Float: v != v")
assertFalse(v == va[0], "Float: v != va[0]")
assertFalse(va[0] == d, "Float: va[0] != d")
assertFalse(va[0] == v, "Float: va[0] != v")
assertFalse(va[0] == va[0], "Float: va[0] != va[0]")
assertTrue(d != d, "Float: d == d")
assertTrue(d != v, "Float: d == v")
assertTrue(d != va[0], "Float: d == va[0]")
assertTrue(v != d, "Float: v == d")
assertTrue(v != v, "Float: v == v")
assertTrue(v != va[0], "Float: v == va[0]")
assertTrue(va[0] != d, "Float: va[0] == d")
assertTrue(va[0] != v, "Float: va[0] == v")
assertTrue(va[0] != va[0], "Float: va[0] == va[0]")
}
var gdn: Any = Double.NaN
var gfn: Any = Float.NaN
fun box(): String {
// Double
val dn = Double.NaN
val adn: Any = dn
val dnq: Double? = dn
val adnq: Any? = dn
assertFalse(dn == dn, "Double: NaN == NaN")
assertTrue(dn == adn, "Double: NaN != (Any)NaN")
assertTrue(adn == dn, "Double: (Any)NaN != NaN")
assertTrue(adn == adn, "Double: (Any)NaN != (Any)NaN")
assertFalse(dn == dnq, "Double: NaN == NaN?")
assertTrue(dn == adnq, "Double: NaN != (Any?)NaN")
assertTrue(adn == dnq, "Double: (Any)NaN != NaN?")
assertTrue(adn == adnq, "Double: (Any)NaN != (Any?)NaN")
assertFalse(dnq == dn, "Double: NaN? == NaN")
assertTrue(dnq == adn, "Double: NaN? != (Any)NaN")
assertTrue(adnq == dn, "Double: (Any?)NaN != NaN")
assertTrue(adnq == adn, "Double: (Any?)NaN != (Any)NaN")
assertFalse(dnq == dnq, "Double: NaN? == NaN?")
assertTrue(dnq == adnq, "Double: NaN? != (Any?)NaN")
assertTrue(adnq == dnq, "Double: (Any?)NaN != NaN?")
assertTrue(adnq == adnq, "Double: (Any?)NaN != (Any?)NaN")
assertTrue(dn != dn, "Double: NaN == NaN")
assertFalse(dn != adn, "Double: NaN != (Any)NaN")
assertFalse(adn != dn, "Double: (Any)NaN != NaN")
assertFalse(adn != adn, "Double: (Any)NaN != (Any)NaN")
assertTrue(dn != dnq, "Double: NaN == NaN?")
assertFalse(dn != adnq, "Double: NaN != (Any?)NaN")
assertFalse(adn != dnq, "Double: (Any)NaN != NaN?")
assertFalse(adn != adnq, "Double: (Any)NaN != (Any?)NaN")
assertTrue(dnq != dn, "Double: NaN? == NaN")
assertFalse(dnq != adn, "Double: NaN? != (Any)NaN")
assertFalse(adnq != dn, "Double: (Any?)NaN != NaN")
assertFalse(adnq != adn, "Double: (Any?)NaN != (Any)NaN")
assertTrue(dnq != dnq, "Double: NaN? == NaN?")
assertFalse(dnq != adnq, "Double: NaN? != (Any?)NaN")
assertFalse(adnq != dnq, "Double: (Any?)NaN != NaN?")
assertFalse(adnq != adnq, "Double: (Any?)NaN != (Any?)NaN")
// Stable smart-casts
if (adn is Double) {
assertFalse(adn == adn, "Double smart-cast: NaN == NaN")
assertTrue(adn != adn, "Double smart-cast: NaN == NaN")
}
if (adnq is Double?) {
assertFalse(adnq == adnq, "Double? smart-cast: NaN? == NaN?")
assertTrue(adnq != adnq, "Double? smart-cast: NaN? == NaN?")
}
// Unstable smart-casts
if (gdn is Double) {
assertTrue(gdn == gdn, "Unstable Double smart-cast: NaN != NaN")
assertFalse(gdn != gdn, "Unstable Double smart-cast: NaN != NaN")
}
if (gdn is Double?) {
assertTrue(gdn == gdn, "Unstable Double smart-cast: NaN != NaN")
assertFalse(gdn != gdn, "Unstable Double smart-cast: NaN != NaN")
}
// Explicit .equals
assertTrue(A == dn && O.equalsCalled, "A.equals not called for A == dn")
assertTrue(dn != A && !O.equalsCalled, "A.equals called for dn == A")
assertFalse(A != dn || !O.equalsCalled, "A.equals not called for A != dn")
assertFalse(dn == A || O.equalsCalled, "A.equals called for dn != A")
// Generics and varags
testDouble(Double.NaN, Double.NaN, Double.NaN)
// Float
val fn = Float.NaN
val afn: Any = fn
val fnq: Float? = fn
val afnq: Any? = fn
assertFalse(fn == fn, "Float: NaN == NaN")
assertTrue(fn == afn, "Float: NaN != (Any)NaN")
assertTrue(afn == fn, "Float: (Any)NaN != NaN")
assertTrue(afn == afn, "Float: (Any)NaN != (Any)NaN")
assertFalse(fn == fnq, "Float: NaN == NaN?")
assertTrue(fn == afnq, "Float: NaN != (Any?)NaN")
assertTrue(afn == fnq, "Float: (Any)NaN != NaN?")
assertTrue(afn == afnq, "Float: (Any)NaN != (Any?)NaN")
assertFalse(fnq == fn, "Float: NaN? == NaN")
assertTrue(fnq == afn, "Float: NaN? != (Any)NaN")
assertTrue(afnq == fn, "Float: (Any?)NaN != NaN")
assertTrue(afnq == afn, "Float: (Any?)NaN != (Any)NaN")
assertFalse(fnq == fnq, "Float: NaN? == NaN?")
assertTrue(fnq == afnq, "Float: NaN? != (Any?)NaN")
assertTrue(afnq == fnq, "Float: (Any?)NaN != NaN?")
assertTrue(afnq == afnq, "Float: (Any?)NaN != (Any?)NaN")
assertTrue(fn != fn, "Float: NaN == NaN")
assertFalse(fn != afn, "Float: NaN != (Any)NaN")
assertFalse(afn != fn, "Float: (Any)NaN != NaN")
assertFalse(afn != afn, "Float: (Any)NaN != (Any)NaN")
assertTrue(fn != fnq, "Float: NaN == NaN?")
assertFalse(fn != afnq, "Float: NaN != (Any?)NaN")
assertFalse(afn != fnq, "Float: (Any)NaN != NaN?")
assertFalse(afn != afnq, "Float: (Any)NaN != (Any?)NaN")
assertTrue(fnq != fn, "Float: NaN? == NaN")
assertFalse(fnq != afn, "Float: NaN? != (Any)NaN")
assertFalse(afnq != fn, "Float: (Any?)NaN != NaN")
assertFalse(afnq != afn, "Float: (Any?)NaN != (Any)NaN")
assertTrue(fnq != fnq, "Float: NaN? == NaN?")
assertFalse(fnq != afnq, "Float: NaN? != (Any?)NaN")
assertFalse(afnq != fnq, "Float: (Any?)NaN != NaN?")
assertFalse(afnq != afnq, "Float: (Any?)NaN != (Any?)NaN")
// Stable smart-casts
if (afn is Float) {
assertFalse(afn == afn, "Float smart-cast: NaN == NaN")
assertTrue(afn != afn, "Float smart-cast: NaN == NaN")
}
if (afnq is Float?) {
assertFalse(afnq == afnq, "Float? smart-cast: NaN? == NaN?")
assertTrue(afnq != afnq, "Float? smart-cast: NaN? == NaN?")
}
// Unstable smart-casts
if (gfn is Float) {
assertTrue(gfn == gfn, "Unstable Float smart-cast: NaN != NaN")
assertFalse(gfn != gfn, "Unstable Float smart-cast: NaN != NaN")
}
if (gfn is Float?) {
assertTrue(gfn == gfn, "Unstable Float smart-cast: NaN != NaN")
assertFalse(gfn != gfn, "Unstable Float smart-cast: NaN != NaN")
}
assertTrue(A == fn && O.equalsCalled, "A.equals not called for A == fn")
assertTrue(fn != A && !O.equalsCalled, "A.equals called for fn == A")
assertFalse(A != fn || !O.equalsCalled, "A.equals not called for A != fn")
assertFalse(fn == A || O.equalsCalled, "A.equals called for fn != A")
// Generics and varags
testFloat(Float.NaN, Float.NaN, Float.NaN)
return "OK"
}
@@ -0,0 +1,24 @@
@kotlin.Metadata
public final class EqualsNaNKt {
private final static @org.jetbrains.annotations.NotNull field A: java.lang.Object
private static @org.jetbrains.annotations.NotNull field gdn: java.lang.Object
private static @org.jetbrains.annotations.NotNull field gfn: java.lang.Object
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static @org.jetbrains.annotations.NotNull method getA(): java.lang.Object
public final static @org.jetbrains.annotations.NotNull method getGdn(): java.lang.Object
public final static @org.jetbrains.annotations.NotNull method getGfn(): java.lang.Object
public final static method setGdn(@org.jetbrains.annotations.NotNull p0: java.lang.Object): void
public final static method setGfn(@org.jetbrains.annotations.NotNull p0: java.lang.Object): void
public final static method testDouble(p0: double, p1: double, @org.jetbrains.annotations.NotNull p2: java.lang.Double[]): void
public final static method testFloat(p0: float, p1: float, @org.jetbrains.annotations.NotNull p2: java.lang.Float[]): void
}
@kotlin.Metadata
public final class O {
public final static field INSTANCE: O
private static field equalsCalled: boolean
private method <init>(): void
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public final method getEqualsCalled(): boolean
public final method setEqualsCalled(p0: boolean): void
}
@@ -8525,6 +8525,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("equalsNaN.kt")
public void testEqualsNaN() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNaN.kt");
doTest(fileName);
}
@TestMetadata("equalsNullableDouble.kt")
public void testEqualsNullableDouble() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNullableDouble.kt");
@@ -8525,6 +8525,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("equalsNaN.kt")
public void testEqualsNaN() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNaN.kt");
doTest(fileName);
}
@TestMetadata("equalsNullableDouble.kt")
public void testEqualsNullableDouble() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNullableDouble.kt");
@@ -878,8 +878,19 @@ public abstract class KotlinBuiltIns {
}
public static boolean isPrimitiveType(@NotNull KotlinType type) {
return !type.isMarkedNullable() && isPrimitiveTypeOrNullablePrimitiveType(type);
}
public static boolean isPrimitiveTypeOrNullablePrimitiveType(@NotNull KotlinType type) {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
return !type.isMarkedNullable() && descriptor instanceof ClassDescriptor && isPrimitiveClass((ClassDescriptor) descriptor);
return descriptor instanceof ClassDescriptor && isPrimitiveClass((ClassDescriptor) descriptor);
}
@Nullable
public static PrimitiveType getPrimitiveTypeByKotlinType(@NotNull KotlinType type) {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
if (descriptor == null) return null;
return getPrimitiveTypeByFqName(getFqName(descriptor));
}
public static boolean isPrimitiveClass(@NotNull ClassDescriptor descriptor) {
+4
View File
@@ -23,6 +23,10 @@ Kotlin.equals = function (obj1, obj2) {
return false;
}
if (obj1 !== obj1) {
return obj2 !== obj2;
}
if (typeof obj1 == "object" && typeof obj1.equals === "function") {
return obj1.equals(obj2);
}
@@ -9603,13 +9603,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("dataClass.kt")
public void testDataClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/dataClass.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("equalsDouble.kt")
@@ -9624,6 +9618,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("equalsNaN.kt")
public void testEqualsNaN() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNaN.kt");
doTest(fileName);
}
@TestMetadata("equalsNullableDouble.kt")
public void testEqualsNullableDouble() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNullableDouble.kt");
@@ -190,11 +190,7 @@ public final class Translation {
JsNode jsNode = translateExpression(expression, context, block);
if (jsNode instanceof JsExpression) {
KotlinType expressionType = context.bindingContext().getType(expression);
if (expressionType != null && KotlinBuiltIns.isCharOrNullableChar(expressionType) &&
(jsNode instanceof JsInvocation || jsNode instanceof JsNameRef || jsNode instanceof JsArrayAccess)) {
jsNode = JsAstUtils.boxedCharToChar((JsExpression) jsNode);
}
return (JsExpression) jsNode;
return unboxIfNeeded((JsExpression) jsNode, expressionType != null && KotlinBuiltIns.isCharOrNullableChar(expressionType));
}
assert jsNode instanceof JsStatement : "Unexpected node of type: " + jsNode.getClass().toString();
@@ -209,6 +205,16 @@ public final class Translation {
return JsLiteral.NULL;
}
@NotNull
public static JsExpression unboxIfNeeded(@NotNull JsExpression expression, boolean charOrNullableChar) {
if (charOrNullableChar &&
(expression instanceof JsInvocation || expression instanceof JsNameRef || expression instanceof JsArrayAccess)
) {
expression = JsAstUtils.boxedCharToChar(expression);
}
return expression;
}
@NotNull
public static JsStatement translateAsStatement(@NotNull KtExpression expression, @NotNull TranslationContext context) {
return translateAsStatement(expression, context, context.dynamicContext().jsBlock());
@@ -16,23 +16,26 @@
package org.jetbrains.kotlin.js.translate.intrinsic.operation
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation
import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsLiteral
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.patterns.NamePredicate
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.OperatorConventions
@@ -41,13 +44,26 @@ import java.util.*
object EqualsBOIF : BinaryOperationIntrinsicFactory {
private object EqualsIntrinsic : AbstractBinaryOperationIntrinsic() {
// Primitives with no boxing or tricky NaN behavior, represented by a Number at runtime.
// Whenever the left side of equality is of this type, equality could be tested via '==='.
private val SIMPLE_PRIMITIVES = EnumSet.of(PrimitiveType.BYTE, PrimitiveType.SHORT, PrimitiveType.INT)
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val isNegated = expression.isNegated()
if (right == JsLiteral.NULL || left == JsLiteral.NULL) {
return TranslationUtils.nullCheck(if (right == JsLiteral.NULL) left else right, isNegated)
}
else if (canUseSimpleEquals(expression, context)) {
return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ, left, right)
val ktLeft = checkNotNull(expression.left) { "No left-hand side: " + expression.text }
val ktRight = checkNotNull(expression.right) { "No right-hand side: " + expression.text }
val leftType = getRefinedType(ktLeft, context)?.let { KotlinBuiltIns.getPrimitiveTypeByKotlinType(it) }
val rightType = getRefinedType(ktRight, context)?.let { KotlinBuiltIns.getPrimitiveTypeByKotlinType(it) }
if (leftType != null && (leftType in SIMPLE_PRIMITIVES || leftType == rightType && leftType != PrimitiveType.LONG)) {
return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ,
Translation.unboxIfNeeded(left, leftType == PrimitiveType.CHAR),
Translation.unboxIfNeeded(right, rightType == PrimitiveType.CHAR))
}
val resolvedCall = expression.getResolvedCall(context.bindingContext())
@@ -61,15 +77,41 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
return JsBinaryOperation(if (isNegated) JsBinaryOperator.NEQ else JsBinaryOperator.EQ, left, right)
}
val result = TopLevelFIF.KOTLIN_EQUALS.apply(left, Arrays.asList<JsExpression>(right), context)
val maybeBoxedLeft = if (leftType == PrimitiveType.CHAR) JsAstUtils.charToBoxedChar(left) else left
val maybeBoxedRight = if (rightType == PrimitiveType.CHAR) JsAstUtils.charToBoxedChar(right) else right
val result = TopLevelFIF.KOTLIN_EQUALS.apply(maybeBoxedLeft, Arrays.asList<JsExpression>(maybeBoxedRight), context)
return if (isNegated) JsAstUtils.not(result) else result
}
private fun canUseSimpleEquals(expression: KtBinaryExpression, context: TranslationContext): Boolean {
val left = expression.left
assert(left != null) { "No left-hand side: " + expression.text }
val typeName = JsDescriptorUtils.getNameIfStandardType(left!!, context)
return typeName != null && NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS.apply(typeName)
/**
* Tries to get as precise statically known primitive type as possible - taking smart-casts and generic supertypes into account.
* This is needed to be compatible with JVM NaN behaviour, in particular the following two cases.
*
* // Smart-casts
* val a: Any = Double.NaN
* println(a == a) // true
* if (a is Double) {
* println(a == a) // false
* }
*
* // Generics with Double super-type
* fun <T: Double> foo(v: T) = println(v == v)
* foo(Double.NaN) // false
*
* Also see org/jetbrains/kotlin/codegen/codegenUtil.kt#calcTypeForIEEE754ArithmeticIfNeeded
*/
private fun getRefinedType(expression: KtExpression, context: TranslationContext): KotlinType? {
val bindingContext = context.bindingContext()
val descriptor = context.declarationDescriptor ?: context.currentModule
val ktType = bindingContext.getType(expression) ?: return null
val dataFlow = DataFlowValueFactory.createDataFlowValue(expression, ktType, bindingContext, descriptor)
val isPrimitiveFn = KotlinBuiltIns::isPrimitiveTypeOrNullablePrimitiveType
return bindingContext.getDataFlowInfoBefore(expression).getStableTypes(dataFlow).find(isPrimitiveFn) ?: // Smart-casts
TypeUtils.getAllSupertypes(ktType).find(isPrimitiveFn) ?: // Generic super-types
ktType // Default
}
}
@@ -92,21 +134,6 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
else -> null
}
if (result != null && leftType != rightType) {
val leftChar = (leftType != null && KotlinBuiltIns.isCharOrNullableChar(leftType))
val rightChar = (rightType != null && KotlinBuiltIns.isCharOrNullableChar(rightType))
if (leftChar xor rightChar) {
return object : AbstractBinaryOperationIntrinsic() {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val maybeBoxedLeft = if (leftChar) JsAstUtils.charToBoxedChar(left) else left
val maybeBoxedRight = if (rightChar) JsAstUtils.charToBoxedChar(right) else right
return result.apply(expression, maybeBoxedLeft, maybeBoxedRight, context)
}
}
}
}
return result
}
@@ -22,10 +22,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
@@ -152,12 +148,6 @@ public final class JsDescriptorUtils {
!ModalityKt.isOverridableOrOverrides(propertyDescriptor);
}
@Nullable
public static Name getNameIfStandardType(@NotNull KtExpression expression, @NotNull TranslationContext context) {
KotlinType type = context.bindingContext().getType(expression);
return type != null ? DescriptorUtilsKt.getNameIfStandardType(type) : null;
}
@NotNull
public static String getModuleName(@NotNull DeclarationDescriptor descriptor) {
ModuleDescriptor moduleDescriptor = DescriptorUtils.getContainingModule(findRealInlineDeclaration(descriptor));
@@ -22,12 +22,11 @@ fun box(): String {
mapWithDoubleKeys[1.0] = 1
assertEquals("number", jsTypeOf (mapWithDoubleKeys.keys.iterator().next()), "mapWithDoubleKeys")
// boxed NaNs are not equal, KT-13610
// mapWithDoubleKeys.clear()
// var dNaN = 0.0 / 0.0
// mapWithDoubleKeys[dNaN] = 100
// assertEquals(100, mapWithDoubleKeys[dNaN])
// assertEquals("number", jsTypeOf (mapWithDoubleKeys.keys.iterator().next()), "dNaN")
mapWithDoubleKeys.clear()
var dNaN = 0.0 / 0.0
mapWithDoubleKeys[dNaN] = 100
assertEquals(100, mapWithDoubleKeys[dNaN])
assertEquals("number", jsTypeOf (mapWithDoubleKeys.keys.iterator().next()), "dNaN")
mapWithDoubleKeys.clear()
var dPositiveInfinity = +1.0 / 0.0
@@ -45,12 +44,11 @@ fun box(): String {
mapWithFloatKeys[1.0f] = 1
assertEquals("number", jsTypeOf (mapWithFloatKeys.keys.iterator().next()), "mapWithFloatKeys")
// boxed NaNs are not equal, KT-13610
// mapWithFloatKeys.clear()
// var fNaN: Float = 0.0f / 0.0f
// mapWithFloatKeys[fNaN] = 100
// assertEquals(100, mapWithFloatKeys[fNaN])
// assertEquals("number", jsTypeOf (mapWithFloatKeys.keys.iterator().next()), "fNaN")
mapWithFloatKeys.clear()
var fNaN: Float = 0.0f / 0.0f
mapWithFloatKeys[fNaN] = 100
assertEquals(100, mapWithFloatKeys[fNaN])
assertEquals("number", jsTypeOf (mapWithFloatKeys.keys.iterator().next()), "fNaN")
mapWithFloatKeys.clear()
var fPositiveInfinity = +1.0f / 0.0f