diff --git a/src/FSharp.Core/map.fs b/src/FSharp.Core/map.fs index 9fad005450e..2535dff7522 100644 --- a/src/FSharp.Core/map.fs +++ b/src/FSharp.Core/map.fs @@ -882,6 +882,41 @@ type Map<[] 'Key, [ as that -> + use e1 = (this :> seq<_>).GetEnumerator() + use e2 = (that :> seq<_>).GetEnumerator() + + let rec loop () = + let m1 = e1.MoveNext() + let m2 = e2.MoveNext() + + (m1 = m2) + && (not m1 + || (let e1c = e1.Current + let e2c = e2.Current + + (comparer.Equals(e1c.Key, e2c.Key) + && comparer.Equals(e1c.Value, e2c.Value) + && loop ()))) + + loop () + | _ -> false + + member this.GetHashCode(comparer) = + let combineHash x y = + (x <<< 1) + y + 631 + + let mutable res = 0 + + for (KeyValue (x, y)) in this do + res <- combineHash res (comparer.GetHashCode x) + res <- combineHash res (comparer.GetHashCode y) + + res + interface IEnumerable> with member _.GetEnumerator() = MapTree.mkIEnumerator tree diff --git a/src/FSharp.Core/map.fsi b/src/FSharp.Core/map.fsi index b560950ffbd..abf960909a2 100644 --- a/src/FSharp.Core/map.fsi +++ b/src/FSharp.Core/map.fsi @@ -210,6 +210,7 @@ type Map<[] 'Key, [> interface IEnumerable> interface System.IComparable + interface System.Collections.IStructuralEquatable interface System.Collections.IEnumerable interface IReadOnlyCollection> interface IReadOnlyDictionary<'Key, 'Value> diff --git a/src/FSharp.Core/set.fs b/src/FSharp.Core/set.fs index f04cc12433e..4a1b9b42f57 100644 --- a/src/FSharp.Core/set.fs +++ b/src/FSharp.Core/set.fs @@ -872,7 +872,7 @@ type Set<[] 'T when 'T: comparison>(comparer: IComparer<' member x.ToArray() = SetTree.toArray x.Tree - member this.ComputeHashCode() = + member private this.ComputeHashCode() = let combineHash x y = (x <<< 1) + y + 631 @@ -904,6 +904,32 @@ type Set<[] 'T when 'T: comparison>(comparer: IComparer<' member this.CompareTo(that: obj) = SetTree.compare this.Comparer this.Tree ((that :?> Set<'T>).Tree) + interface IStructuralEquatable with + member this.Equals(that, comparer) = + match that with + | :? Set<'T> as that -> + use e1 = (this :> seq<_>).GetEnumerator() + use e2 = (that :> seq<_>).GetEnumerator() + + let rec loop () = + let m1 = e1.MoveNext() + let m2 = e2.MoveNext() + (m1 = m2) && (not m1 || ((comparer.Equals(e1.Current, e2.Current)) && loop ())) + + loop () + | _ -> false + + member this.GetHashCode(comparer) = + let combineHash x y = + (x <<< 1) + y + 631 + + let mutable res = 0 + + for x in this do + res <- combineHash res (comparer.GetHashCode(x)) + + res + interface ICollection<'T> with member s.Add x = ignore x diff --git a/src/FSharp.Core/set.fsi b/src/FSharp.Core/set.fsi index b1c51c87afb..f1c2fd291c2 100644 --- a/src/FSharp.Core/set.fsi +++ b/src/FSharp.Core/set.fsi @@ -229,6 +229,7 @@ type Set<[] 'T when 'T: comparison> = interface IEnumerable<'T> interface System.Collections.IEnumerable interface System.IComparable + interface System.Collections.IStructuralEquatable interface IReadOnlyCollection<'T> override Equals: obj -> bool diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs index ee2b662bfe5..0c5e7435ae7 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs @@ -202,6 +202,45 @@ type LanguagePrimitivesModule() = let resultNul = LanguagePrimitives.GenericEquality "ABC" null Assert.False(resultNul) + + [] + member _.GenericEqualityForNans() = + Assert.DoesNotContain(true, + [| LanguagePrimitives.GenericEquality nan nan + LanguagePrimitives.GenericEquality [nan] [nan] + LanguagePrimitives.GenericEquality [|nan|] [|nan|] + LanguagePrimitives.GenericEquality (Set.ofList [nan]) (Set.ofList [nan]) + LanguagePrimitives.GenericEquality (Map.ofList [1,nan]) (Map.ofList [1,nan]) + LanguagePrimitives.GenericEquality (Map.ofList [nan,1]) (Map.ofList [nan,1]) + LanguagePrimitives.GenericEquality (Map.ofList [nan,nan]) (Map.ofList [nan,nan]) + + LanguagePrimitives.GenericEquality nanf nanf + LanguagePrimitives.GenericEquality [nanf] [nanf] + LanguagePrimitives.GenericEquality [|nanf|] [|nanf|] + LanguagePrimitives.GenericEquality (Set.ofList [nanf]) (Set.ofList [nanf]) + LanguagePrimitives.GenericEquality (Map.ofList [1,nanf]) (Map.ofList [1,nanf]) + LanguagePrimitives.GenericEquality (Map.ofList [nanf,1]) (Map.ofList [nanf,1]) + LanguagePrimitives.GenericEquality (Map.ofList [nanf,nanf]) (Map.ofList [nanf,nanf])|]) + + [] + member _.GenericEqualityER() = + Assert.DoesNotContain(false, + [| LanguagePrimitives.GenericEqualityER nan nan + LanguagePrimitives.GenericEqualityER [nan] [nan] + LanguagePrimitives.GenericEqualityER [|nan|] [|nan|] + LanguagePrimitives.GenericEqualityER (Set.ofList [nan]) (Set.ofList [nan]) + LanguagePrimitives.GenericEqualityER (Map.ofList [1,nan]) (Map.ofList [1,nan]) + LanguagePrimitives.GenericEqualityER (Map.ofList [nan,1]) (Map.ofList [nan,1]) + LanguagePrimitives.GenericEqualityER (Map.ofList [nan,nan]) (Map.ofList [nan,nan]) + + LanguagePrimitives.GenericEqualityER nanf nanf + LanguagePrimitives.GenericEqualityER [nanf] [nanf] + LanguagePrimitives.GenericEqualityER [|nanf|] [|nanf|] + LanguagePrimitives.GenericEqualityER (Set.ofList [nanf]) (Set.ofList [nanf]) + LanguagePrimitives.GenericEqualityER (Map.ofList [1,nanf]) (Map.ofList [1,nanf]) + LanguagePrimitives.GenericEqualityER (Map.ofList [nanf,1]) (Map.ofList [nanf,1]) + LanguagePrimitives.GenericEqualityER (Map.ofList [nanf,nanf]) (Map.ofList [nanf,nanf])|]) + [] member this.GenericGreaterOrEqual() = diff --git a/tests/projects/SelfContained_Trimming_Test/check.ps1 b/tests/projects/SelfContained_Trimming_Test/check.ps1 index fbc122b4158..388ed50ae7e 100644 --- a/tests/projects/SelfContained_Trimming_Test/check.ps1 +++ b/tests/projects/SelfContained_Trimming_Test/check.ps1 @@ -14,7 +14,7 @@ if (-not ($output -eq $expected)) } # Checking that FSharp.Core binary is of expected size (needs adjustments if test is updated). -$expected_len = 245248 # In bytes +$expected_len = 246272 # In bytes $file = Get-Item .\bin\Release\net7.0\win-x64\publish\FSharp.Core.dll $file_len = $file.Length if (-not ($file_len -eq $expected_len)) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/OptionParserTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/OptionParserTests.fs index 778911047c8..00a82c99aa4 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Hints/OptionParserTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/OptionParserTests.fs @@ -22,7 +22,7 @@ module OptionParserTests = let actual = OptionParser.getHintKinds options - Assert.AreEqual(expected, actual) + CollectionAssert.AreEquivalent(expected, actual) [] let ``Type hints on, parameter name hints off`` () = @@ -36,7 +36,7 @@ module OptionParserTests = let actual = OptionParser.getHintKinds options - Assert.AreEqual(expected, actual) + CollectionAssert.AreEquivalent(expected, actual) [] let ``Type hints off, parameter name hints on`` () = @@ -50,7 +50,7 @@ module OptionParserTests = let actual = OptionParser.getHintKinds options - Assert.AreEqual(expected, actual) + CollectionAssert.AreEquivalent(expected, actual) [] let ``Type hints on, parameter name hints on`` () = @@ -64,4 +64,4 @@ module OptionParserTests = let actual = OptionParser.getHintKinds options - Assert.AreEqual(expected, actual) + CollectionAssert.AreEquivalent(expected, actual)