@@ -4,6 +4,7 @@ open Fable.Tests.Util
44open Util.Testing
55open Microsoft.FSharp .Quotations
66open Microsoft.FSharp .Quotations .Patterns
7+ open Microsoft.FSharp .Quotations .DerivedPatterns
78open Microsoft.FSharp .Linq .RuntimeHelpers
89
910type QuotationTestUnion =
@@ -12,6 +13,26 @@ type QuotationTestUnion =
1213
1314let inline quotTestDouble x = x * 2
1415
16+ // DerivedPatterns: AndAlso and OrElse recover the shape `&&` and `||` desugar
17+ // into, and SpecificCall matches a call by the identity of a template quotation
18+ // rather than by its compiled name. All three previously reported
19+ // "not supported by Fable".
20+ type private DpRec = { Country: string ; Balance: float ; Id: int }
21+
22+ let rec private dpToSql ( e : Expr ) : string =
23+ match e with
24+ | Lambda(_, body) -> dpToSql body
25+ | AndAlso( l, r) -> " (" + dpToSql l + " AND " + dpToSql r + " )"
26+ | OrElse( l, r) -> " (" + dpToSql l + " OR " + dpToSql r + " )"
27+ | SpecificCall <@ (=) @> (_, _, [ l; r ]) -> " (" + dpToSql l + " = " + dpToSql r + " )"
28+ | SpecificCall <@ (>) @> (_, _, [ l; r ]) -> " (" + dpToSql l + " > " + dpToSql r + " )"
29+ | SpecificCall <@ (<) @> (_, _, [ l; r ]) -> " (" + dpToSql l + " < " + dpToSql r + " )"
30+ // Bound as a wildcard: PropertyGet exposes a PropertyInfo on Rust but the
31+ // bare name on the other targets, and this test is about DerivedPatterns.
32+ | PropertyGet _ -> " col"
33+ | Value _ -> " ?"
34+ | _ -> " <unsupported>"
35+
1536[<Fact>]
1637let ``test Simple integer value quotation`` () =
1738 let q = <@ 42 @>
@@ -283,3 +304,35 @@ let ``test Call on an instance whose value is null keeps a Some instance`` () =
283304
284305 if not ( hasSomeInstancePropertyGet q) then
285306 failwith " Expected a PropertyGet with a Some instance, even though its value is null"
307+
308+ [<Fact>]
309+ let ``test DerivedPatterns AndAlso , OrElse and SpecificCall work`` () =
310+ dpToSql <@ fun ( c : DpRec ) -> c.Country = " UK" @> |> equal " (col = ?)"
311+
312+ dpToSql <@ fun ( c : DpRec ) -> c.Country = " UK" && c.Balance > 100.0 @>
313+ |> equal " ((col = ?) AND (col > ?))"
314+
315+ dpToSql <@ fun ( c : DpRec ) -> c.Id < 5 || c.Balance > 1.0 @>
316+ |> equal " ((col < ?) OR (col > ?))"
317+
318+ [<Fact>]
319+ let ``test a captured local is a Value , not a Var`` () =
320+ let captured = " SE"
321+
322+ let describe ( e : Expr ) =
323+ match e with
324+ | Lambda(_, body) ->
325+ match body with
326+ | Value( v, _) -> " Value:" + unbox< string> v
327+ | Var v -> " Var:" + v.Name
328+ | _ -> " other"
329+ | _ -> " not a lambda"
330+
331+ describe <@ fun ( _ : int ) -> captured @> |> equal " Value:SE"
332+ describe <@ fun ( _ : int ) -> " SE" @> |> equal " Value:SE"
333+
334+ // Checks that a bound variable remains a Var, rather than being spliced in.
335+ ( match <@ fun ( x : string ) -> x @> with
336+ | Lambda(_, Var _) -> " Var"
337+ | _ -> " ?" )
338+ |> equal " Var"
0 commit comments