Skip to content

Commit 0f7179a

Browse files
committed
Quotation tests
1 parent ea7adb3 commit 0f7179a

File tree

1 file changed

+121
-1
lines changed

1 file changed

+121
-1
lines changed

tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Quotations/FSharpQuotations.fs

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace FSharp.Core.UnitTests.Quotations
66

77
open System
8+
open FSharp.Core.UnitTests
9+
open FSharp.Core.UnitTests.Collections
810
open FSharp.Core.UnitTests.LibraryTestFx
911
open Xunit
1012
open FSharp.Quotations
@@ -139,4 +141,122 @@ type FSharpQuotationsTests() =
139141
let expr = Expr.NewTuple [ <@@ 1 @@>; <@@ "" @@> ]
140142
match expr with
141143
| NewStructTuple _ -> Assert.Fail()
142-
| _ -> ()
144+
| _ -> ()
145+
146+
/// This fixture is here to test handling of EqualityConditionalOn and ComparisonConditionalOn.
147+
/// We don't generate witnesses for equality and comparison if they're conditional; the tests
148+
/// assert that code gen doesn't fail in those cases.
149+
[<RequireQualifiedAccess>]
150+
module TestConditionalConstraints =
151+
open FSharp.Linq.RuntimeHelpers
152+
153+
let eval q = LeafExpressionConverter.EvaluateQuotation q
154+
155+
type DiscriminatedUnionWithGeneric<'a> =
156+
| Case of 'a
157+
158+
[<NoComparison>]
159+
type ThingWithNoComparison =
160+
| NoComparison
161+
162+
[<NoEquality ; NoComparison>]
163+
type ThingWithNoEquality =
164+
| NoEquality
165+
166+
override this.ToString () =
167+
"NoEquality"
168+
169+
let inline compare< ^T when ^T : comparison> (x : ^T) (y : ^T) : bool =
170+
x < y
171+
172+
let inline equate< ^T when ^T : equality> (x : ^T) (y : ^T) : bool =
173+
x = y
174+
175+
[<Fact>]
176+
let ``SRTP quotations can consume conditionally constrained types `` () =
177+
// Just normal calls, no quotation
178+
Assert.False (equate (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 4))
179+
Assert.True (equate (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 3))
180+
Assert.True (compare (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 4))
181+
182+
// Typed quotation, int
183+
<@ equate (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 4) @>
184+
|> eval
185+
|> unbox<bool>
186+
|> Assert.False
187+
188+
<@ equate (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 3) @>
189+
|> eval
190+
|> unbox<bool>
191+
|> Assert.True
192+
193+
<@ compare (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 4) @>
194+
|> eval
195+
|> unbox<bool>
196+
|> Assert.True
197+
198+
// Untyped quotation, int
199+
<@@ equate (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 4) @@>
200+
|> eval
201+
|> unbox<bool>
202+
|> Assert.False
203+
204+
<@@ equate (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 3) @@>
205+
|> eval
206+
|> unbox<bool>
207+
|> Assert.True
208+
209+
<@@ compare (DiscriminatedUnionWithGeneric.Case 3) (DiscriminatedUnionWithGeneric.Case 4) @@>
210+
|> eval
211+
|> unbox<bool>
212+
|> Assert.True
213+
214+
// Typed and untyped quotation, ThingWithNoComparison
215+
<@ equate ThingWithNoComparison.NoComparison ThingWithNoComparison.NoComparison @>
216+
|> eval
217+
|> unbox<bool>
218+
|> Assert.True
219+
220+
<@@ equate ThingWithNoComparison.NoComparison ThingWithNoComparison.NoComparison @@>
221+
|> eval
222+
|> unbox<bool>
223+
|> Assert.True
224+
225+
// Typed and untyped quotation, ThingWithNoEquality
226+
<@ (fun x -> x.ToString ()) ThingWithNoEquality.NoEquality @>
227+
|> eval
228+
|> unbox<string>
229+
|> fun s -> Assert.AreEqual (s, "NoEquality")
230+
231+
<@@ (fun x -> x.ToString ()) ThingWithNoEquality.NoEquality @@>
232+
|> eval
233+
|> unbox<string>
234+
|> fun s -> Assert.AreEqual (s, "NoEquality")
235+
236+
// This test isn't quotation-related, but it *is* closely related to the quotation test: both are checking
237+
// we can cope without witnesses.
238+
[<Fact>]
239+
let ``Reflective invocations of conditionally constrained types throw with a reasonable error`` () =
240+
let compare = typeof<ThingWithNoComparison>.DeclaringType.GetMethod "compare"
241+
let compare = compare.MakeGenericMethod([| typeof<ThingWithNoComparison> |])
242+
let exc =
243+
try
244+
compare.Invoke (null, [|ThingWithNoComparison.NoComparison ; ThingWithNoComparison.NoComparison|])
245+
|> ignore<obj>
246+
None
247+
with
248+
| exc ->
249+
Some exc
250+
251+
Assert.Contains ("does not implement the System.IComparable interface", exc.Value.InnerException.Message, StringComparison.Ordinal)
252+
253+
// This test isn't quotation-related, but it *is* closely related to the quotation test: both are checking
254+
// we can cope without witnesses.
255+
[<Fact>]
256+
let ``We still use Object.ReferenceEquals for non-equatable methods when reflectively invoked`` () =
257+
let equate = typeof<ThingWithNoComparison>.DeclaringType.GetMethod "equate"
258+
let equate = equate.MakeGenericMethod([| typeof<ThingWithNoEquality> |])
259+
let anotherOne = Activator.CreateInstance (typeof<ThingWithNoEquality>, nonPublic=true)
260+
equate.Invoke (null, [| ThingWithNoEquality.NoEquality ; anotherOne |])
261+
|> unbox<bool>
262+
|> Assert.False

0 commit comments

Comments
 (0)