@@ -839,6 +839,12 @@ namespace Microsoft.FSharp.Core
839839 match x with
840840 | null -> 0
841841 | (:? 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.
842848 match a with
843849 | :? ( obj[]) as oa -> GenericHashObjArray iec oa
844850 | :? ( byte[]) as ba -> GenericHashByteArray ba
@@ -1383,10 +1389,12 @@ namespace Microsoft.FSharp.Core
13831389 | (:? string as xs),(:? string as ys) -> System.String.Equals( xs, ys)
13841390 // Permit structural equality on arrays
13851391 | (:? 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.
13861396 match arr1, yobj with
1387- // Fast path
13881397 | (:? ( obj[]) as arr1), (:? ( obj[]) as arr2) -> GenericEqualityObjArray er iec arr1 arr2
1389- // Fast path
13901398 | (:? ( byte[]) as arr1), (:? ( byte[]) as arr2) -> GenericEqualityByteArray arr1 arr2
13911399 | (:? ( int32[]) as arr1), (:? ( int32[]) as arr2) -> GenericEqualityInt32Array arr1 arr2
13921400 | (:? ( int64[]) as arr1), (:? ( int64[]) as arr2) -> GenericEqualityInt64Array arr1 arr2
@@ -1604,11 +1612,21 @@ namespace Microsoft.FSharp.Core
16041612 | null -> 0
16051613 | _ -> getHashCode x }
16061614
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+
16071620 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
16121630 else null
16131631
16141632 let arrayEqualityComparer < 'T > er comparer =
0 commit comments