diff --git a/pkl-core/src/main/java/org/pkl/core/DataSize.java b/pkl-core/src/main/java/org/pkl/core/DataSize.java index 5fcb44dbd..76f3a9f76 100644 --- a/pkl-core/src/main/java/org/pkl/core/DataSize.java +++ b/pkl-core/src/main/java/org/pkl/core/DataSize.java @@ -247,7 +247,8 @@ public final class DataSize implements Value { @Override public int hashCode() { - return Double.hashCode(convertValueTo(DataSizeUnit.BYTES)); + // adding 0.0 normalizes -0.0 to 0.0, because -0.0 == 0.0 but their hash codes differ + return Double.hashCode(convertValueTo(DataSizeUnit.BYTES) + 0.0); } @Override diff --git a/pkl-core/src/main/java/org/pkl/core/Duration.java b/pkl-core/src/main/java/org/pkl/core/Duration.java index df38d7eae..2c21d2019 100644 --- a/pkl-core/src/main/java/org/pkl/core/Duration.java +++ b/pkl-core/src/main/java/org/pkl/core/Duration.java @@ -222,7 +222,8 @@ public final class Duration implements Value { @Override public int hashCode() { - return Double.hashCode(convertValueTo(DurationUnit.NANOS)); + // adding 0.0 normalizes -0.0 to 0.0, because -0.0 == 0.0 but their hash codes differ + return Double.hashCode(convertValueTo(DurationUnit.NANOS) + 0.0); } @Override diff --git a/pkl-core/src/test/kotlin/org/pkl/core/DataSizeTest.kt b/pkl-core/src/test/kotlin/org/pkl/core/DataSizeTest.kt index f6fda6fd5..fdf3fff1a 100644 --- a/pkl-core/src/test/kotlin/org/pkl/core/DataSizeTest.kt +++ b/pkl-core/src/test/kotlin/org/pkl/core/DataSizeTest.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. + * Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -121,5 +121,10 @@ class DataSizeTest { assertThat(size3.hashCode()).isNotEqualTo(size1.hashCode()) assertThat(size2.hashCode()).isNotEqualTo(size3.hashCode()) + + // -0.0 == 0.0, so equal sizes must have equal hash codes + assertThat(DataSize(0.0, BYTES)).isEqualTo(DataSize(-0.0, BYTES)) + assertThat(DataSize(0.0, BYTES).hashCode()).isEqualTo(DataSize(-0.0, BYTES).hashCode()) + assertThat(DataSize(0.0, BYTES).hashCode()).isEqualTo(DataSize(-0.0, PEBIBYTES).hashCode()) } } diff --git a/pkl-core/src/test/kotlin/org/pkl/core/DurationTest.kt b/pkl-core/src/test/kotlin/org/pkl/core/DurationTest.kt index 298d48c6e..690cf6d1c 100644 --- a/pkl-core/src/test/kotlin/org/pkl/core/DurationTest.kt +++ b/pkl-core/src/test/kotlin/org/pkl/core/DurationTest.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. + * Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -285,5 +285,10 @@ class DurationTest { assertThat(duration3.hashCode()).isNotEqualTo(duration1.hashCode()) assertThat(duration2.hashCode()).isNotEqualTo(duration3.hashCode()) + + // -0.0 == 0.0, so equal durations must have equal hash codes + assertThat(Duration(0.0, MILLIS)).isEqualTo(Duration(-0.0, MILLIS)) + assertThat(Duration(0.0, MILLIS).hashCode()).isEqualTo(Duration(-0.0, MILLIS).hashCode()) + assertThat(Duration(0.0, NANOS).hashCode()).isEqualTo(Duration(-0.0, DAYS).hashCode()) } }