@@ -839,6 +839,12 @@ namespace Microsoft.FSharp.Core
839
839
match x with
840
840
| null -> 0
841
841
| (:? System.Array as a) ->
842
+ // due to the rules of the CLI type system, array casts are "assignment compatible"
843
+ // see: https://blogs.msdn.microsoft.com/ericlippert/2009/09/24/why-is-covariance-of-value-typed-arrays-inconsistent/
844
+ // this means that the cast and comparison for byte will also handle sbyte, int32 handle uint32,
845
+ // and int64 handle uint64. The hash code of an individual array element is different for the different
846
+ // types, but it is irrelevant for the creation of the hash code - but this is to be replicated in
847
+ // the tryGetFSharpArrayEqualityComparer function.
842
848
match a with
843
849
| :? ( obj[]) as oa -> GenericHashObjArray iec oa
844
850
| :? ( byte[]) as ba -> GenericHashByteArray ba
@@ -1383,10 +1389,12 @@ namespace Microsoft.FSharp.Core
1383
1389
| (:? string as xs),(:? string as ys) -> System.String.Equals( xs, ys)
1384
1390
// Permit structural equality on arrays
1385
1391
| (:? System.Array as arr1),_ ->
1392
+ // due to the rules of the CLI type system, array casts are "assignment compatible"
1393
+ // see: https://blogs.msdn.microsoft.com/ericlippert/2009/09/24/why-is-covariance-of-value-typed-arrays-inconsistent/
1394
+ // this means that the cast and comparison for byte will also handle sbyte, int32 handle uint32,
1395
+ // and int64 handle uint64. Equality will still be correct.
1386
1396
match arr1, yobj with
1387
- // Fast path
1388
1397
| (:? ( obj[]) as arr1), (:? ( obj[]) as arr2) -> GenericEqualityObjArray er iec arr1 arr2
1389
- // Fast path
1390
1398
| (:? ( byte[]) as arr1), (:? ( byte[]) as arr2) -> GenericEqualityByteArray arr1 arr2
1391
1399
| (:? ( int32[]) as arr1), (:? ( int32[]) as arr2) -> GenericEqualityInt32Array arr1 arr2
1392
1400
| (:? ( int64[]) as arr1), (:? ( int64[]) as arr2) -> GenericEqualityInt64Array arr1 arr2
@@ -1604,11 +1612,21 @@ namespace Microsoft.FSharp.Core
1604
1612
| null -> 0
1605
1613
| _ -> getHashCode x }
1606
1614
1615
+ let inline castNullableEqualityComparer < 'fromType , 'toType when 'toType : null and 'fromType : null > ( equals : 'toType -> 'toType -> bool ) ( getHashCode : 'toType -> int ) =
1616
+ let castEquals ( lhs : 'fromType ) ( rhs : 'fromType ) = equals ( unboxPrim lhs) ( unboxPrim rhs)
1617
+ let castGetHashCode ( o : 'fromType ) = getHashCode ( unboxPrim o)
1618
+ nullableEqualityComparer castEquals castGetHashCode
1619
+
1607
1620
let tryGetFSharpArrayEqualityComparer ( ty : Type ) er comparer : obj =
1608
- if ty.Equals typeof< obj[]> then nullableEqualityComparer ( fun x y -> GenericEqualityObjArray er comparer x y) ( GenericHashObjArray fsEqualityComparerUnlimitedHashingPER)
1609
- elif ty.Equals typeof< byte[]> then nullableEqualityComparer GenericEqualityByteArray GenericHashByteArray
1610
- elif ty.Equals typeof< int32[]> then nullableEqualityComparer GenericEqualityInt32Array GenericHashInt32Array
1611
- elif ty.Equals typeof< int64[]> then nullableEqualityComparer GenericEqualityInt64Array GenericHashInt64Array
1621
+ // the casts here between byte+sbyte, int32+uint32 and int64+uint64 are here to replicate the behaviour
1622
+ // in GenericHashParamObj
1623
+ if ty.Equals typeof< obj[]> then nullableEqualityComparer ( fun x y -> GenericEqualityObjArray er comparer x y) ( GenericHashObjArray fsEqualityComparerUnlimitedHashingPER)
1624
+ elif ty.Equals typeof< byte[]> then nullableEqualityComparer GenericEqualityByteArray GenericHashByteArray
1625
+ elif ty.Equals typeof< sbyte[]> then castNullableEqualityComparer< sbyte[],_> GenericEqualityByteArray GenericHashByteArray
1626
+ elif ty.Equals typeof< int32[]> then nullableEqualityComparer GenericEqualityInt32Array GenericHashInt32Array
1627
+ elif ty.Equals typeof< uint32[]> then castNullableEqualityComparer< uint32[],_> GenericEqualityInt32Array GenericHashInt32Array
1628
+ elif ty.Equals typeof< int64[]> then nullableEqualityComparer GenericEqualityInt64Array GenericHashInt64Array
1629
+ elif ty.Equals typeof< uint64[]> then castNullableEqualityComparer< uint64[],_> GenericEqualityInt64Array GenericHashInt64Array
1612
1630
else null
1613
1631
1614
1632
let arrayEqualityComparer < 'T > er comparer =
0 commit comments