Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/fsharp/FSharp.Core.Unittests/FSharp.Core/PrimTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -683,3 +683,55 @@ type UnboxAndOptionStuff() =
Assert.IsTrue( not (isNull [| |]))
Assert.IsTrue( not (isNull ""))
Assert.IsTrue( not (isNull "1"))


type EnumA =
| A0 = 0
| A1 = 1
| A2 = 2

module EnumEqualityTestHelper =
let equals<'a when 'a : equality> (lhs:'a) (rhs:'a) =
// we are needlessly complex here to avoid the compiler from inlining this function
let r = System.Random ()
let n = r.Next ()
let mutable result = Unchecked.defaultof<_>
for i = n to n do
result <- lhs = rhs
result

let equals2<'a when 'a : equality> (lhs:'a) (rhs:'a) =
LanguagePrimitives.FastGenericEqualityComparer.Equals (lhs, rhs)

[<TestFixture>]
type EnumEqualityTest() =
[<Test>]
member this.EqualityCheck () =
Assert.IsTrue (EnumEqualityTestHelper.equals EnumA.A0 EnumA.A0)
Assert.IsFalse (EnumEqualityTestHelper.equals EnumA.A0 EnumA.A1)
Assert.IsFalse (EnumEqualityTestHelper.equals EnumA.A0 EnumA.A2)

Assert.IsFalse (EnumEqualityTestHelper.equals EnumA.A1 EnumA.A0)
Assert.IsTrue (EnumEqualityTestHelper.equals EnumA.A1 EnumA.A1)
Assert.IsFalse (EnumEqualityTestHelper.equals EnumA.A1 EnumA.A2)

Assert.IsFalse (EnumEqualityTestHelper.equals EnumA.A2 EnumA.A0)
Assert.IsFalse (EnumEqualityTestHelper.equals EnumA.A2 EnumA.A1)
Assert.IsTrue (EnumEqualityTestHelper.equals EnumA.A2 EnumA.A2)

[<Test>]
member this.EqualityCheck2 () =
Assert.IsTrue (EnumEqualityTestHelper.equals2 EnumA.A0 EnumA.A0)
Assert.IsFalse (EnumEqualityTestHelper.equals2 EnumA.A0 EnumA.A1)
Assert.IsFalse (EnumEqualityTestHelper.equals2 EnumA.A0 EnumA.A2)

Assert.IsFalse (EnumEqualityTestHelper.equals2 EnumA.A1 EnumA.A0)
Assert.IsTrue (EnumEqualityTestHelper.equals2 EnumA.A1 EnumA.A1)
Assert.IsFalse (EnumEqualityTestHelper.equals2 EnumA.A1 EnumA.A2)

Assert.IsFalse (EnumEqualityTestHelper.equals2 EnumA.A2 EnumA.A0)
Assert.IsFalse (EnumEqualityTestHelper.equals2 EnumA.A2 EnumA.A1)
Assert.IsTrue (EnumEqualityTestHelper.equals2 EnumA.A2 EnumA.A2)



23 changes: 23 additions & 0 deletions src/fsharp/FSharp.Core/prim-types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ namespace Microsoft.FSharp.Core
type System.Type with
member inline this.IsGenericType = this.GetTypeInfo().IsGenericType
member inline this.IsValueType = this.GetTypeInfo().IsValueType
member inline this.IsEnum = this.GetTypeInfo().IsEnum
member inline this.IsSealed = this.GetTypeInfo().IsSealed
member inline this.IsAssignableFrom(otherTy : Type) = this.GetTypeInfo().IsAssignableFrom(otherTy.GetTypeInfo())
member inline this.GetGenericArguments() = this.GetTypeInfo().GenericTypeArguments
Expand Down Expand Up @@ -1793,6 +1794,16 @@ namespace Microsoft.FSharp.Core
if x.HasValue then x.Value.GetHashCode ()
else 0

module EqualityComparerDefault =
[<Struct; NoComparison; NoEquality>]
type Impl<'a> =
interface IEssenceOfEquals<'a> with
member __.Ensorcel (_:IEqualityComparer, x:'a, y:'a) =
System.Collections.Generic.EqualityComparer.Default.Equals (x, y)
interface IEssenceOfGetHashCode<'a> with
member __.Ensorcel (_:IEqualityComparer, x:'a) =
System.Collections.Generic.EqualityComparer.Default.GetHashCode x

module ValueType =
[<Struct; NoComparison; NoEquality>]
type StructuralEquatable<'a when 'a : struct and 'a :> IStructuralEquatable> =
Expand Down Expand Up @@ -2628,6 +2639,11 @@ namespace Microsoft.FSharp.Core
elif t.Equals typeof<decimal> then typeof<EqualsTypes.Decimal>
else null

let enumTypes (t:Type) : Type =
if t.IsEnum
then mos.makeType t typedefof<CommonEqualityTypes.EqualityComparerDefault.Impl<_>>
else null

let compilerGenerated tyRelation ty =
// if we are using the ER comparer, and we are a standard f# record or value type with compiler generated
// equality operators, then we can avoid the boxing of IStructuralEquatable and just call the
Expand Down Expand Up @@ -2699,6 +2715,7 @@ namespace Microsoft.FSharp.Core
fun () -> tuples tyRelation ty
fun () -> floatingPointTypes tyRelation ty
fun () -> standardTypes ty
fun () -> enumTypes ty
fun () -> compilerGenerated tyRelation ty
fun () -> arrays tyRelation ty
fun () -> nullableType ty
Expand Down Expand Up @@ -3052,6 +3069,11 @@ namespace Microsoft.FSharp.Core
elif t.Equals typeof<float32> then typeof<GetHashCodeTypes.Float32>
else null

let enumTypes (t:Type) : Type =
if t.IsEnum
then mos.makeType t typedefof<CommonEqualityTypes.EqualityComparerDefault.Impl<_>>
else null

[<Struct;NoComparison;NoEquality>]
type GenericHashParamObject<'a> =
interface IEssenceOfGetHashCode<'a> with
Expand Down Expand Up @@ -3093,6 +3115,7 @@ namespace Microsoft.FSharp.Core
mos.takeFirstNonNull [|
fun () -> tuples t
fun () -> standardTypes t
fun () -> enumTypes t
fun () -> arrays t
fun () -> nullableType t
fun () -> structualEquatable t
Expand Down