From ed80252ba8d748853eeb5dd3ebae94a3c60876fe Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Wed, 27 Dec 2017 21:18:05 +0300 Subject: [PATCH] JS: fix double compareTo behaviour for NaN and +-0 (KT-22723) --- .../arguments/CommonCompilerArguments.kt | 6 + .../arguments/K2JVMCompilerArguments.kt | 6 - .../kotlin/cli/common/CLICompiler.java | 3 + .../jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt | 4 - compiler/testData/cli/js/jsExtraHelp.out | 1 + compiler/testData/cli/jvm/extraHelp.out | 2 +- .../box/boxingOptimization/boxedRealsCmp.kt | 2 +- .../explicitEqualsOnDouble.kt | 1 - .../box/ieee754/asComparableToDouble.kt | 2 - ...omparableToDouble_properIeeeComparisons.kt | 1 - .../codegen/box/ieee754/comparableTypeCast.kt | 1 - .../box/ieee754/differentTypesComparison.kt | 62 ++++++ .../codegen/box/ieee754/equalsDouble.kt | 1 - .../codegen/box/ieee754/equalsFloat.kt | 1 - .../testData/codegen/box/ieee754/equalsNaN.kt | 1 - .../box/ieee754/equalsNullableDouble.kt | 1 - .../box/ieee754/equalsNullableFloat.kt | 1 - .../box/ieee754/explicitCompareCall.kt | 1 - .../codegen/box/ieee754/explicitEqualsCall.kt | 2 - .../codegen/box/ieee754/greaterDouble.kt | 1 - .../codegen/box/ieee754/greaterFloat.kt | 1 - .../testData/codegen/box/ieee754/inline.kt | 2 - .../codegen/box/ieee754/lessDouble.kt | 1 - .../testData/codegen/box/ieee754/lessFloat.kt | 1 - .../testData/codegen/box/ieee754/safeCall.kt | 1 - .../box/ieee754/smartCastToDifferentTypes.kt | 1 - ...astToDifferentTypesWithNumericPromotion.kt | 2 - ...hNumericPromotion_properIeeeComparisons.kt | 1 - compiler/testData/codegen/box/ieee754/when.kt | 1 - .../testData/codegen/box/ieee754/when10.kt | 1 - .../codegen/box/ieee754/whenNoSubject.kt | 1 - ...bleRangeLiteralVsComparableRangeLiteral.kt | 1 - .../ir/IrBlackBoxCodegenTestGenerated.java | 6 + .../codegen/BlackBoxCodegenTestGenerated.java | 6 + .../LightAnalysisModeTestGenerated.java | 6 + .../kotlin/builtins/KotlinBuiltIns.java | 4 + .../semantics/JsCodegenBoxTestGenerated.java | 206 +++--------------- .../expression/PatternTranslator.java | 24 +- .../js/translate/expression/WhenTranslator.kt | 6 +- .../functions/factories/LongOperationFIF.kt | 2 +- .../PrimitiveBinaryOperationFIF.java | 9 +- .../intrinsic/operation/CompareToBOIF.kt | 21 +- .../intrinsic/operation/EqualsBOIF.kt | 75 +++---- .../operation/binaryOperationIntrinsics.kt | 14 +- .../kotlin/js/translate/utils/utils.kt | 40 +++- libraries/stdlib/js/src/js/arrayUtils.js | 2 +- libraries/stdlib/js/src/js/core.js | 4 + libraries/stdlib/js/src/js/misc.js | 27 ++- .../stdlib/test/numbers/NaNPropagationTest.kt | 1 - 49 files changed, 260 insertions(+), 307 deletions(-) create mode 100644 compiler/testData/codegen/box/ieee754/differentTypesComparison.kt diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt index f055312aefb..27924c5332d 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt @@ -151,6 +151,12 @@ abstract class CommonCompilerArguments : CommonToolArguments() { ) var useExperimental: Array? by FreezableVar(null) + @Argument( + value = "-Xproper-ieee754-comparisons", + description = "Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types" + ) + var properIeee754Comparisons by FreezableVar(false) + open fun configureAnalysisFlags(collector: MessageCollector): MutableMap, Any> { return HashMap, Any>().apply { put(AnalysisFlag.skipMetadataVersionCheck, skipMetadataVersionCheck) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index b4cffdaddd8..c6275a1953d 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -224,12 +224,6 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { ) var noExceptionOnExplicitEqualsForBoxedNull by FreezableVar(false) - @Argument( - value = "-Xproper-ieee754-comparisons", - description = "Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types" - ) - var properIeee754Comparisons by FreezableVar(false) - // Paths to output directories for friend modules. var friendPaths: Array? by FreezableVar(null) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java index ff0810eecc3..c2ac5f690db 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java @@ -226,6 +226,9 @@ public abstract class CLICompiler extends CLI extraLanguageFeatures.put(LanguageFeature.ReadDeserializedContracts, LanguageFeature.State.ENABLED); } + if (arguments.getProperIeee754Comparisons()) { + extraLanguageFeatures.put(LanguageFeature.ProperIeee754Comparisons, LanguageFeature.State.ENABLED); + } setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, arguments); diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index 19cbb66f9a0..32c33540b0d 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -235,10 +235,6 @@ class K2JVMCompiler : CLICompiler() { extraLanguageFeatures[LanguageFeature.StrictJavaNullabilityAssertions] = LanguageFeature.State.ENABLED } - if (commandLineArguments.properIeee754Comparisons) { - extraLanguageFeatures[LanguageFeature.ProperIeee754Comparisons] = LanguageFeature.State.ENABLED - } - super.setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, commandLineArguments) } diff --git a/compiler/testData/cli/js/jsExtraHelp.out b/compiler/testData/cli/js/jsExtraHelp.out index 1e64a902713..e504657eb9d 100644 --- a/compiler/testData/cli/js/jsExtraHelp.out +++ b/compiler/testData/cli/js/jsExtraHelp.out @@ -15,6 +15,7 @@ where advanced options include: -Xno-check-actual Do not check presence of 'actual' modifier in multi-platform projects -Xno-inline Disable method inlining -Xplugin= Load plugins from the given classpath + -Xproper-ieee754-comparisons Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types -Xread-deserialized-contracts Enable reading of contracts from metadata -Xrepeat= Repeat compilation (for performance analysis) -Xreport-output-files Report source to output files mapping diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index 664bd81fb4f..b2b1d08f213 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -28,7 +28,6 @@ where advanced options include: -Xno-optimize Disable optimizations -Xno-param-assertions Don't generate not-null assertions on parameters of methods accessible from Java -Xno-receiver-assertions Don't generate not-null assertion for extension receiver arguments of platform types - -Xproper-ieee754-comparisons Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types -Xreport-perf Report detailed performance statistics -Xscript-resolver-environment= Script resolver environment in key-value pairs (the value could be quoted and escaped) @@ -53,6 +52,7 @@ where advanced options include: -Xno-check-actual Do not check presence of 'actual' modifier in multi-platform projects -Xno-inline Disable method inlining -Xplugin= Load plugins from the given classpath + -Xproper-ieee754-comparisons Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types -Xread-deserialized-contracts Enable reading of contracts from metadata -Xrepeat= Repeat compilation (for performance analysis) -Xreport-output-files Report source to output files mapping diff --git a/compiler/testData/codegen/box/boxingOptimization/boxedRealsCmp.kt b/compiler/testData/codegen/box/boxingOptimization/boxedRealsCmp.kt index 20db67feeb0..eace35f1888 100644 --- a/compiler/testData/codegen/box/boxingOptimization/boxedRealsCmp.kt +++ b/compiler/testData/codegen/box/boxingOptimization/boxedRealsCmp.kt @@ -1,4 +1,4 @@ -// IGNORE_BACKEND: JS, NATIVE +// IGNORE_BACKEND: NATIVE inline fun ltx(a: Comparable, b: Any) = a < b inline fun lex(a: Comparable, b: Any) = a <= b diff --git a/compiler/testData/codegen/box/boxingOptimization/explicitEqualsOnDouble.kt b/compiler/testData/codegen/box/boxingOptimization/explicitEqualsOnDouble.kt index d515e1d9db2..19130d51cb5 100644 --- a/compiler/testData/codegen/box/boxingOptimization/explicitEqualsOnDouble.kt +++ b/compiler/testData/codegen/box/boxingOptimization/explicitEqualsOnDouble.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS // IGNORE_BACKEND: NATIVE fun equals1(a: Double, b: Double) = a.equals(b) diff --git a/compiler/testData/codegen/box/ieee754/asComparableToDouble.kt b/compiler/testData/codegen/box/ieee754/asComparableToDouble.kt index 9ae66414371..d215f9a5f05 100644 --- a/compiler/testData/codegen/box/ieee754/asComparableToDouble.kt +++ b/compiler/testData/codegen/box/ieee754/asComparableToDouble.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JS - val minus: Any = -0.0 fun box(): String { diff --git a/compiler/testData/codegen/box/ieee754/asComparableToDouble_properIeeeComparisons.kt b/compiler/testData/codegen/box/ieee754/asComparableToDouble_properIeeeComparisons.kt index b0f1c933dbc..b5e651e395f 100644 --- a/compiler/testData/codegen/box/ieee754/asComparableToDouble_properIeeeComparisons.kt +++ b/compiler/testData/codegen/box/ieee754/asComparableToDouble_properIeeeComparisons.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +ProperIeee754Comparisons -// IGNORE_BACKEND: JS val minus: Any = -0.0 diff --git a/compiler/testData/codegen/box/ieee754/comparableTypeCast.kt b/compiler/testData/codegen/box/ieee754/comparableTypeCast.kt index a4298207118..368da4d0289 100644 --- a/compiler/testData/codegen/box/ieee754/comparableTypeCast.kt +++ b/compiler/testData/codegen/box/ieee754/comparableTypeCast.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS fun box(): String { if ((-0.0 as Comparable) >= 0.0) return "fail 0" if ((-0.0F as Comparable) >= 0.0F) return "fail 1" diff --git a/compiler/testData/codegen/box/ieee754/differentTypesComparison.kt b/compiler/testData/codegen/box/ieee754/differentTypesComparison.kt new file mode 100644 index 00000000000..c72ad2a2038 --- /dev/null +++ b/compiler/testData/codegen/box/ieee754/differentTypesComparison.kt @@ -0,0 +1,62 @@ +fun box(): String { + if (0.toByte().compareTo(-0.0) != 1) return "fail 1.1" + if (0.toByte().compareTo(-0.0F) != 1) return "fail 1.2" + if (0.toByte().compareTo(Double.NaN) != -1) return "fail 1.3" + if (0.toByte().compareTo(Float.NaN) != -1) return "fail 1.4" + + if (0.toShort().compareTo(-0.0) != 1) return "fail 2.1" + if (0.toShort().compareTo(-0.0F) != 1) return "fail 2.2" + if (0.toShort().compareTo(Double.NaN) != -1) return "fail 2.3" + if (0.toShort().compareTo(Float.NaN) != -1) return "fail 2.4" + + if (0.compareTo(-0.0) != 1) return "fail 3.1" + if (0.compareTo(-0.0F) != 1) return "fail 3.2" + if (0.compareTo(Double.NaN) != -1) return "fail 3.3" + if (0.compareTo(Float.NaN) != -1) return "fail 3.4" + + if (0.0F.compareTo(-0.0) != 1) return "fail 4.1" + if (0.0F.compareTo(-0.0F) != 1) return "fail 4.2" + if (0.0F.compareTo(Double.NaN) != -1) return "fail 4.3" + if (0.0F.compareTo(Float.NaN) != -1) return "fail 4.4" + + if (0.0.compareTo(-0.0) != 1) return "fail 5.1" + if (0.0.compareTo(-0.0F) != 1) return "fail 5.2" + if (0.0.compareTo(Double.NaN) != -1) return "fail 5.3" + if (0.0.compareTo(Float.NaN) != -1) return "fail 5.4" + + if (0L.compareTo(-0.0) != 1) return "fail 6.1" + if (0L.compareTo(-0.0F) != 1) return "fail 6.2" + if (0L.compareTo(Double.NaN) != -1) return "fail 6.3" + if (0L.compareTo(Float.NaN) != -1) return "fail 6.4" + + + if ((-0.0).compareTo(0.toByte()) != -1) return "fail 7.1" + if ((-0.0).compareTo(0.toShort()) != -1) return "fail 7.2" + if ((-0.0).compareTo(0) != -1) return "fail 7.3" + if ((-0.0).compareTo(0.0F) != -1) return "fail 7.4" + if ((-0.0).compareTo(0.0) != -1) return "fail 7.5" + if ((-0.0).compareTo(0L) != -1) return "fail 7.6" + + if ((-0.0F).compareTo(0.toByte()) != -1) return "fail 8.1" + if ((-0.0F).compareTo(0.toShort()) != -1) return "fail 8.2" + if ((-0.0F).compareTo(0) != -1) return "fail 8.3" + if ((-0.0F).compareTo(0.0F) != -1) return "fail 8.4" + if ((-0.0F).compareTo(0.0) != -1) return "fail 8.5" + if ((-0.0F).compareTo(0L) != -1) return "fail 8.6" + + if (Double.NaN.compareTo(0.toByte()) != 1) return "fail 9.1" + if (Double.NaN.compareTo(0.toShort()) != 1) return "fail 9.2" + if (Double.NaN.compareTo(0) != 1) return "fail 9.3" + if (Double.NaN.compareTo(0.0F) != 1) return "fail 9.4" + if (Double.NaN.compareTo(0.0) != 1) return "fail 9.5" + if (Double.NaN.compareTo(0L) != 1) return "fail 9.6" + + if (Float.NaN.compareTo(0.toByte()) != 1) return "fail 10.1" + if (Float.NaN.compareTo(0.toShort()) != 1) return "fail 10.2" + if (Float.NaN.compareTo(0) != 1) return "fail 10.3" + if (Float.NaN.compareTo(0.0F) != 1) return "fail 10.4" + if (Float.NaN.compareTo(0.0) != 1) return "fail 10.5" + if (Float.NaN.compareTo(0L) != 1) return "fail 10.6" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ieee754/equalsDouble.kt b/compiler/testData/codegen/box/ieee754/equalsDouble.kt index c9f3cae5697..499f21e39ba 100644 --- a/compiler/testData/codegen/box/ieee754/equalsDouble.kt +++ b/compiler/testData/codegen/box/ieee754/equalsDouble.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun equals1(a: Double, b: Double) = a == b diff --git a/compiler/testData/codegen/box/ieee754/equalsFloat.kt b/compiler/testData/codegen/box/ieee754/equalsFloat.kt index 822c6e17950..b4afc50c035 100644 --- a/compiler/testData/codegen/box/ieee754/equalsFloat.kt +++ b/compiler/testData/codegen/box/ieee754/equalsFloat.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun equals1(a: Float, b: Float) = a == b diff --git a/compiler/testData/codegen/box/ieee754/equalsNaN.kt b/compiler/testData/codegen/box/ieee754/equalsNaN.kt index 1e6ab618d1f..66385efcc21 100644 --- a/compiler/testData/codegen/box/ieee754/equalsNaN.kt +++ b/compiler/testData/codegen/box/ieee754/equalsNaN.kt @@ -1,6 +1,5 @@ // !LANGUAGE: -ProperIeee754Comparisons // WITH_RUNTIME -// IGNORE_BACKEND: JS import kotlin.test.* diff --git a/compiler/testData/codegen/box/ieee754/equalsNullableDouble.kt b/compiler/testData/codegen/box/ieee754/equalsNullableDouble.kt index 6da3e3dc1b1..665d843b131 100644 --- a/compiler/testData/codegen/box/ieee754/equalsNullableDouble.kt +++ b/compiler/testData/codegen/box/ieee754/equalsNullableDouble.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun equals1(a: Double, b: Double?) = a == b diff --git a/compiler/testData/codegen/box/ieee754/equalsNullableFloat.kt b/compiler/testData/codegen/box/ieee754/equalsNullableFloat.kt index d3db8eae0cb..950e2a401ef 100644 --- a/compiler/testData/codegen/box/ieee754/equalsNullableFloat.kt +++ b/compiler/testData/codegen/box/ieee754/equalsNullableFloat.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun equals1(a: Float, b: Float?) = a == b diff --git a/compiler/testData/codegen/box/ieee754/explicitCompareCall.kt b/compiler/testData/codegen/box/ieee754/explicitCompareCall.kt index 40409e20e4c..57d0b06328d 100644 --- a/compiler/testData/codegen/box/ieee754/explicitCompareCall.kt +++ b/compiler/testData/codegen/box/ieee754/explicitCompareCall.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS fun less1(a: Double, b: Double) = a.compareTo(b) == -1 fun less2(a: Double?, b: Double?) = a!!.compareTo(b!!) == -1 diff --git a/compiler/testData/codegen/box/ieee754/explicitEqualsCall.kt b/compiler/testData/codegen/box/ieee754/explicitEqualsCall.kt index 4a6f495d576..51dfd696f72 100644 --- a/compiler/testData/codegen/box/ieee754/explicitEqualsCall.kt +++ b/compiler/testData/codegen/box/ieee754/explicitEqualsCall.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JS - fun equals1(a: Double, b: Double) = a.equals(b) fun equals2(a: Double?, b: Double?) = a!!.equals(b!!) diff --git a/compiler/testData/codegen/box/ieee754/greaterDouble.kt b/compiler/testData/codegen/box/ieee754/greaterDouble.kt index c2d2c17aa77..5dbd15f7654 100644 --- a/compiler/testData/codegen/box/ieee754/greaterDouble.kt +++ b/compiler/testData/codegen/box/ieee754/greaterDouble.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun greater1(a: Double, b: Double) = a > b diff --git a/compiler/testData/codegen/box/ieee754/greaterFloat.kt b/compiler/testData/codegen/box/ieee754/greaterFloat.kt index 3e4c3dea819..c49d89fd450 100644 --- a/compiler/testData/codegen/box/ieee754/greaterFloat.kt +++ b/compiler/testData/codegen/box/ieee754/greaterFloat.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun greater1(a: Float, b: Float) = a > b diff --git a/compiler/testData/codegen/box/ieee754/inline.kt b/compiler/testData/codegen/box/ieee754/inline.kt index 58a844412bc..c1d3e721321 100644 --- a/compiler/testData/codegen/box/ieee754/inline.kt +++ b/compiler/testData/codegen/box/ieee754/inline.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JS - inline fun less(a: Comparable, b: Double): Boolean { return a < b } diff --git a/compiler/testData/codegen/box/ieee754/lessDouble.kt b/compiler/testData/codegen/box/ieee754/lessDouble.kt index 6de4793e15e..f3036a97577 100644 --- a/compiler/testData/codegen/box/ieee754/lessDouble.kt +++ b/compiler/testData/codegen/box/ieee754/lessDouble.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun less1(a: Double, b: Double) = a < b diff --git a/compiler/testData/codegen/box/ieee754/lessFloat.kt b/compiler/testData/codegen/box/ieee754/lessFloat.kt index 6fd2d721a06..138b0efbb2a 100644 --- a/compiler/testData/codegen/box/ieee754/lessFloat.kt +++ b/compiler/testData/codegen/box/ieee754/lessFloat.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun less1(a: Float, b: Float) = a < b diff --git a/compiler/testData/codegen/box/ieee754/safeCall.kt b/compiler/testData/codegen/box/ieee754/safeCall.kt index 5133ddaef43..690b6168935 100644 --- a/compiler/testData/codegen/box/ieee754/safeCall.kt +++ b/compiler/testData/codegen/box/ieee754/safeCall.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS fun box(): String { val plusZero: Double? = 0.0 val minusZero: Double = -0.0 diff --git a/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt b/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt index e3a06426db3..85edc8afadf 100644 --- a/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt +++ b/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS fun box(): String { val zero: Any = 0.0 val floatZero: Any = -0.0F diff --git a/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion.kt b/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion.kt index e28e840f43f..ba043ebf0fb 100644 --- a/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion.kt +++ b/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JS - fun eqDI(x: Any?, y: Any?) = x is Double? && y is Int? && x == y fun eqDL(x: Any?, y: Any?) = x is Double? && y is Long? && x == y fun eqID(x: Any?, y: Any?) = x is Int? && y is Double? && x == y diff --git a/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion_properIeeeComparisons.kt b/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion_properIeeeComparisons.kt index fb469e43383..5f0ad6a37af 100644 --- a/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion_properIeeeComparisons.kt +++ b/compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion_properIeeeComparisons.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun eqDI(x: Any?, y: Any?) = x is Double? && y is Int? && x == y fun eqDL(x: Any?, y: Any?) = x is Double? && y is Long? && x == y diff --git a/compiler/testData/codegen/box/ieee754/when.kt b/compiler/testData/codegen/box/ieee754/when.kt index 0c0119f664b..e5bec5d2324 100644 --- a/compiler/testData/codegen/box/ieee754/when.kt +++ b/compiler/testData/codegen/box/ieee754/when.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun box(): String { val plusZero: Any = 0.0 diff --git a/compiler/testData/codegen/box/ieee754/when10.kt b/compiler/testData/codegen/box/ieee754/when10.kt index 517efc7bebf..a43bdda966a 100644 --- a/compiler/testData/codegen/box/ieee754/when10.kt +++ b/compiler/testData/codegen/box/ieee754/when10.kt @@ -1,5 +1,4 @@ // LANGUAGE_VERSION: 1.0 -// IGNORE_BACKEND: JS fun box(): String { val plusZero: Any = 0.0 diff --git a/compiler/testData/codegen/box/ieee754/whenNoSubject.kt b/compiler/testData/codegen/box/ieee754/whenNoSubject.kt index 0a8a99040d1..21a40dd3444 100644 --- a/compiler/testData/codegen/box/ieee754/whenNoSubject.kt +++ b/compiler/testData/codegen/box/ieee754/whenNoSubject.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -ProperIeee754Comparisons -// IGNORE_BACKEND: JS fun box(): String { val plusZero: Any = 0.0 diff --git a/compiler/testData/codegen/box/ranges/contains/inDoubleRangeLiteralVsComparableRangeLiteral.kt b/compiler/testData/codegen/box/ranges/contains/inDoubleRangeLiteralVsComparableRangeLiteral.kt index 824d7ef428f..d6f8fccf329 100644 --- a/compiler/testData/codegen/box/ranges/contains/inDoubleRangeLiteralVsComparableRangeLiteral.kt +++ b/compiler/testData/codegen/box/ranges/contains/inDoubleRangeLiteralVsComparableRangeLiteral.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS // WITH_RUNTIME val DOUBLE_RANGE = 0.0 .. -0.0 diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 686a7ec60c9..6b83b041b9f 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -10125,6 +10125,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("differentTypesComparison.kt") + public void testDifferentTypesComparison() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/differentTypesComparison.kt"); + doTest(fileName); + } + @TestMetadata("equalsDouble.kt") public void testEqualsDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsDouble.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 0b0c6e5c9d9..81836cea482 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10125,6 +10125,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("differentTypesComparison.kt") + public void testDifferentTypesComparison() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/differentTypesComparison.kt"); + doTest(fileName); + } + @TestMetadata("equalsDouble.kt") public void testEqualsDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsDouble.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 757f97a2be1..ea2a6b8506c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10125,6 +10125,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("differentTypesComparison.kt") + public void testDifferentTypesComparison() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/differentTypesComparison.kt"); + doTest(fileName); + } + @TestMetadata("equalsDouble.kt") public void testEqualsDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsDouble.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index a7f8c1cd5a0..1b934443a33 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -946,6 +946,10 @@ public abstract class KotlinBuiltIns { return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._long); } + public static boolean isLongOrNullableLong(@NotNull KotlinType type) { + return isConstructedFromGivenClass(type, FQ_NAMES._long); + } + public static boolean isShort(@NotNull KotlinType type) { return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._short); } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 051b2987c14..b2983669a06 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -1122,13 +1122,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("boxedRealsCmp.kt") public void testBoxedRealsCmp() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/boxedRealsCmp.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("casts.kt") @@ -1152,13 +1146,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("explicitEqualsOnDouble.kt") public void testExplicitEqualsOnDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/explicitEqualsOnDouble.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("fold.kt") @@ -11028,25 +11016,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("asComparableToDouble.kt") public void testAsComparableToDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/asComparableToDouble.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("asComparableToDouble_properIeeeComparisons.kt") public void testAsComparableToDouble_properIeeeComparisons() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/asComparableToDouble_properIeeeComparisons.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("comparableToTWithT_properIeeeComparisons.kt") @@ -11058,13 +11034,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("comparableTypeCast.kt") public void testComparableTypeCast() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/comparableTypeCast.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("dataClass.kt") @@ -11073,16 +11043,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("differentTypesComparison.kt") + public void testDifferentTypesComparison() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/differentTypesComparison.kt"); + doTest(fileName); + } + @TestMetadata("equalsDouble.kt") public void testEqualsDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsDouble.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_properIeeeComparisons.kt") @@ -11094,13 +11064,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("equalsFloat.kt") public void testEqualsFloat() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsFloat.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("equalsFloat_properIeeeComparisons.kt") @@ -11112,13 +11076,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("equalsNaN.kt") public void testEqualsNaN() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNaN.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("equalsNaN_properIeeeComparisons.kt") @@ -11130,13 +11088,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("equalsNullableDouble.kt") public void testEqualsNullableDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNullableDouble.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("equalsNullableDouble_properIeeeComparisons.kt") @@ -11148,13 +11100,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("equalsNullableFloat.kt") public void testEqualsNullableFloat() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/equalsNullableFloat.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("equalsNullableFloat_properIeeeComparisons.kt") @@ -11166,25 +11112,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("explicitCompareCall.kt") public void testExplicitCompareCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/explicitCompareCall.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("explicitEqualsCall.kt") public void testExplicitEqualsCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/explicitEqualsCall.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("generic.kt") @@ -11196,13 +11130,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("greaterDouble.kt") public void testGreaterDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/greaterDouble.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("greaterDouble_properIeeeComparisons.kt") @@ -11214,13 +11142,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("greaterFloat.kt") public void testGreaterFloat() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/greaterFloat.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("greaterFloat_properIeeeComparisons.kt") @@ -11232,25 +11154,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("inline.kt") public void testInline() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/inline.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("lessDouble.kt") public void testLessDouble() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/lessDouble.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("lessDouble_properIeeeComparisons.kt") @@ -11262,13 +11172,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("lessFloat.kt") public void testLessFloat() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/lessFloat.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("lessFloat_properIeeeComparisons.kt") @@ -11346,13 +11250,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("safeCall.kt") public void testSafeCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/safeCall.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("smartCastOnWhenSubjectAfterCheckInBranch_properIeeeComparisons.kt") @@ -11364,37 +11262,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("smartCastToDifferentTypes.kt") public void testSmartCastToDifferentTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.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("smartCastToDifferentTypesWithNumericPromotion.kt") public void testSmartCastToDifferentTypesWithNumericPromotion() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion.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("smartCastToDifferentTypesWithNumericPromotion_properIeeeComparisons.kt") public void testSmartCastToDifferentTypesWithNumericPromotion_properIeeeComparisons() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion_properIeeeComparisons.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("smartCastToDifferentTypes_properIeeeComparisons.kt") @@ -11412,25 +11292,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("when.kt") public void testWhen() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/when.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("when10.kt") public void testWhen10() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/when10.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("when10_properIeeeComparisons.kt") @@ -11442,13 +11310,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("whenNoSubject.kt") public void testWhenNoSubject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ieee754/whenNoSubject.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("whenNoSubject_properIeeeComparisons.kt") @@ -16823,13 +16685,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("inDoubleRangeLiteralVsComparableRangeLiteral.kt") public void testInDoubleRangeLiteralVsComparableRangeLiteral() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inDoubleRangeLiteralVsComparableRangeLiteral.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("inExtensionRange.kt") diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java index 08926c5b3c1..6dd526cb1ff 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java @@ -34,16 +34,14 @@ import org.jetbrains.kotlin.js.translate.general.Translation; import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.ArrayFIF; import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF; import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator; -import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils; -import org.jetbrains.kotlin.js.translate.utils.BindingUtils; -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; -import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; +import org.jetbrains.kotlin.js.translate.utils.*; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtIsExpression; import org.jetbrains.kotlin.psi.KtTypeReference; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo; import org.jetbrains.kotlin.types.KotlinType; import java.util.Collections; @@ -272,16 +270,26 @@ public final class PatternTranslator extends AbstractTranslator { @NotNull public JsExpression translateExpressionPattern( - @NotNull KotlinType type, + @NotNull KtExpression subjectExpression, @NotNull JsExpression expressionToMatch, @NotNull KtExpression patternExpression ) { - JsExpression expressionToMatchAgainst = translateExpressionForExpressionPattern(patternExpression); - KotlinType patternType = BindingUtils.getTypeForExpression(bindingContext(), patternExpression); + PrimitiveNumericComparisonInfo ieeeInfo = UtilsKt.getPrimitiveNumericComparisonInfo(context(), patternExpression); - EqualityType matchEquality = equalityType(type); + KotlinType subjectType, patternType; + if (ieeeInfo != null) { + subjectType = ieeeInfo.getLeftType(); + patternType = ieeeInfo.getRightType(); + } else { + subjectType = UtilsKt.getPrecisePrimitiveTypeNotNull(context(), subjectExpression); + patternType = UtilsKt.getPrecisePrimitiveTypeNotNull(context(), patternExpression); + } + + EqualityType matchEquality = equalityType(subjectType); EqualityType patternEquality = equalityType(patternType); + JsExpression expressionToMatchAgainst = translateExpressionForExpressionPattern(patternExpression); + if (matchEquality == EqualityType.PRIMITIVE && patternEquality == EqualityType.PRIMITIVE) { return equality(expressionToMatch, expressionToMatchAgainst); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/WhenTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/WhenTranslator.kt index f5897b15c38..34e70d69a99 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/WhenTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/WhenTranslator.kt @@ -326,10 +326,8 @@ private constructor(private val whenExpression: KtWhenExpression, context: Trans val patternTranslator = Translation.patternTranslator(context) return if (expressionToMatch == null) { patternTranslator.translateExpressionForExpressionPattern(patternExpression) - } - else { - val type = bindingContext().getType(whenExpression.subjectExpression!!)!! - patternTranslator.translateExpressionPattern(type, expressionToMatch, patternExpression) + } else { + patternTranslator.translateExpressionPattern(whenExpression.subjectExpression!!, expressionToMatch, patternExpression) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/LongOperationFIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/LongOperationFIF.kt index 6f512ac4a03..e35bb7d6267 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/LongOperationFIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/LongOperationFIF.kt @@ -59,7 +59,7 @@ object LongOperationFIF : FunctionIntrinsicFactory { private val floatBinaryIntrinsics: Map = mapOf( - "compareTo" to BaseBinaryIntrinsic(::primitiveCompareTo), + "compareTo" to BaseBinaryIntrinsic(::compareTo), "plus" to BaseBinaryIntrinsic(::sum), "minus" to BaseBinaryIntrinsic(::subtract), "times" to BaseBinaryIntrinsic(::mul), diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java index 98f398bb077..6381985a516 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java @@ -110,8 +110,11 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { private static final DescriptorPredicate PRIMITIVE_NUMBERS_BINARY_OPERATIONS = pattern(NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS, BINARY_OPERATIONS); + private static final DescriptorPredicate PRIMITIVE_INTEGRAL_NUMBERS_COMPARE_TO_INTEGRAL_OPERATIONS = + pattern("Byte|Short|Int.compareTo(Byte|Short|Int)"); private static final DescriptorPredicate PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS = pattern(NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS, "compareTo"); + private static final Predicate INT_WITH_BIT_OPERATIONS = pattern("Int.or|and|xor|shl|shr|ushr") .or(pattern("Short|Byte.or|and|xor")); private static final DescriptorPredicate BOOLEAN_OPERATIONS = pattern("Boolean.or|and|xor"); @@ -140,10 +143,12 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { return new RangeToIntrinsic(descriptor); } - if (PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS.test(descriptor)) { + if (PRIMITIVE_INTEGRAL_NUMBERS_COMPARE_TO_INTEGRAL_OPERATIONS.test(descriptor)) { return PRIMITIVE_NUMBER_COMPARE_TO_INTRINSIC; } - + if (PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS.test(descriptor)) { + return BUILTINS_COMPARE_TO_INTRINSIC; + } if (KotlinBuiltIns.isBuiltIn(descriptor) && descriptor.getName().equals(OperatorNameConventions.COMPARE_TO)) { return BUILTINS_COMPARE_TO_INTRINSIC; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/CompareToBOIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/CompareToBOIF.kt index bee39a4c5d8..32af369afe0 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/CompareToBOIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/CompareToBOIF.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation import org.jetbrains.kotlin.js.backend.ast.JsExpression import org.jetbrains.kotlin.js.backend.ast.JsIntLiteral -import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.operation.OperatorTable import org.jetbrains.kotlin.js.translate.utils.JsAstUtils @@ -33,10 +32,6 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.expressions.OperatorConventions object CompareToBOIF : BinaryOperationIntrinsicFactory { - val COMPARE_TO_CHAR = pattern("Int|Short|Byte|Double|Float.compareTo(Char)") - val CHAR_COMPARE_TO = pattern("Char.compareTo(Int|Short|Byte|Double|Float)") - val PRIMITIVE_COMPARE_TO = pattern("Int|Short|Byte|Double|Float|Char|String|Boolean.compareTo") - private object CompareToIntrinsic : AbstractBinaryOperationIntrinsic() { override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression { val operator = OperatorTable.getBinaryOperator(getOperationToken(expression)) @@ -71,17 +66,17 @@ object CompareToBOIF : BinaryOperationIntrinsicFactory { override fun getIntrinsic(descriptor: FunctionDescriptor, leftType: KotlinType?, rightType: KotlinType?): BinaryOperationIntrinsic? { if (descriptor.isDynamic()) return CompareToIntrinsic + if (leftType == null || rightType == null) return null + if (!KotlinBuiltIns.isBuiltIn(descriptor)) return null + // Types may be nullable if properIeeeComparisons are switched off, e.g. fun foo(a: Double?) = a != null && a < 0.0 return when { - COMPARE_TO_CHAR.test(descriptor) -> - CompareToCharIntrinsic - CHAR_COMPARE_TO.test(descriptor) -> - CompareCharToPrimitiveIntrinsic - PRIMITIVE_COMPARE_TO.test(descriptor) -> - CompareToIntrinsic - else -> - CompareToFunctionIntrinsic + KotlinBuiltIns.isCharOrNullableChar(rightType) -> CompareToCharIntrinsic + KotlinBuiltIns.isCharOrNullableChar(leftType) -> CompareCharToPrimitiveIntrinsic + KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(leftType) && + KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(rightType) -> CompareToIntrinsic + else -> CompareToFunctionIntrinsic } } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt index 989a86394f7..d4562bd6bc0 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.js.translate.intrinsic.operation import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType -import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator @@ -31,11 +30,8 @@ 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.DataFlowValueFactoryImpl import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.expressions.OperatorConventions @@ -46,9 +42,8 @@ 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) + private val JS_NUMBER_PRIMITIVES = + EnumSet.of(PrimitiveType.BYTE, PrimitiveType.SHORT, PrimitiveType.INT, PrimitiveType.DOUBLE, PrimitiveType.FLOAT) override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression { val isNegated = expression.isNegated() @@ -60,25 +55,38 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory { return TranslationUtils.nullCheck(coercedSubject, isNegated) } - val ktLeft = checkNotNull(expression.left) { "No left-hand side: " + expression.text } - val ktRight = checkNotNull(expression.right) { "No right-hand side: " + expression.text } - val leftKotlinType = getRefinedType(ktLeft, context) - val rightKotlinType = getRefinedType(ktRight, context) + val (leftKotlinType, rightKotlinType) = binaryOperationTypes(expression, context) + val leftType = leftKotlinType?.let { KotlinBuiltIns.getPrimitiveType(it) } val rightType = rightKotlinType?.let { KotlinBuiltIns.getPrimitiveType(it) } - if (leftType != null && (leftType in SIMPLE_PRIMITIVES || leftType == rightType && leftType != PrimitiveType.LONG)) { + if (leftType != null && rightType != null && ( + leftType in JS_NUMBER_PRIMITIVES && rightType in JS_NUMBER_PRIMITIVES || + leftType in JS_NUMBER_PRIMITIVES && rightType == PrimitiveType.LONG || + leftType == PrimitiveType.LONG && rightType in JS_NUMBER_PRIMITIVES || + leftType == PrimitiveType.BOOLEAN && rightType == PrimitiveType.BOOLEAN || + leftType == PrimitiveType.CHAR && rightType == PrimitiveType.CHAR + )) { + val useEq = leftType == PrimitiveType.LONG || rightType == PrimitiveType.LONG + + val operator = when { + useEq && isNegated -> JsBinaryOperator.NEQ + useEq && !isNegated -> JsBinaryOperator.EQ + !useEq && isNegated -> JsBinaryOperator.REF_NEQ + else /* !useEq && !isNegated */ -> JsBinaryOperator.REF_EQ + } + val coercedLeft = TranslationUtils.coerce(context, left, leftKotlinType) - val coercedRight = TranslationUtils.coerce(context, right, rightKotlinType!!) - return JsBinaryOperation(if (isNegated) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ, coercedLeft, coercedRight) + val coercedRight = TranslationUtils.coerce(context, right, rightKotlinType) + return JsBinaryOperation(operator, coercedLeft, coercedRight) } val resolvedCall = expression.getResolvedCall(context.bindingContext()) val appliedToDynamic = - resolvedCall != null && - with(resolvedCall.dispatchReceiver) { - if (this != null) type.isDynamic() else false - } + resolvedCall != null && + with(resolvedCall.dispatchReceiver) { + if (this != null) type.isDynamic() else false + } if (appliedToDynamic) { return JsBinaryOperation(if (isNegated) JsBinaryOperator.NEQ else JsBinaryOperator.EQ, left, right) @@ -89,37 +97,6 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory { val result = TopLevelFIF.KOTLIN_EQUALS.apply(coercedLeft, listOf(coercedRight), context) return if (isNegated) JsAstUtils.not(result) else result } - - /** - * 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 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 = DataFlowValueFactoryImpl().createDataFlowValue(expression, ktType, bindingContext, descriptor) - val isPrimitiveFn = KotlinBuiltIns::isPrimitiveTypeOrNullablePrimitiveType - - val languageVersionSettings = context.config.configuration.languageVersionSettings - return bindingContext.getDataFlowInfoBefore(expression).getStableTypes(dataFlow, languageVersionSettings).find(isPrimitiveFn) ?: // Smart-casts - TypeUtils.getAllSupertypes(ktType).find(isPrimitiveFn) ?: // Generic super-types - ktType // Default - } } object EnumEqualsIntrinsic : AbstractBinaryOperationIntrinsic() { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/binaryOperationIntrinsics.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/binaryOperationIntrinsics.kt index b142522848c..01c35d493cf 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/binaryOperationIntrinsics.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/binaryOperationIntrinsics.kt @@ -21,6 +21,8 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken +import org.jetbrains.kotlin.js.translate.utils.getPrecisePrimitiveType +import org.jetbrains.kotlin.js.translate.utils.getPrimitiveNumericComparisonInfo import org.jetbrains.kotlin.lexer.KtToken import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.types.KotlinType @@ -45,8 +47,7 @@ class BinaryOperationIntrinsics { return NO_INTRINSIC } - val leftType = expression.left?.let { context.bindingContext().getType(it) } - val rightType = expression.right?.let { context.bindingContext().getType(it) } + val (leftType, rightType) = binaryOperationTypes(expression, context) val key = IntrinsicKey(token, descriptor, leftType, rightType) return intrinsicCache.getOrPut(key) { computeIntrinsic(token, descriptor, leftType, rightType) } @@ -68,6 +69,15 @@ class BinaryOperationIntrinsics { } } +// Takes into account smart-casts (needed for IEEE 754 comparisons) +fun binaryOperationTypes(expression: KtBinaryExpression, context: TranslationContext): Pair { + val info = context.getPrimitiveNumericComparisonInfo(expression) + if (info != null) { + return info.leftType to info.rightType + } + return expression.left?.let { context.getPrecisePrimitiveType(it) } to expression.right?.let { context.getPrecisePrimitiveType(it) } +} + private data class IntrinsicKey( val token: KtToken, val function: FunctionDescriptor, val leftType: KotlinType?, val rightType: KotlinType? diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index b00a1e01f9f..a4941776cc1 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -19,6 +19,9 @@ package org.jetbrains.kotlin.js.translate.utils import com.intellij.psi.PsiElement import com.intellij.util.SmartList import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -31,15 +34,14 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction -import org.jetbrains.kotlin.psi.KtBlockExpression -import org.jetbrains.kotlin.psi.KtDeclarationWithBody -import org.jetbrains.kotlin.psi.KtFunctionLiteral -import org.jetbrains.kotlin.psi.KtLambdaExpression +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeUtils fun generateDelegateCall( classDescriptor: ClassDescriptor, @@ -242,4 +244,34 @@ fun TranslationContext.createCoroutineResult(resolvedCall: ResolvedCall<*>): JsE coroutineResult = true synthetic = true } +} + +/** + * Tries to get precise statically known primitive type. Takes generic supertypes into account. Doesn't handle smart-casts. + * This is needed to be compatible with JVM NaN behaviour: + * + * // Generics with Double super-type + * fun foo(v: T) = println(v == v) + * foo(Double.NaN) // false + * + * Also see org/jetbrains/kotlin/codegen/codegenUtil.kt#calcTypeForIEEE754ArithmeticIfNeeded + */ +fun TranslationContext.getPrecisePrimitiveType(expression: KtExpression): KotlinType? { + val bindingContext = bindingContext() + val ktType = bindingContext.getType(expression) ?: return null + + return TypeUtils.getAllSupertypes(ktType).find(KotlinBuiltIns::isPrimitiveTypeOrNullablePrimitiveType) ?: ktType +} + +fun TranslationContext.getPrecisePrimitiveTypeNotNull(expression: KtExpression): KotlinType { + return getPrecisePrimitiveType(expression) ?: throw IllegalStateException("Type must be not null for " + expression) +} + +fun TranslationContext.getPrimitiveNumericComparisonInfo(expression: KtExpression) = + config.configuration.languageVersionSettings.let { + if (it.supportsFeature(LanguageFeature.ProperIeee754Comparisons)) { + bindingContext().get(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, expression) + } else { + null + } } \ No newline at end of file diff --git a/libraries/stdlib/js/src/js/arrayUtils.js b/libraries/stdlib/js/src/js/arrayUtils.js index 015075492d7..42e75d1f2be 100644 --- a/libraries/stdlib/js/src/js/arrayUtils.js +++ b/libraries/stdlib/js/src/js/arrayUtils.js @@ -130,5 +130,5 @@ Kotlin.arrayDeepHashCode = function (arr) { }; Kotlin.primitiveArraySort = function (array) { - array.sort(Kotlin.primitiveCompareTo) + array.sort(Kotlin.doubleCompareTo) }; diff --git a/libraries/stdlib/js/src/js/core.js b/libraries/stdlib/js/src/js/core.js index 73fae6e0600..116dd568cb2 100644 --- a/libraries/stdlib/js/src/js/core.js +++ b/libraries/stdlib/js/src/js/core.js @@ -31,6 +31,10 @@ Kotlin.equals = function (obj1, obj2) { return obj1.equals(obj2); } + if (typeof obj1 === "number" && typeof obj2 === "number") { + return obj1 === obj2 && (obj1 !== 0 || 1 / obj1 === 1 / obj2) + } + return obj1 === obj2; }; diff --git a/libraries/stdlib/js/src/js/misc.js b/libraries/stdlib/js/src/js/misc.js index 79e49b02926..4007579605e 100644 --- a/libraries/stdlib/js/src/js/misc.js +++ b/libraries/stdlib/js/src/js/misc.js @@ -16,14 +16,13 @@ Kotlin.compareTo = function (a, b) { var typeA = typeof a; - var typeB = typeof a; - if (Kotlin.isChar(a) && typeB === "number") { - return Kotlin.primitiveCompareTo(a.charCodeAt(0), b); + if (typeA === "number") { + if (typeof b === "number") { + return Kotlin.doubleCompareTo(a, b); + } + return Kotlin.primitiveCompareTo(a, b); } - if (typeA === "number" && Kotlin.isChar(b)) { - return Kotlin.primitiveCompareTo(a, b.charCodeAt(0)); - } - if (typeA === "number" || typeA === "string" || typeA === "boolean") { + if (typeA === "string" || typeA === "boolean") { return Kotlin.primitiveCompareTo(a, b); } return a.compareTo_11rb$(b); @@ -33,6 +32,20 @@ Kotlin.primitiveCompareTo = function (a, b) { return a < b ? -1 : a > b ? 1 : 0; }; +Kotlin.doubleCompareTo = function (a, b) { + if (a < b) return -1; + if (a > b) return 1; + + if (a === b) { + if (a !== 0) return 0; + + var ia = 1 / a; + return ia === 1 / b ? 0 : (ia < 0 ? -1 : 1); + } + + return a !== a ? (b !== b ? 0 : 1) : -1 +}; + Kotlin.charInc = function (value) { return Kotlin.toChar(value+1); }; diff --git a/libraries/stdlib/test/numbers/NaNPropagationTest.kt b/libraries/stdlib/test/numbers/NaNPropagationTest.kt index fabd48b7b4e..c9dfa54a4df 100644 --- a/libraries/stdlib/test/numbers/NaNPropagationTest.kt +++ b/libraries/stdlib/test/numbers/NaNPropagationTest.kt @@ -104,7 +104,6 @@ class NaNPropagationTest { } -@JvmVersion class NaNTotalOrderTest { private fun > totalOrderMinOf2(f2t: (T, T) -> T, function: String) {