diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.4.0.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.4.0.fs index 445f93aa2fc..96ff2ea9b2c 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.4.0.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.4.0.fs @@ -205,6 +205,7 @@ Microsoft.FSharp.Collections.ArrayModule: Void SortInPlace[T](T[]) Microsoft.FSharp.Collections.ComparisonIdentity: Boolean Equals(System.Object) Microsoft.FSharp.Collections.ComparisonIdentity: Int32 GetHashCode() Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] FromFunction[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]]) +Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] NonStructural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() @@ -289,6 +290,7 @@ Microsoft.FSharp.Collections.HashIdentity: Boolean Equals(System.Object) Microsoft.FSharp.Collections.HashIdentity: Int32 GetHashCode() Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] FromFunctions[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean]]) Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] LimitedStructural[T](Int32) +Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] NonStructural[T]() Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] Reference[T]() Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.HashIdentity: System.String ToString() @@ -2443,6 +2445,20 @@ Microsoft.FSharp.Core.Operators+Checked: UInt16 ToUInt16[T](T) Microsoft.FSharp.Core.Operators+Checked: UInt32 ToUInt32[T](T) Microsoft.FSharp.Core.Operators+Checked: UInt64 ToUInt64[T](T) Microsoft.FSharp.Core.Operators+Checked: UIntPtr ToUIntPtr[T](T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean Equals(System.Object) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_Equality[T](T, T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_GreaterThanOrEqual[T,TResult](T, TResult) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_GreaterThan[T,TResult](T, TResult) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_Inequality[T](T, T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_LessThanOrEqual[T,TResult](T, TResult) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_LessThan[T,TResult](T, TResult) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Int32 Compare[T](T, T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Int32 GetHashCode() +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Int32 Hash[T](T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: System.String ToString() +Microsoft.FSharp.Core.Operators+NonStructuralComparison: System.Type GetType() +Microsoft.FSharp.Core.Operators+NonStructuralComparison: T Max[T](T, T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: T Min[T](T, T) Microsoft.FSharp.Core.Operators+OperatorIntrinsics: Boolean Equals(System.Object) Microsoft.FSharp.Core.Operators+OperatorIntrinsics: Byte PowByte(Byte, Int32) Microsoft.FSharp.Core.Operators+OperatorIntrinsics: Double PowDouble(Double, Int32) @@ -2553,6 +2569,7 @@ Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.FSharpOption`1[System.Str Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.FSharpOption`1[T] TryUnbox[T](System.Object) Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.FSharpRef`1[T] Ref[T](T) Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.Operators+Checked +Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.Operators+NonStructuralComparison Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.Operators+OperatorIntrinsics Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.Operators+Unchecked Microsoft.FSharp.Core.Operators: SByte ToSByte[T](T) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.Portable.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.Portable.fs index c357eaac653..37cb72619dd 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.Portable.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.Portable.fs @@ -199,6 +199,7 @@ Microsoft.FSharp.Collections.ArrayModule: Void SortInPlace[T](T[]) Microsoft.FSharp.Collections.ComparisonIdentity: Boolean Equals(System.Object) Microsoft.FSharp.Collections.ComparisonIdentity: Int32 GetHashCode() Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] FromFunction[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]]) +Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] NonStructural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() @@ -283,6 +284,7 @@ Microsoft.FSharp.Collections.HashIdentity: Boolean Equals(System.Object) Microsoft.FSharp.Collections.HashIdentity: Int32 GetHashCode() Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] FromFunctions[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean]]) Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] LimitedStructural[T](Int32) +Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] NonStructural[T]() Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] Reference[T]() Microsoft.FSharp.Collections.HashIdentity: System.Collections.Generic.IEqualityComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.HashIdentity: System.String ToString() @@ -2430,6 +2432,20 @@ Microsoft.FSharp.Core.Operators+Checked: UInt16 ToUInt16[T](T) Microsoft.FSharp.Core.Operators+Checked: UInt32 ToUInt32[T](T) Microsoft.FSharp.Core.Operators+Checked: UInt64 ToUInt64[T](T) Microsoft.FSharp.Core.Operators+Checked: UIntPtr ToUIntPtr[T](T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean Equals(System.Object) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_Equality[T](T, T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_GreaterThanOrEqual[T,TResult](T, TResult) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_GreaterThan[T,TResult](T, TResult) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_Inequality[T](T, T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_LessThanOrEqual[T,TResult](T, TResult) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Boolean op_LessThan[T,TResult](T, TResult) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Int32 Compare[T](T, T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Int32 GetHashCode() +Microsoft.FSharp.Core.Operators+NonStructuralComparison: Int32 Hash[T](T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: System.String ToString() +Microsoft.FSharp.Core.Operators+NonStructuralComparison: System.Type GetType() +Microsoft.FSharp.Core.Operators+NonStructuralComparison: T Max[T](T, T) +Microsoft.FSharp.Core.Operators+NonStructuralComparison: T Min[T](T, T) Microsoft.FSharp.Core.Operators+OperatorIntrinsics: Boolean Equals(System.Object) Microsoft.FSharp.Core.Operators+OperatorIntrinsics: Byte PowByte(Byte, Int32) Microsoft.FSharp.Core.Operators+OperatorIntrinsics: Double PowDouble(Double, Int32) @@ -2540,6 +2556,7 @@ Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.FSharpOption`1[System.Str Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.FSharpOption`1[T] TryUnbox[T](System.Object) Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.FSharpRef`1[T] Ref[T](T) Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.Operators+Checked +Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.Operators+NonStructuralComparison Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.Operators+OperatorIntrinsics Microsoft.FSharp.Core.Operators: Microsoft.FSharp.Core.Operators+Unchecked Microsoft.FSharp.Core.Operators: SByte ToSByte[T](T) diff --git a/src/fsharp/FSharp.Core/Linq.fs b/src/fsharp/FSharp.Core/Linq.fs index 64b0217c7e3..1156b25527b 100644 --- a/src/fsharp/FSharp.Core/Linq.fs +++ b/src/fsharp/FSharp.Core/Linq.fs @@ -233,6 +233,13 @@ module LeafExpressionConverter = let (|LessEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x <= y)) let (|NotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x <> y)) + let (|StaticEqualsQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(=) x y)) + let (|StaticGreaterQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(>) x y)) + let (|StaticGreaterEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(>=) x y)) + let (|StaticLessQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(<) x y)) + let (|StaticLessEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(<=) x y)) + let (|StaticNotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(<>) x y)) + let (|NullableEqualsQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?= ) x y)) let (|NullableNotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?<> ) x y)) let (|NullableGreaterQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?> ) x y)) @@ -487,6 +494,13 @@ module LeafExpressionConverter = | LessEqQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 false Expression.LessThanOrEqual | NotQ (_, _, [x1]) -> Expression.Not(ConvExprToLinqInContext env x1) |> asExpr + | StaticEqualsQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 false Expression.Equal + | StaticNotEqQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 false Expression.NotEqual + | StaticGreaterQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 false Expression.GreaterThan + | StaticGreaterEqQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 false Expression.GreaterThanOrEqual + | StaticLessQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 false Expression.LessThan + | StaticLessEqQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 false Expression.LessThanOrEqual + | NullableEqualsQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 true Expression.Equal | NullableNotEqQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 true Expression.NotEqual | NullableGreaterQ (_, _,[x1;x2]) -> transBinOp env false x1 x2 true Expression.GreaterThan diff --git a/src/fsharp/FSharp.Core/collections.fs b/src/fsharp/FSharp.Core/collections.fs index 3c7f41e3058..6c4e2b23fa8 100644 --- a/src/fsharp/FSharp.Core/collections.fs +++ b/src/fsharp/FSharp.Core/collections.fs @@ -28,6 +28,11 @@ namespace Microsoft.FSharp.Collections member self.GetHashCode(x) = LanguagePrimitives.PhysicalHash(x) member self.Equals(x,y) = LanguagePrimitives.PhysicalEquality x y } + let inline NonStructural< 'T when 'T : equality and 'T : (static member ( = ) : 'T * 'T -> bool) > = + { new IEqualityComparer< 'T > with + member self.GetHashCode(x) = NonStructuralComparison.hash x + member self.Equals(x, y) = NonStructuralComparison.(=) x y } + let inline FromFunctions hash eq : IEqualityComparer<'T> = let eq = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(eq) { new IEqualityComparer<'T> with @@ -37,10 +42,16 @@ namespace Microsoft.FSharp.Collections module ComparisonIdentity = - let inline Structural<'T when 'T : comparison > : IComparer<'T> = LanguagePrimitives.FastGenericComparer<'T> - + +#if BUILDING_WITH_LKG +#else + let inline NonStructural< 'T when 'T : (static member ( < ) : 'T * 'T -> bool) and 'T : (static member ( > ) : 'T * 'T -> bool) > : IComparer< 'T > = + { new IComparer<'T> with + member self.Compare(x,y) = NonStructuralComparison.compare x y } +#endif + let FromFunction comparer = let comparer = OptimizedClosures.FSharpFunc<'T,'T,int>.Adapt(comparer) { new IComparer<'T> with diff --git a/src/fsharp/FSharp.Core/collections.fsi b/src/fsharp/FSharp.Core/collections.fsi index 4ae00f4e644..10e71fceb96 100644 --- a/src/fsharp/FSharp.Core/collections.fsi +++ b/src/fsharp/FSharp.Core/collections.fsi @@ -14,7 +14,13 @@ namespace Microsoft.FSharp.Collections /// Structural comparison. Compare using Operators.compare. val inline Structural<'T> : IComparer<'T> when 'T : comparison - + +#if BUILDING_WITH_LKG +#else + /// Non-structural comparison. Compare using NonStructuralComparison.compare. + val inline NonStructural< ^T > : IComparer< ^T > when ^T : (static member ( < ) : ^T * ^T -> bool) and ^T : (static member ( > ) : ^T * ^T -> bool) +#endif + /// Compare using the given comparer function. /// A function to compare two values. /// An object implementing IComparer using the supplied comparer. @@ -24,10 +30,11 @@ namespace Microsoft.FSharp.Collections module HashIdentity = /// Structural hashing. Hash using Operators.(=) and Operators.hash. - - // inline justification: allows specialization of structural hash functions based on type val inline Structural<'T> : IEqualityComparer<'T> when 'T : equality + /// Non-structural hashing. Equality using NonStructuralComparison.(=) and NonStructuralComparison.hash. + val inline NonStructural<'T> : IEqualityComparer< ^T > when ^T : equality and ^T : (static member ( = ) : ^T * ^T -> bool) + val inline LimitedStructural<'T> : limit: int -> IEqualityComparer<'T> when 'T : equality /// Physical hashing (hash on reference identity of objects, and the contents of value types). diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs index 15eaae8ad34..2fc6ada8824 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -956,13 +956,8 @@ namespace Microsoft.FSharp.Core | null,null -> 0 | null,_ -> -1 | _,null -> 1 -#if INVARIANT_CULTURE_STRING_COMPARISON - // Use invariant culture comparison for strings - | (:? string as x),(:? string as y) -> System.String.Compare(x, y, false, CultureInfo.InvariantCulture) -#else // Use Ordinal comparison for strings | (:? string as x),(:? string as y) -> System.String.CompareOrdinal(x, y) -#endif // Permit structural comparison on arrays | (:? System.Array as arr1),_ -> match arr1,yobj with @@ -1216,15 +1211,9 @@ namespace Microsoft.FSharp.Core when 'T : float32 = if (# "clt" x y : bool #) then (-1) else if (# "cgt" x y : bool #) then 1 else if (# "ceq" x y : bool #) then 0 else GenericComparisonWithComparerIntrinsic comp x y when 'T : char = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) when 'T : string = -#if INVARIANT_CULTURE_STRING_COMPARISON - // NOTE: we don't have to null check here because System.String.Compare - // gives reliable results on null values. - System.String.Compare((# "" x : string #) ,(# "" y : string #), false, CultureInfo.InvariantCulture) -#else // NOTE: we don't have to null check here because System.String.CompareOrdinal // gives reliable results on null values. System.String.CompareOrdinal((# "" x : string #) ,(# "" y : string #)) -#endif when 'T : decimal = System.Decimal.Compare((# "" x:decimal #), (# "" y:decimal #)) @@ -1292,15 +1281,9 @@ namespace Microsoft.FSharp.Core when 'T : float32 = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) when 'T : char = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) when 'T : string = -#if INVARIANT_CULTURE_STRING_COMPARISON - // NOTE: we don't have to null check here because System.String.Compare - // gives reliable results on null values. - System.String.Compare((# "" x : string #) ,(# "" y : string #), false, CultureInfo.InvariantCulture) -#else // NOTE: we don't have to null check here because System.String.CompareOrdinal // gives reliable results on null values. System.String.CompareOrdinal((# "" x : string #) ,(# "" y : string #)) -#endif when 'T : decimal = System.Decimal.Compare((# "" x:decimal #), (# "" y:decimal #)) /// Generic less-than with static optimizations for some well-known cases. @@ -4499,6 +4482,180 @@ namespace Microsoft.FSharp.Core when ^T : byte = (# "conv.u2" x : char #) + module NonStructuralComparison = + /// Static less-than with static optimizations for some well-known cases. + let inline (<) (x:^T) (y:^U) = + ((^T or ^U): (static member (<) : ^T * ^U -> bool) (x,y)) + when ^T : bool = (# "clt" x y : bool #) + when ^T : sbyte = (# "clt" x y : bool #) + when ^T : int16 = (# "clt" x y : bool #) + when ^T : int32 = (# "clt" x y : bool #) + when ^T : int64 = (# "clt" x y : bool #) + when ^T : byte = (# "clt.un" x y : bool #) + when ^T : uint16 = (# "clt.un" x y : bool #) + when ^T : uint32 = (# "clt.un" x y : bool #) + when ^T : uint64 = (# "clt.un" x y : bool #) + when ^T : unativeint = (# "clt.un" x y : bool #) + when ^T : nativeint = (# "clt" x y : bool #) + when ^T : float = (# "clt" x y : bool #) + when ^T : float32= (# "clt" x y : bool #) + when ^T : char = (# "clt" x y : bool #) + when ^T : decimal = System.Decimal.op_LessThan ((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = (# "clt" (System.String.CompareOrdinal((# "" x : string #) ,(# "" y : string #))) 0 : bool #) + + /// Static greater-than with static optimizations for some well-known cases. + let inline (>) (x:^T) (y:^U) = + ((^T or ^U): (static member (>) : ^T * ^U -> bool) (x,y)) + when 'T : bool = (# "cgt" x y : bool #) + when 'T : sbyte = (# "cgt" x y : bool #) + when 'T : int16 = (# "cgt" x y : bool #) + when 'T : int32 = (# "cgt" x y : bool #) + when 'T : int64 = (# "cgt" x y : bool #) + when 'T : nativeint = (# "cgt" x y : bool #) + when 'T : byte = (# "cgt.un" x y : bool #) + when 'T : uint16 = (# "cgt.un" x y : bool #) + when 'T : uint32 = (# "cgt.un" x y : bool #) + when 'T : uint64 = (# "cgt.un" x y : bool #) + when 'T : unativeint = (# "cgt.un" x y : bool #) + when 'T : float = (# "cgt" x y : bool #) + when 'T : float32 = (# "cgt" x y : bool #) + when 'T : char = (# "cgt" x y : bool #) + when 'T : decimal = System.Decimal.op_GreaterThan ((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = (# "cgt" (System.String.CompareOrdinal((# "" x : string #) ,(# "" y : string #))) 0 : bool #) + + /// Static less-than-or-equal with static optimizations for some well-known cases. + let inline (<=) (x:^T) (y:^U) = + ((^T or ^U): (static member (<=) : ^T * ^U -> bool) (x,y)) + when 'T : bool = not (# "cgt" x y : bool #) + when 'T : sbyte = not (# "cgt" x y : bool #) + when 'T : int16 = not (# "cgt" x y : bool #) + when 'T : int32 = not (# "cgt" x y : bool #) + when 'T : int64 = not (# "cgt" x y : bool #) + when 'T : nativeint = not (# "cgt" x y : bool #) + when 'T : byte = not (# "cgt.un" x y : bool #) + when 'T : uint16 = not (# "cgt.un" x y : bool #) + when 'T : uint32 = not (# "cgt.un" x y : bool #) + when 'T : uint64 = not (# "cgt.un" x y : bool #) + when 'T : unativeint = not (# "cgt.un" x y : bool #) + when 'T : float = not (# "cgt.un" x y : bool #) + when 'T : float32 = not (# "cgt.un" x y : bool #) + when 'T : char = not (# "cgt" x y : bool #) + when 'T : decimal = System.Decimal.op_LessThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = not (# "cgt" (System.String.CompareOrdinal((# "" x : string #) ,(# "" y : string #))) 0 : bool #) + + /// Static greater-than-or-equal with static optimizations for some well-known cases. + let inline (>=) (x:^T) (y:^U) = + ((^T or ^U): (static member (>=) : ^T * ^U -> bool) (x,y)) + when 'T : bool = not (# "clt" x y : bool #) + when 'T : sbyte = not (# "clt" x y : bool #) + when 'T : int16 = not (# "clt" x y : bool #) + when 'T : int32 = not (# "clt" x y : bool #) + when 'T : int64 = not (# "clt" x y : bool #) + when 'T : nativeint = not (# "clt" x y : bool #) + when 'T : byte = not (# "clt.un" x y : bool #) + when 'T : uint16 = not (# "clt.un" x y : bool #) + when 'T : uint32 = not (# "clt.un" x y : bool #) + when 'T : uint64 = not (# "clt.un" x y : bool #) + when 'T : unativeint = not (# "clt.un" x y : bool #) + when 'T : float = not (# "clt.un" x y : bool #) + when 'T : float32 = not (# "clt.un" x y : bool #) + when 'T : char = not (# "clt" x y : bool #) + when 'T : decimal = System.Decimal.op_GreaterThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = not (# "clt" (System.String.CompareOrdinal((# "" x : string #) ,(# "" y : string #))) 0 : bool #) + + + /// Static greater-than-or-equal with static optimizations for some well-known cases. + let inline (=) (x:^T) (y:^T) = + (^T : (static member (=) : ^T * ^T -> bool) (x,y)) + when ^T : bool = (# "ceq" x y : bool #) + when ^T : sbyte = (# "ceq" x y : bool #) + when ^T : int16 = (# "ceq" x y : bool #) + when ^T : int32 = (# "ceq" x y : bool #) + when ^T : int64 = (# "ceq" x y : bool #) + when ^T : byte = (# "ceq" x y : bool #) + when ^T : uint16 = (# "ceq" x y : bool #) + when ^T : uint32 = (# "ceq" x y : bool #) + when ^T : uint64 = (# "ceq" x y : bool #) + when ^T : float = (# "ceq" x y : bool #) + when ^T : float32 = (# "ceq" x y : bool #) + when ^T : char = (# "ceq" x y : bool #) + when ^T : nativeint = (# "ceq" x y : bool #) + when ^T : unativeint = (# "ceq" x y : bool #) + when ^T : string = System.String.Equals((# "" x : string #),(# "" y : string #)) + when ^T : decimal = System.Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) + + let inline (<>) (x:^T) (y:^T) = + (^T : (static member (<>) : ^T * ^T -> bool) (x,y)) + when ^T : bool = not (# "ceq" x y : bool #) + when ^T : sbyte = not (# "ceq" x y : bool #) + when ^T : int16 = not (# "ceq" x y : bool #) + when ^T : int32 = not (# "ceq" x y : bool #) + when ^T : int64 = not (# "ceq" x y : bool #) + when ^T : byte = not (# "ceq" x y : bool #) + when ^T : uint16 = not (# "ceq" x y : bool #) + when ^T : uint32 = not (# "ceq" x y : bool #) + when ^T : uint64 = not (# "ceq" x y : bool #) + when ^T : float = not (# "ceq" x y : bool #) + when ^T : float32 = not (# "ceq" x y : bool #) + when ^T : char = not (# "ceq" x y : bool #) + when ^T : nativeint = not (# "ceq" x y : bool #) + when ^T : unativeint = not (# "ceq" x y : bool #) + when ^T : string = not (System.String.Equals((# "" x : string #),(# "" y : string #))) + when ^T : decimal = System.Decimal.op_Inequality((# "" x:decimal #), (# "" y:decimal #)) + + + [] + let inline compare (x:^T) (y:^T) : int = + (if x < y then -1 elif x > y then 1 else 0) + when ^T : bool = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) + when ^T : sbyte = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) + when ^T : int16 = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) + when ^T : int32 = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) + when ^T : int64 = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) + when ^T : nativeint = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) + when ^T : byte = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) + when ^T : uint16 = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) + when ^T : uint32 = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) + when ^T : uint64 = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) + when ^T : unativeint = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) + when ^T : float = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) + when ^T : float32 = if (# "clt" x y : bool #) then (-1) else (# "cgt" x y : int #) + when ^T : char = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) + when ^T : string = + // NOTE: we don't have to null check here because System.String.CompareOrdinal + // gives reliable results on null values. + System.String.CompareOrdinal((# "" x : string #) ,(# "" y : string #)) + when ^T : decimal = System.Decimal.Compare((# "" x:decimal #), (# "" y:decimal #)) + + [] + let inline max (x:^T) y = + (if x < y then y else x) + when ^T : float = (System.Math.Max : float * float -> float)(retype<_,float> x, retype<_,float> y) + when ^T : float32 = (System.Math.Max : float32 * float32 -> float32)(retype<_,float32> x, retype<_,float32> y) + + [] + let inline min (x: ^T) y = + (if x < y then x else y) + when ^T : float = (System.Math.Min : float * float -> float)(retype<_,float> x, retype<_,float> y) + when ^T : float32 = (System.Math.Min : float32 * float32 -> float32)(retype<_,float32> x, retype<_,float32> y) + + [] + let inline hash (x:'T) = + x.GetHashCode() + when 'T : bool = (# "" x : int #) + when 'T : int32 = (# "" x : int #) + when 'T : byte = (# "" x : int #) + when 'T : uint32 = (# "" x : int #) + when 'T : char = HashCompare.HashChar (# "" x : char #) + when 'T : sbyte = HashCompare.HashSByte (# "" x : sbyte #) + when 'T : int16 = HashCompare.HashInt16 (# "" x : int16 #) + when 'T : int64 = HashCompare.HashInt64 (# "" x : int64 #) + when 'T : uint64 = HashCompare.HashUInt64 (# "" x : uint64 #) + when 'T : nativeint = HashCompare.HashIntPtr (# "" x : nativeint #) + when 'T : unativeint = HashCompare.HashUIntPtr (# "" x : unativeint #) + when 'T : uint16 = (# "" x : int #) + when 'T : string = HashCompare.HashString (# "" x : string #) + module Attributes = open System.Runtime.CompilerServices diff --git a/src/fsharp/FSharp.Core/prim-types.fsi b/src/fsharp/FSharp.Core/prim-types.fsi index 916232c3e87..dc8ee26bfdf 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -3047,6 +3047,73 @@ namespace Microsoft.FSharp.Core /// The computed hash value. val inline hash : 'T -> int + /// A module of comparison and equality operators that are statically resolved, but which are not fully generic and do not make structural comparison. Opening this + /// module may make code that relies on structural or generic comparison no longer compile. + module NonStructuralComparison = + + /// Compares the two values for less-than + /// The first parameter. + /// The second parameter. + /// The result of the comparison. + val inline ( < ) : x:^T -> y:^U -> bool when (^T or ^U) : (static member ( < ) : ^T * ^U -> bool) + + /// Compares the two values for greater-than + /// The first parameter. + /// The second parameter. + /// The result of the comparison. + val inline ( > ) : x:^T -> y:^U -> bool when (^T or ^U) : (static member ( > ) : ^T * ^U -> bool) + + /// Compares the two values for greater-than-or-equal + /// The first parameter. + /// The second parameter. + /// The result of the comparison. + val inline ( >= ) : x:^T -> y:^U -> bool when (^T or ^U) : (static member ( >= ) : ^T * ^U -> bool) + + /// Compares the two values for less-than-or-equal + /// The first parameter. + /// The second parameter. + /// The result of the comparison. + val inline ( <= ) : x:^T -> y:^U -> bool when (^T or ^U) : (static member ( <= ) : ^T * ^U -> bool) + + /// Compares the two values for equality + /// The first parameter. + /// The second parameter. + /// The result of the comparison. + val inline ( = ) : x:^T -> y:^T -> bool when ^T : (static member ( = ) : ^T * ^T -> bool) + + /// Compares the two values for inequality + /// The first parameter. + /// The second parameter. + /// The result of the comparison. + val inline ( <> ) : x:^T -> y:^T -> bool when ^T : (static member ( <> ) : ^T * ^T -> bool) + + /// Compares the two values + /// The first value. + /// The second value. + /// The result of the comparison. + [] + val inline compare: e1:'T -> e2:^T -> int when ^T : (static member ( < ) : ^T * ^T -> bool) and ^T : (static member ( > ) : ^T * ^T -> bool) + + /// Maximum of the two values + /// The first value. + /// The second value. + /// The maximum value. + [] + val inline max : e1:^T -> e2:^T -> ^T when ^T : (static member ( < ) : ^T * ^T -> bool) + + /// Minimum of the two values + /// The first value. + /// The second value. + /// The minimum value. + [] + val inline min : e1:^T -> e2:^T -> ^T when ^T : (static member ( < ) : ^T * ^T -> bool) + + /// Calls GetHashCode() on the value + /// The value. + /// The hash code. + [] + val inline hash :value:'T -> int when 'T : equality + /// This module contains the basic arithmetic operations with overflow checks. module Checked = /// Overloaded unary negation (checks for overflow) diff --git a/src/fsharp/csolve.fs b/src/fsharp/csolve.fs index 99b095a8d82..92f338e6e8e 100644 --- a/src/fsharp/csolve.fs +++ b/src/fsharp/csolve.fs @@ -226,6 +226,7 @@ let rec isIntegerTy g ty = let isStringTy g ty = typeEquiv g g.string_ty ty let isCharTy g ty = typeEquiv g g.char_ty ty +let isBoolTy g ty = typeEquiv g g.bool_ty ty /// float or float32 or float<_> or float32<_> let isFpTy g ty = @@ -240,6 +241,7 @@ let IsNonDecimalNumericOrIntegralEnumType g ty = isIntegerOrIntegerEnumTy g ty | let IsNumericOrIntegralEnumType g ty = IsNonDecimalNumericOrIntegralEnumType g ty || isDecimalTy g ty let IsNonDecimalNumericType g ty = isIntegerTy g ty || isFpTy g ty let IsNumericType g ty = IsNonDecimalNumericType g ty || isDecimalTy g ty +let IsRelationalType g ty = IsNumericType g ty || isStringTy g ty || isCharTy g ty || isBoolTy g ty // Get measure of type, float<_> or float32<_> or decimal<_> but not float=float<1> or float32=float32<1> or decimal=decimal<1> let GetMeasureOfType g ty = @@ -259,6 +261,7 @@ type TraitConstraintSolution = let BakedInTraitConstraintNames = [ "op_Division" ; "op_Multiply"; "op_Addition" + "op_Equality" ; "op_Inequality"; "op_GreaterThan" ; "op_LessThan"; "op_LessThanOrEqual"; "op_GreaterThanOrEqual" "op_Subtraction"; "op_Modulus"; "get_Zero"; "get_One"; "DivideByInt";"get_Item"; "set_Item"; @@ -977,6 +980,14 @@ and SolveMemberConstraint (csenv:ConstraintSolverEnv) permitWeakResolution ndeep SolveTypEqualsTypKeepAbbrevs csenv ndeep m2 trace rty argty1 ++ (fun () -> ResultD TTraitBuiltIn)) + | _,_,false,("op_LessThan" | "op_LessThanOrEqual" | "op_GreaterThan" | "op_GreaterThanOrEqual" | "op_Equality" | "op_Inequality" ),[argty1;argty2] + when // Ignore any explicit overloads from any basic integral types + (minfos |> List.forall (fun minfo -> isIntegerTy g minfo.EnclosingType ) && + ( (IsRelationalType g argty1 && (permitWeakResolution || not (isTyparTy g argty2))) + || (IsRelationalType g argty2 && (permitWeakResolution || not (isTyparTy g argty1))))) -> + SolveTypEqualsTypKeepAbbrevs csenv ndeep m2 trace argty2 argty1 ++ (fun () -> + SolveTypEqualsTypKeepAbbrevs csenv ndeep m2 trace rty g.bool_ty ++ (fun () -> + ResultD TTraitBuiltIn)) // We pretend for uniformity that the numeric types have a static property called Zero and One // As with constants, only zero is polymorphic in its units diff --git a/tests/fsharp/core/libtest/test.fsx b/tests/fsharp/core/libtest/test.fsx index 5a8c9cefbd6..d29eeb64906 100644 --- a/tests/fsharp/core/libtest/test.fsx +++ b/tests/fsharp/core/libtest/test.fsx @@ -71,12 +71,11 @@ let reportFailure s = #else let argv = System.Environment.GetCommandLineArgs() let SetCulture() = - if argv.Length > 2 && argv.[1] = "--culture" then begin + if argv.Length > 2 && argv.[1] = "--culture" then let cultureString = argv.[2] in let culture = new System.Globalization.CultureInfo(cultureString) in stdout.WriteLine ("Running under culture "+culture.ToString()+"..."); System.Threading.Thread.CurrentThread.CurrentCulture <- culture - end do SetCulture() #endif @@ -818,7 +817,7 @@ let _ = printString "type specific hash matches generic hash (9): "; if getObjec !* check we can resolve overlapping constructor names using type names *--------------------------------------------------------------------------- *) -module OverlappingCOnstructorNames = begin +module OverlappingCOnstructorNames = type XY = X | Y type YZ = Y | Z @@ -842,13 +841,6 @@ module OverlappingCOnstructorNames = begin | YZ.Y -> "X" | YZ.Z -> "Y" -end - - -(*--------------------------------------------------------------------------- -!* hashing of large terms that contain back pointers (are infinite) - *--------------------------------------------------------------------------- *) - (*--------------------------------------------------------------------------- !* Equality tests over structured values for data likely to contain @@ -1444,7 +1436,7 @@ let _ = test "List.rev d" (List.rev [1; 2] = [2; 1]) -module MinMaxAverageSum = begin +module MinMaxAverageSum = do test "ceijoe9cewz" (Seq.sum [] = 0) do test "ceijoe9cewx" (Seq.sum [1;2;3] = 6) do test "ceijoe9cewv" (Seq.sum [0.0;1.0] = 1.0) @@ -1506,10 +1498,10 @@ module MinMaxAverageSum = begin do test "ceijoe9ceww" (List.max [1.0M;2.0M;3.0M] = 3.0M) do test "ceijoe9cewe" (List.max [3.0M;2.0M;1.0M] = 3.0M) -end -module Pow = begin + +module Pow = do test "cnod90km1" (pown 2.0 -3 = 0.125) do test "cnod90km2" (pown 2.0 -2 = 0.25) do test "cnod90km3" (pown 2.0 -1 = 0.5) @@ -1615,9 +1607,9 @@ module Pow = begin test "cnod90kmbb1a" (pown (byte baseIdx) 2 = (byte baseIdx) * (byte baseIdx)); ) done -end -module TakeUntilSkipWhile = begin + +module TakeUntilSkipWhile = do test "oewvjrrovvr1" ([ ] |> Seq.takeWhile (fun x -> x <= 5) |> Seq.toList = [ ]) do test "oewvjrrovvr2" ([ 1 ] |> Seq.takeWhile (fun x -> x <= 5) |> Seq.toList = [ 1 ]) @@ -1631,7 +1623,6 @@ module TakeUntilSkipWhile = begin do test "oewvjrrovvr9" ([ 1;2;3;4;5;6;7 ] |> Seq.skipWhile (fun x -> x <= 5) |> Seq.toList = [ 6;7 ]) do test "oewvjrrovvra" ([ 1;2;3;4;5;6;5;4;3;2;1 ] |> Seq.skipWhile (fun x -> x <= 5) |> Seq.toList = [ 6;5;4;3;2;1 ]) -end (*--------------------------------------------------------------------------- @@ -2087,19 +2078,19 @@ let sort_test cmp ans = let _ = sort_test compare [0;1;2;3;4;5] let _ = sort_test (fun x y -> -(compare x y)) [5;4;3;2;1;0] *) -module StrangeOperatorTest = begin - let (&&&) x y = x^y - let (<<<) (x:string) (y:string) = x ^y^x +module StrangeOperatorTest = + let (&&&) x y = x^y + let (<<<) (x:string) (y:string) = x ^y^x - let e1 = ("0" &&& ("1" <<< "2")) - let e2= (("0" &&& "1") <<< "2") - let e3= ("0" &&& "1" <<< "2") + let e1 = ("0" &&& ("1" <<< "2")) + let e2= (("0" &&& "1") <<< "2") + let e3= ("0" &&& "1" <<< "2") + + let _ = if (e1 <> e2) then stderr.WriteLine "Control Passed" else stderr.WriteLine "Control Failed" + let _ = if (e1 = e3) then (stderr.WriteLine "Parsed to Right! Wrong!" ; reportFailure "parsing") + let _ = if (e2 = e3) then stderr.WriteLine "Parsed to Left - correct!" - let _ = if (e1 <> e2) then stderr.WriteLine "Control Passed" else stderr.WriteLine "Control Failed" - let _ = if (e1 = e3) then (stderr.WriteLine "Parsed to Right! Wrong!" ; reportFailure "parsing") - let _ = if (e2 = e3) then stderr.WriteLine "Parsed to Left - correct!" -end //let _ = if (3 then do ignore(4)) = 3 then stderr.WriteLine "OK!" else (stderr.WriteLine "Wrong!" ; reportFailure "unlabelled test") //let _ = let x = ref 1 in if (!x then do x := !x + 1) = 1 then stderr.WriteLine "OK!" else (stderr.WriteLine "Wrong!" ; reportFailure "unlabelled test") @@ -2331,12 +2322,11 @@ do check "type test double" 1.0 (match box(1.0) with | :? System.Int32 -> 3.14 | !* type syntax *--------------------------------------------------------------------------- *) -module TypeSyntax = begin - let x1 = [Map.add 1 (Map.add 1 1 Map.empty) Map.empty] - let x2 : Map<'a,'b> list = [Map.empty] - let x3 : Map<'a,'b> list = [] +module TypeSyntax = + let x1 = [Map.add 1 (Map.add 1 1 Map.empty) Map.empty] + let x2 : Map<'a,'b> list = [Map.empty] + let x3 : Map<'a,'b> list = [] -end module IEnumerableTests = begin @@ -2855,52 +2845,101 @@ let nan2 = (let r = ref Double.NaN in (if sprintf "Hello" = "Hello" then !r else do printf "checking floating point relational operators\n" let _ = check "d3wiojd30a" ((Double.NaN > Double.NaN)) false -let _ = check "d3wiojd30a" (if (Double.NaN > Double.NaN) then "a" else "b") "b" -let _ = check "d3wiojd30b" ((Double.NaN >= Double.NaN)) false -let _ = check "d3wiojd30b" (if (Double.NaN >= Double.NaN) then "a" else "b") "b" -let _ = check "d3wiojd30c" ((Double.NaN < Double.NaN)) false -let _ = check "d3wiojd30c" (if (Double.NaN < Double.NaN) then "a" else "b") "b" -let _ = check "d3wiojd30d" ((Double.NaN <= Double.NaN)) false -let _ = check "d3wiojd30d" (if (Double.NaN <= Double.NaN) then "a" else "b") "b" -let _ = check "d3wiojd30e" ((Double.NaN = Double.NaN)) false -let _ = check "d3wiojd30e" (if (Double.NaN = Double.NaN) then "a" else "b") "b" -let _ = check "d3wiojd30q" ((Double.NaN <> Double.NaN)) true -let _ = check "d3wiojd30w" ((Double.NaN > 1.0)) false -let _ = check "d3wiojd30e" ((Double.NaN >= 1.0)) false -let _ = check "d3wiojd30r" ((Double.NaN < 1.0)) false -let _ = check "d3wiojd30t" ((Double.NaN <= 1.0)) false -let _ = check "d3wiojd30y" ((Double.NaN = 1.0)) false -let _ = check "d3wiojd30u" ((Double.NaN <> 1.0)) true -let _ = check "d3wiojd30i" ((1.0 > Double.NaN)) false -let _ = check "d3wiojd30o" ((1.0 >= Double.NaN)) false -let _ = check "d3wiojd30p" ((1.0 < Double.NaN)) false -let _ = check "d3wiojd30a" ((1.0 <= Double.NaN)) false -let _ = check "d3wiojd30s" ((1.0 = Double.NaN)) false -let _ = check "d3wiojd30d" ((1.0 <> Double.NaN)) true -let _ = check "d3wiojd30a" ((nan1 > Double.NaN)) false -let _ = check "d3wiojd30b" ((nan1 >= nan2)) false -let _ = check "d3wiojd30c" ((nan1 < nan2)) false -let _ = check "d3wiojd30d" ((nan1 <= nan2)) false -let _ = check "d3wiojd30e" ((nan1 = nan2)) false -let _ = check "d3wiojd30q" ((nan1 <> nan2)) true -let _ = check "d3wiojd30w" ((nan1 > 1.0)) false -let _ = check "d3wiojd30e" ((nan1 >= 1.0)) false -let _ = check "d3wiojd30r" ((nan1 < 1.0)) false -let _ = check "d3wiojd30t" ((nan1 <= 1.0)) false -let _ = check "d3wiojd30y" ((nan1 = 1.0)) false -let _ = check "d3wiojd30u" ((nan1 <> 1.0)) true -let _ = check "d3wiojd30i" ((1.0 > nan2)) false -let _ = check "d3wiojd30o" ((1.0 >= nan2)) false -let _ = check "d3wiojd30p" ((1.0 < nan2)) false -let _ = check "d3wiojd30a" ((1.0 <= nan2)) false -let _ = check "d3wiojd30s" ((1.0 = nan2)) false -let _ = check "d3wiojd30d" ((1.0 <> nan2)) true -let _ = check "d3wiojd30f" ((Double.NegativeInfinity = Double.NegativeInfinity)) true -let _ = check "d3wiojd30g" ((Double.NegativeInfinity < Double.PositiveInfinity)) true -let _ = check "d3wiojd30h" ((Double.NegativeInfinity > Double.PositiveInfinity)) false -let _ = check "d3wiojd30j" ((Double.NegativeInfinity <= Double.NegativeInfinity)) true - -module FloatingPointStructured = begin +check "d3wiojd30a" (if (Double.NaN > Double.NaN) then "a" else "b") "b" +check "d3wiojd30b" ((Double.NaN >= Double.NaN)) false +check "d3wiojd30b" (if (Double.NaN >= Double.NaN) then "a" else "b") "b" +check "d3wiojd30c" ((Double.NaN < Double.NaN)) false +check "d3wiojd30c" (if (Double.NaN < Double.NaN) then "a" else "b") "b" +check "d3wiojd30d" ((Double.NaN <= Double.NaN)) false +check "d3wiojd30d" (if (Double.NaN <= Double.NaN) then "a" else "b") "b" +check "d3wiojd30e" ((Double.NaN = Double.NaN)) false +check "d3wiojd30e" (if (Double.NaN = Double.NaN) then "a" else "b") "b" +check "d3wiojd30q" ((Double.NaN <> Double.NaN)) true +check "d3wiojd30w" ((Double.NaN > 1.0)) false +check "d3wiojd30e" ((Double.NaN >= 1.0)) false +check "d3wiojd30r" ((Double.NaN < 1.0)) false +check "d3wiojd30t" ((Double.NaN <= 1.0)) false +check "d3wiojd30y" ((Double.NaN = 1.0)) false +check "d3wiojd30u" ((Double.NaN <> 1.0)) true +check "d3wiojd30i" ((1.0 > Double.NaN)) false +check "d3wiojd30o" ((1.0 >= Double.NaN)) false +check "d3wiojd30p" ((1.0 < Double.NaN)) false +check "d3wiojd30a" ((1.0 <= Double.NaN)) false +check "d3wiojd30s" ((1.0 = Double.NaN)) false +check "d3wiojd30d" ((1.0 <> Double.NaN)) true +check "d3wiojd30a" ((nan1 > Double.NaN)) false +check "d3wiojd30b" ((nan1 >= nan2)) false +check "d3wiojd30c" ((nan1 < nan2)) false +check "d3wiojd30d" ((nan1 <= nan2)) false +check "d3wiojd30e" ((nan1 = nan2)) false +check "d3wiojd30q" ((nan1 <> nan2)) true +check "d3wiojd30w" ((nan1 > 1.0)) false +check "d3wiojd30e" ((nan1 >= 1.0)) false +check "d3wiojd30r" ((nan1 < 1.0)) false +check "d3wiojd30t" ((nan1 <= 1.0)) false +check "d3wiojd30y" ((nan1 = 1.0)) false +check "d3wiojd30u" ((nan1 <> 1.0)) true +check "d3wiojd30i" ((1.0 > nan2)) false +check "d3wiojd30o" ((1.0 >= nan2)) false +check "d3wiojd30p" ((1.0 < nan2)) false +check "d3wiojd30a" ((1.0 <= nan2)) false +check "d3wiojd30s" ((1.0 = nan2)) false +check "d3wiojd30d" ((1.0 <> nan2)) true +check "d3wiojd30f" ((Double.NegativeInfinity = Double.NegativeInfinity)) true +check "d3wiojd30g" ((Double.NegativeInfinity < Double.PositiveInfinity)) true +check "d3wiojd30h" ((Double.NegativeInfinity > Double.PositiveInfinity)) false +check "d3wiojd30j" ((Double.NegativeInfinity <= Double.NegativeInfinity)) true + +module SameTestsUsingNonStructuralComparison1 = + open NonStructuralComparison + + check "d3wiojd30a" (if (Double.NaN > Double.NaN) then "a" else "b") "b" + check "d3wiojd30b" ((Double.NaN >= Double.NaN)) false + check "d3wiojd30b" (if (Double.NaN >= Double.NaN) then "a" else "b") "b" + check "d3wiojd30c" ((Double.NaN < Double.NaN)) false + check "d3wiojd30c" (if (Double.NaN < Double.NaN) then "a" else "b") "b" + check "d3wiojd30d" ((Double.NaN <= Double.NaN)) false + check "d3wiojd30d" (if (Double.NaN <= Double.NaN) then "a" else "b") "b" + check "d3wiojd30e" ((Double.NaN = Double.NaN)) false + check "d3wiojd30e" (if (Double.NaN = Double.NaN) then "a" else "b") "b" + check "d3wiojd30q" ((Double.NaN <> Double.NaN)) true + check "d3wiojd30w" ((Double.NaN > 1.0)) false + check "d3wiojd30e" ((Double.NaN >= 1.0)) false + check "d3wiojd30r" ((Double.NaN < 1.0)) false + check "d3wiojd30t" ((Double.NaN <= 1.0)) false + check "d3wiojd30y" ((Double.NaN = 1.0)) false + check "d3wiojd30u" ((Double.NaN <> 1.0)) true + check "d3wiojd30i" ((1.0 > Double.NaN)) false + check "d3wiojd30o" ((1.0 >= Double.NaN)) false + check "d3wiojd30p" ((1.0 < Double.NaN)) false + check "d3wiojd30a" ((1.0 <= Double.NaN)) false + check "d3wiojd30s" ((1.0 = Double.NaN)) false + check "d3wiojd30d" ((1.0 <> Double.NaN)) true + check "d3wiojd30a" ((nan1 > Double.NaN)) false + check "d3wiojd30b" ((nan1 >= nan2)) false + check "d3wiojd30c" ((nan1 < nan2)) false + check "d3wiojd30d" ((nan1 <= nan2)) false + check "d3wiojd30e" ((nan1 = nan2)) false + check "d3wiojd30q" ((nan1 <> nan2)) true + check "d3wiojd30w" ((nan1 > 1.0)) false + check "d3wiojd30e" ((nan1 >= 1.0)) false + check "d3wiojd30r" ((nan1 < 1.0)) false + check "d3wiojd30t" ((nan1 <= 1.0)) false + check "d3wiojd30y" ((nan1 = 1.0)) false + check "d3wiojd30u" ((nan1 <> 1.0)) true + check "d3wiojd30i" ((1.0 > nan2)) false + check "d3wiojd30o" ((1.0 >= nan2)) false + check "d3wiojd30p" ((1.0 < nan2)) false + check "d3wiojd30a" ((1.0 <= nan2)) false + check "d3wiojd30s" ((1.0 = nan2)) false + check "d3wiojd30d" ((1.0 <> nan2)) true + check "d3wiojd30f" ((Double.NegativeInfinity = Double.NegativeInfinity)) true + check "d3wiojd30g" ((Double.NegativeInfinity < Double.PositiveInfinity)) true + check "d3wiojd30h" ((Double.NegativeInfinity > Double.PositiveInfinity)) false + check "d3wiojd30j" ((Double.NegativeInfinity <= Double.NegativeInfinity)) true + + +module FloatingPointStructured = type www = W of float do printf "checking floating point relational operators on structured data\n" @@ -2930,9 +2969,9 @@ module FloatingPointStructured = begin let _ = check "d3wiojd31c" ((W Double.NegativeInfinity < W Double.PositiveInfinity)) true let _ = check "d3wiojd3xx" ((W Double.NegativeInfinity > W Double.PositiveInfinity)) false let _ = check "d3wiojd31z" ((W Double.NegativeInfinity <= W Double.NegativeInfinity)) true -end -module FloatingPointStructuredPoly = begin + +module FloatingPointStructuredPoly = type 'a www = W of 'a do printf "checking floating point relational operators on polymorphic structured data\n" @@ -2960,9 +2999,9 @@ module FloatingPointStructuredPoly = begin let _ = check "d3wiojd32z" ((W Double.NegativeInfinity < W Double.PositiveInfinity)) true let _ = check "d3wiojd32x" ((W Double.NegativeInfinity > W Double.PositiveInfinity)) false let _ = check "d3wiojd32c" ((W Double.NegativeInfinity <= W Double.NegativeInfinity)) true -end -module MoreStructuralEqHashCompareNaNChecks = begin + +module MoreStructuralEqHashCompareNaNChecks = let test398275413() = let floats = [1.0; 0.0; System.Double.NaN; System.Double.NegativeInfinity; System.Double.PositiveInfinity; nan] in for x in floats do @@ -3199,7 +3238,7 @@ module MoreStructuralEqHashCompareNaNChecks = begin let _ = test398275416() -end + // This test tests basic behavior of IEquatable and IComparable augmentations module GenericComparisonAndEquality = begin @@ -4268,6 +4307,188 @@ do check "cenonoiwc" (int64 4UL) 4L do check "cenonoiwc" (uint64 4UL) 4UL do check "cenonoiwc" (match null with null -> 2 | _ -> 1) 2 +module SameTestsUsingNonStructuralComparison2 = + open NonStructuralComparison + + do check "ffcenonoiwe1" (3 > 1) true + do check "ffcenonoiwe2" (3y > 1y) true + do check "ffcenonoiwe3" (3uy > 1uy) true + do check "ffcenonoiwe4" (3s > 1s) true + do check "ffcenonoiwe5" (3us > 1us) true + do check "ffcenonoiwe6" (3 > 1) true + do check "ffcenonoiwe7" (3u > 1u) true + do check "ffcenonoiwe8" (3L > 1L) true + do check "ffcenonoiwe9" (3UL > 1UL) true + do check "ffcenonoiwe9" (3.14 > 3.1) true + do check "ffcenonoiwe9" (3.14f > 3.1f) true + do check "ffcenonoiwe9" ("bbb" > "aaa") true + do check "ffcenonoiwe9" ("bbb" > "bbb") false + do check "ffcenonoiwe9" ("aaa" > "bbb") false + do check "ffcenonoiwe9" ('b' > 'a') true + do check "ffcenonoiwe9" ('a' > 'b') false + do check "ffcenonoiwe9" ('b' > 'b') false + + do check "ffcenonoiwea" (3 >= 3) true + do check "ffcenonoiwes" (3y >= 3y) true + do check "ffcenonoiwed" (3uy >= 3uy) true + do check "ffcenonoiwef" (3s >= 3s) true + do check "ffcenonoiweg" (3us >= 3us) true + do check "ffcenonoiweh" (3 >= 3) true + do check "ffcenonoiwej" (3u >= 3u) true + do check "ffcenonoiwek" (3L >= 3L) true + do check "ffcenonoiwel" (3UL >= 3UL) true + do check "ffcenonoiwem" (3.14 >= 3.1) true + do check "ffcenonoiwen" (3.14f >= 3.1f) true + do check "ffcenonoiwen" (3.14M >= 3.1M) true + do check "ffcenonoiwe91r" ("bbb" >= "aaa") true + do check "ffcenonoiwe92r" ("bbb" >= "bbb") true + do check "ffcenonoiwe93r" ("aaa" >= "bbb") false + do check "ffcenonoiwe94r" ('b' >= 'a') true + do check "ffcenonoiwe95r" ('a' >= 'b') false + do check "ffcenonoiwe96r" ('b' >= 'b') true + + + do check "ffcenonoiwd1" (3 < 1) false + do check "ffcenonoiwd2" (3y < 1y) false + do check "ffcenonoiwd3" (3uy < 1uy) false + do check "ffcenonoiwd4" (3s < 1s) false + do check "ffcenonoiwd5" (3us < 1us) false + do check "ffcenonoiwd6" (3 < 1) false + do check "ffcenonoiwd7" (3u < 1u) false + do check "ffcenonoiwd8" (3L < 1L) false + do check "ffcenonoiwd9" (3UL < 1UL) false + do check "ffcenonoiwd9" (3.14 < 1.0) false + do check "ffcenonoiwd9" (3.14f < 1.0f) false + do check "ffcenonoiwd9" (3.14M < 1.0M) false + do check "ffcenonoiwe91a" ("bbb" < "aaa") false + do check "ffcenonoiwe92a" ("bbb" < "bbb") false + do check "ffcenonoiwe93a" ("aaa" < "bbb") true + do check "ffcenonoiwe94a" ('b' < 'a') false + do check "ffcenonoiwe95a" ('a' < 'b') true + do check "ffcenonoiwe96a" ('b' < 'b') false + + + do check "ffcenonoiwdq" (3 <= 1) false + do check "ffcenonoiwdw" (3y <= 1y) false + do check "ffcenonoiwde" (3uy <= 1uy) false + do check "ffcenonoiwdr" (3s <= 1s) false + do check "ffcenonoiwdt" (3us <= 1us) false + do check "ffcenonoiwdy" (3 <= 1) false + do check "ffcenonoiwdu" (3u <= 1u) false + do check "ffcenonoiwdi" (3L <= 1L) false + do check "ffcenonoiwdo" (3UL <= 1UL) false + do check "ffcenonoiwdg" (3.14 <= 1.0) false + do check "ffcenonoiwdt" (3.14f <= 1.0f) false + do check "ffcenonoiwdt" (3.14M <= 1.0M) false + do check "ffcenonoiwe91q" ("bbb" <= "aaa") false + do check "ffcenonoiwe92q" ("bbb" <= "bbb") true + do check "ffcenonoiwe93q" ("aaa" <= "bbb") true + do check "ffcenonoiwe94q" ('b' <= 'a') false + do check "ffcenonoiwe95q" ('a' <= 'b') true + do check "ffcenonoiwe96q" ('b' <= 'b') true + + + do check "ffcenonoiwda" (3 <= 3) true + do check "ffcenonoiwds" (3y <= 3y) true + do check "ffcenonoiwdd" (3uy <= 3uy) true + do check "ffcenonoiwdf" (3s <= 3s) true + do check "ffcenonoiwdg" (3us <= 3us) true + do check "ffcenonoiwdh" (3 <= 3) true + do check "ffcenonoiwdj" (3u <= 3u) true + do check "ffcenonoiwdk" (3L <= 3L) true + do check "ffcenonoiwdl" (3UL <= 3UL) true + do check "ffcenonoiwdo" (3.14 <= 3.14) true + do check "ffcenonoiwdp" (3.14f <= 3.14f) true + do check "ffcenonoiwdp" (3.14M <= 3.14M) true + + +module NonStructuralComparisonOverDateTime = + open NonStructuralComparison + let now = System.DateTime.Now + let tom = now.AddDays 1.0 + do check "ffcenonoiwe90" (now = tom) false + do check "ffcenonoiwe9q" (now <> tom) true + do check "ffcenonoiwe91" (now < tom) true + do check "ffcenonoiwe92" (now <= now) true + do check "ffcenonoiwe93" (now <= tom) true + do check "ffcenonoiwe94" (tom > now) true + do check "ffcenonoiwe95" (now >= now) true + do check "ffcenonoiwe96" (tom >= now) true + do check "ffcenonoiwe97" (compare now now) 0 + do check "ffcenonoiwe98" (compare now tom) -1 + do check "ffcenonoiwe99" (compare tom now) 1 + do check "ffcenonoiwe9a" (max tom tom) tom + do check "ffcenonoiwe9b" (max tom now) tom + do check "ffcenonoiwe9c" (max now tom) tom + do check "ffcenonoiwe9d" (min tom tom) tom + do check "ffcenonoiwe9e" (min tom now) now + do check "ffcenonoiwe9f" (min now tom) now + + do check "ffcenonoiwe97a1" (ComparisonIdentity.NonStructural.Compare (1, 1)) 0 + do check "ffcenonoiwe98b2" (ComparisonIdentity.NonStructural.Compare (0, 1)) -1 + do check "ffcenonoiwe99c3" (ComparisonIdentity.NonStructural.Compare (1, 0)) 1 + + do check "ffcenonoiwe97a4" (ComparisonIdentity.NonStructural.Compare (now, now)) 0 + do check "ffcenonoiwe98b5" (ComparisonIdentity.NonStructural.Compare (now, tom)) -1 + do check "ffcenonoiwe99c6" (ComparisonIdentity.NonStructural.Compare (tom, now)) 1 + + do check "ffcenonoiwe97a7" (HashIdentity.NonStructural.Equals (now, now)) true + do check "ffcenonoiwe98b8" (HashIdentity.NonStructural.Equals (now, tom)) false + do check "ffcenonoiwe99c9" (HashIdentity.NonStructural.Equals (tom, now)) false + + do check "ffcenonoiwe97a7" (HashIdentity.NonStructural.GetHashCode now) (hash now) + do check "ffcenonoiwe97a7" (HashIdentity.NonStructural.GetHashCode tom) (hash tom) + do check "ffcenonoiwe97a7" (HashIdentity.NonStructural.GetHashCode 11) (hash 11) + do check "ffcenonoiwe97a7" (HashIdentity.NonStructural.GetHashCode 11L) (hash 11L) + do check "ffcenonoiwe97a7" (HashIdentity.NonStructural.GetHashCode 11UL) (hash 11UL) + + do check "ffcenonoiwe97aa" (HashIdentity.NonStructural.Equals (1, 1)) true + do check "ffcenonoiwe98bb" (HashIdentity.NonStructural.Equals (1, 0)) false + do check "ffcenonoiwe99cc" (HashIdentity.NonStructural.Equals (0, 1)) false + + +module NonStructuralComparisonOverTimeSpan = + open NonStructuralComparison + let now = System.TimeSpan.Zero + let tom = System.TimeSpan.FromDays 1.0 + do check "tscenonoiwe90" (now = tom) false + do check "tscenonoiwe9q" (now <> tom) true + do check "tscenonoiwe91" (now < tom) true + do check "tscenonoiwe92" (now <= now) true + do check "tscenonoiwe93" (now <= tom) true + do check "tscenonoiwe94" (tom > now) true + do check "tscenonoiwe95" (now >= now) true + do check "tscenonoiwe96" (tom >= now) true + do check "tscenonoiwe97" (compare now now) 0 + do check "tscenonoiwe98" (compare now tom) -1 + do check "tscenonoiwe99" (compare tom now) 1 + do check "tscenonoiwe9a" (max tom tom) tom + do check "tscenonoiwe9b" (max tom now) tom + do check "tscenonoiwe9c" (max now tom) tom + do check "tscenonoiwe9d" (min tom tom) tom + do check "tscenonoiwe9e" (min tom now) now + do check "tscenonoiwe9f" (min now tom) now + + +// Check you can use the operators without opening the module by naming them +module NonStructuralComparisonOverTimeSpanDirect = + let now = System.TimeSpan.Zero + let tom = System.TimeSpan.FromDays 1.0 + do check "tscenonoiwe90" (NonStructuralComparison.(=) now tom) false + do check "tscenonoiwe9q" (NonStructuralComparison.(<>) now tom) true + do check "tscenonoiwe91" (NonStructuralComparison.(<) now tom) true + do check "tscenonoiwe92" (NonStructuralComparison.(<=) now now) true + do check "tscenonoiwe94" (NonStructuralComparison.(>) tom now) true + do check "tscenonoiwe95" (NonStructuralComparison.(>=) now now) true + do check "tscenonoiwe97" (NonStructuralComparison.compare now now) 0 + do check "tscenonoiwe9a" (NonStructuralComparison.max tom now) tom + do check "tscenonoiwe9e" (NonStructuralComparison.min tom now) now + + do check "ffcenonoiwe97a7" (NonStructuralComparison.hash now) (Operators.hash now) + do check "ffcenonoiwe97a7" (NonStructuralComparison.hash tom) (Operators.hash tom) + do check "ffcenonoiwe97a7" (NonStructuralComparison.hash 11) (Operators.hash 11) + do check "ffcenonoiwe97a7" (NonStructuralComparison.hash 11L) (Operators.hash 11L) + do check "ffcenonoiwe97a7" (NonStructuralComparison.hash 11UL) (Operators.hash 11UL) (*--------------------------------------------------------------------------- !* Bug 1029: Support conversion functions named after C# type names? e.g. uint for uint32 diff --git a/tests/fsharp/core/queriesLeafExpressionConvert/test.fsx b/tests/fsharp/core/queriesLeafExpressionConvert/test.fsx index 5947fd02c1c..6b04b318f65 100644 --- a/tests/fsharp/core/queriesLeafExpressionConvert/test.fsx +++ b/tests/fsharp/core/queriesLeafExpressionConvert/test.fsx @@ -86,6 +86,33 @@ module LeafExpressionEvaluationTests = let _ = 1 checkEval "2ver9ewve" (<@ () @>) () + check "2ver9ewvr1" (Eval <@ (fun x -> NonStructuralComparison.(>) x 1) @> 3) true + check "2ver9ewvr1" (Eval <@ (fun x -> NonStructuralComparison.(>) x 4) @> 3) false + check "2ver9ewvr1" (Eval <@ (fun x -> NonStructuralComparison.(>) x 3) @> 3) false + + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<) x 1) @> 3) false + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<) x 3) @> 3) false + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<) x 4) @> 3) true + + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(>=) x 1) @> 3) true + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(>=) x 3) @> 3) true + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(>=) x 4) @> 3) false + + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<=) x 1) @> 3) false + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<=) x 3) @> 3) true + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<=) x 4) @> 3) true + + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(=) x 3) @> 3) true + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(=) x 4) @> 3) false + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(=) x 1) @> 3) false + + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<>) x 4) @> 3) true + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<>) x 3) @> 3) false + check "2ver9ewvr2" (Eval <@ (fun x -> NonStructuralComparison.(<>) x 1) @> 3) true + + check "2ver9ewvr" (Eval <@ (fun x -> x + 1) @> (3)) 4 + check "2ver9ewvr" (Eval <@ (fun x -> x + 1) @> (3)) 4 + check "2ver9ewvr" (Eval <@ (fun x -> x + 1) @> (3)) 4 check "2ver9ewvr" (Eval <@ (fun x -> x + 1) @> (3)) 4 check "2ver9ewvt" (Eval <@ (fun (x,y) -> x + 1) @> (3,4)) 4 check "2ver9ewvy" (Eval <@ (fun (x1,x2,x3) -> x1 + x2 + x3) @> (3,4,5)) (3+4+5)