Skip to content

Commit ed80252

Browse files
committed
JS: fix double compareTo behaviour for NaN and +-0 (KT-22723)
1 parent 12c01ef commit ed80252

File tree

49 files changed

+260
-307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+260
-307
lines changed

compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
151151
)
152152
var useExperimental: Array<String>? by FreezableVar(null)
153153

154+
@Argument(
155+
value = "-Xproper-ieee754-comparisons",
156+
description = "Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types"
157+
)
158+
var properIeee754Comparisons by FreezableVar(false)
159+
154160
open fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
155161
return HashMap<AnalysisFlag<*>, Any>().apply {
156162
put(AnalysisFlag.skipMetadataVersionCheck, skipMetadataVersionCheck)

compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,6 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
224224
)
225225
var noExceptionOnExplicitEqualsForBoxedNull by FreezableVar(false)
226226

227-
@Argument(
228-
value = "-Xproper-ieee754-comparisons",
229-
description = "Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types"
230-
)
231-
var properIeee754Comparisons by FreezableVar(false)
232-
233227
// Paths to output directories for friend modules.
234228
var friendPaths: Array<String>? by FreezableVar(null)
235229

compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ private void setupLanguageVersionSettings(@NotNull CompilerConfiguration configu
226226
extraLanguageFeatures.put(LanguageFeature.ReadDeserializedContracts, LanguageFeature.State.ENABLED);
227227
}
228228

229+
if (arguments.getProperIeee754Comparisons()) {
230+
extraLanguageFeatures.put(LanguageFeature.ProperIeee754Comparisons, LanguageFeature.State.ENABLED);
231+
}
229232

230233
setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, arguments);
231234

compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,6 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
235235
extraLanguageFeatures[LanguageFeature.StrictJavaNullabilityAssertions] = LanguageFeature.State.ENABLED
236236
}
237237

238-
if (commandLineArguments.properIeee754Comparisons) {
239-
extraLanguageFeatures[LanguageFeature.ProperIeee754Comparisons] = LanguageFeature.State.ENABLED
240-
}
241-
242238
super.setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, commandLineArguments)
243239
}
244240

compiler/testData/cli/js/jsExtraHelp.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ where advanced options include:
1515
-Xno-check-actual Do not check presence of 'actual' modifier in multi-platform projects
1616
-Xno-inline Disable method inlining
1717
-Xplugin=<path> Load plugins from the given classpath
18+
-Xproper-ieee754-comparisons Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types
1819
-Xread-deserialized-contracts Enable reading of contracts from metadata
1920
-Xrepeat=<count> Repeat compilation (for performance analysis)
2021
-Xreport-output-files Report source to output files mapping

compiler/testData/cli/jvm/extraHelp.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ where advanced options include:
2828
-Xno-optimize Disable optimizations
2929
-Xno-param-assertions Don't generate not-null assertions on parameters of methods accessible from Java
3030
-Xno-receiver-assertions Don't generate not-null assertion for extension receiver arguments of platform types
31-
-Xproper-ieee754-comparisons Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types
3231
-Xreport-perf Report detailed performance statistics
3332
-Xscript-resolver-environment=<key=value[,]>
3433
Script resolver environment in key-value pairs (the value could be quoted and escaped)
@@ -53,6 +52,7 @@ where advanced options include:
5352
-Xno-check-actual Do not check presence of 'actual' modifier in multi-platform projects
5453
-Xno-inline Disable method inlining
5554
-Xplugin=<path> Load plugins from the given classpath
55+
-Xproper-ieee754-comparisons Generate proper IEEE 754 comparisons in all cases if values are statically known to be of primitive numeric types
5656
-Xread-deserialized-contracts Enable reading of contracts from metadata
5757
-Xrepeat=<count> Repeat compilation (for performance analysis)
5858
-Xreport-output-files Report source to output files mapping

compiler/testData/codegen/box/boxingOptimization/boxedRealsCmp.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// IGNORE_BACKEND: JS, NATIVE
1+
// IGNORE_BACKEND: NATIVE
22

33
inline fun ltx(a: Comparable<Any>, b: Any) = a < b
44
inline fun lex(a: Comparable<Any>, b: Any) = a <= b

compiler/testData/codegen/box/boxingOptimization/explicitEqualsOnDouble.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// IGNORE_BACKEND: JS
21
// IGNORE_BACKEND: NATIVE
32

43
fun equals1(a: Double, b: Double) = a.equals(b)

compiler/testData/codegen/box/ieee754/asComparableToDouble.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// IGNORE_BACKEND: JS
2-
31
val minus: Any = -0.0
42

53
fun box(): String {

compiler/testData/codegen/box/ieee754/asComparableToDouble_properIeeeComparisons.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: +ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
val minus: Any = -0.0
54

compiler/testData/codegen/box/ieee754/comparableTypeCast.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// IGNORE_BACKEND: JS
21
fun box(): String {
32
if ((-0.0 as Comparable<Double>) >= 0.0) return "fail 0"
43
if ((-0.0F as Comparable<Float>) >= 0.0F) return "fail 1"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
fun box(): String {
2+
if (0.toByte().compareTo(-0.0) != 1) return "fail 1.1"
3+
if (0.toByte().compareTo(-0.0F) != 1) return "fail 1.2"
4+
if (0.toByte().compareTo(Double.NaN) != -1) return "fail 1.3"
5+
if (0.toByte().compareTo(Float.NaN) != -1) return "fail 1.4"
6+
7+
if (0.toShort().compareTo(-0.0) != 1) return "fail 2.1"
8+
if (0.toShort().compareTo(-0.0F) != 1) return "fail 2.2"
9+
if (0.toShort().compareTo(Double.NaN) != -1) return "fail 2.3"
10+
if (0.toShort().compareTo(Float.NaN) != -1) return "fail 2.4"
11+
12+
if (0.compareTo(-0.0) != 1) return "fail 3.1"
13+
if (0.compareTo(-0.0F) != 1) return "fail 3.2"
14+
if (0.compareTo(Double.NaN) != -1) return "fail 3.3"
15+
if (0.compareTo(Float.NaN) != -1) return "fail 3.4"
16+
17+
if (0.0F.compareTo(-0.0) != 1) return "fail 4.1"
18+
if (0.0F.compareTo(-0.0F) != 1) return "fail 4.2"
19+
if (0.0F.compareTo(Double.NaN) != -1) return "fail 4.3"
20+
if (0.0F.compareTo(Float.NaN) != -1) return "fail 4.4"
21+
22+
if (0.0.compareTo(-0.0) != 1) return "fail 5.1"
23+
if (0.0.compareTo(-0.0F) != 1) return "fail 5.2"
24+
if (0.0.compareTo(Double.NaN) != -1) return "fail 5.3"
25+
if (0.0.compareTo(Float.NaN) != -1) return "fail 5.4"
26+
27+
if (0L.compareTo(-0.0) != 1) return "fail 6.1"
28+
if (0L.compareTo(-0.0F) != 1) return "fail 6.2"
29+
if (0L.compareTo(Double.NaN) != -1) return "fail 6.3"
30+
if (0L.compareTo(Float.NaN) != -1) return "fail 6.4"
31+
32+
33+
if ((-0.0).compareTo(0.toByte()) != -1) return "fail 7.1"
34+
if ((-0.0).compareTo(0.toShort()) != -1) return "fail 7.2"
35+
if ((-0.0).compareTo(0) != -1) return "fail 7.3"
36+
if ((-0.0).compareTo(0.0F) != -1) return "fail 7.4"
37+
if ((-0.0).compareTo(0.0) != -1) return "fail 7.5"
38+
if ((-0.0).compareTo(0L) != -1) return "fail 7.6"
39+
40+
if ((-0.0F).compareTo(0.toByte()) != -1) return "fail 8.1"
41+
if ((-0.0F).compareTo(0.toShort()) != -1) return "fail 8.2"
42+
if ((-0.0F).compareTo(0) != -1) return "fail 8.3"
43+
if ((-0.0F).compareTo(0.0F) != -1) return "fail 8.4"
44+
if ((-0.0F).compareTo(0.0) != -1) return "fail 8.5"
45+
if ((-0.0F).compareTo(0L) != -1) return "fail 8.6"
46+
47+
if (Double.NaN.compareTo(0.toByte()) != 1) return "fail 9.1"
48+
if (Double.NaN.compareTo(0.toShort()) != 1) return "fail 9.2"
49+
if (Double.NaN.compareTo(0) != 1) return "fail 9.3"
50+
if (Double.NaN.compareTo(0.0F) != 1) return "fail 9.4"
51+
if (Double.NaN.compareTo(0.0) != 1) return "fail 9.5"
52+
if (Double.NaN.compareTo(0L) != 1) return "fail 9.6"
53+
54+
if (Float.NaN.compareTo(0.toByte()) != 1) return "fail 10.1"
55+
if (Float.NaN.compareTo(0.toShort()) != 1) return "fail 10.2"
56+
if (Float.NaN.compareTo(0) != 1) return "fail 10.3"
57+
if (Float.NaN.compareTo(0.0F) != 1) return "fail 10.4"
58+
if (Float.NaN.compareTo(0.0) != 1) return "fail 10.5"
59+
if (Float.NaN.compareTo(0L) != 1) return "fail 10.6"
60+
61+
return "OK"
62+
}

compiler/testData/codegen/box/ieee754/equalsDouble.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun equals1(a: Double, b: Double) = a == b
54

compiler/testData/codegen/box/ieee754/equalsFloat.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun equals1(a: Float, b: Float) = a == b
54

compiler/testData/codegen/box/ieee754/equalsNaN.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
22
// WITH_RUNTIME
3-
// IGNORE_BACKEND: JS
43

54
import kotlin.test.*
65

compiler/testData/codegen/box/ieee754/equalsNullableDouble.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun equals1(a: Double, b: Double?) = a == b
54

compiler/testData/codegen/box/ieee754/equalsNullableFloat.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun equals1(a: Float, b: Float?) = a == b
54

compiler/testData/codegen/box/ieee754/explicitCompareCall.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// IGNORE_BACKEND: JS
21
fun less1(a: Double, b: Double) = a.compareTo(b) == -1
32

43
fun less2(a: Double?, b: Double?) = a!!.compareTo(b!!) == -1

compiler/testData/codegen/box/ieee754/explicitEqualsCall.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// IGNORE_BACKEND: JS
2-
31
fun equals1(a: Double, b: Double) = a.equals(b)
42

53
fun equals2(a: Double?, b: Double?) = a!!.equals(b!!)

compiler/testData/codegen/box/ieee754/greaterDouble.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun greater1(a: Double, b: Double) = a > b
54

compiler/testData/codegen/box/ieee754/greaterFloat.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun greater1(a: Float, b: Float) = a > b
54

compiler/testData/codegen/box/ieee754/inline.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// IGNORE_BACKEND: JS
2-
31
inline fun less(a: Comparable<Double>, b: Double): Boolean {
42
return a < b
53
}

compiler/testData/codegen/box/ieee754/lessDouble.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun less1(a: Double, b: Double) = a < b
54

compiler/testData/codegen/box/ieee754/lessFloat.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun less1(a: Float, b: Float) = a < b
54

compiler/testData/codegen/box/ieee754/safeCall.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// IGNORE_BACKEND: JS
21
fun box(): String {
32
val plusZero: Double? = 0.0
43
val minusZero: Double = -0.0

compiler/testData/codegen/box/ieee754/smartCastToDifferentTypes.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// IGNORE_BACKEND: JS
21
fun box(): String {
32
val zero: Any = 0.0
43
val floatZero: Any = -0.0F

compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// IGNORE_BACKEND: JS
2-
31
fun eqDI(x: Any?, y: Any?) = x is Double? && y is Int? && x == y
42
fun eqDL(x: Any?, y: Any?) = x is Double? && y is Long? && x == y
53
fun eqID(x: Any?, y: Any?) = x is Int? && y is Double? && x == y

compiler/testData/codegen/box/ieee754/smartCastToDifferentTypesWithNumericPromotion_properIeeeComparisons.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: +ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun eqDI(x: Any?, y: Any?) = x is Double? && y is Int? && x == y
54
fun eqDL(x: Any?, y: Any?) = x is Double? && y is Long? && x == y

compiler/testData/codegen/box/ieee754/when.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun box(): String {
54
val plusZero: Any = 0.0

compiler/testData/codegen/box/ieee754/when10.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// LANGUAGE_VERSION: 1.0
2-
// IGNORE_BACKEND: JS
32

43
fun box(): String {
54
val plusZero: Any = 0.0

compiler/testData/codegen/box/ieee754/whenNoSubject.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// !LANGUAGE: -ProperIeee754Comparisons
2-
// IGNORE_BACKEND: JS
32

43
fun box(): String {
54
val plusZero: Any = 0.0

compiler/testData/codegen/box/ranges/contains/inDoubleRangeLiteralVsComparableRangeLiteral.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// IGNORE_BACKEND: JS
21
// WITH_RUNTIME
32

43
val DOUBLE_RANGE = 0.0 .. -0.0

compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,10 @@ public static boolean isLong(@NotNull KotlinType type) {
946946
return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._long);
947947
}
948948

949+
public static boolean isLongOrNullableLong(@NotNull KotlinType type) {
950+
return isConstructedFromGivenClass(type, FQ_NAMES._long);
951+
}
952+
949953
public static boolean isShort(@NotNull KotlinType type) {
950954
return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._short);
951955
}

0 commit comments

Comments
 (0)