| | | 1 | | namespace FSharp.Interop.Dlr |
| | | 2 | | |
| | | 3 | | open System |
| | | 4 | | open System.Linq.Expressions |
| | | 5 | | open FSharp.Quotations |
| | | 6 | | open FSharp.Quotations.Patterns |
| | | 7 | | open FSharp.Quotations.DerivedPatterns |
| | | 8 | | open FSharp.Quotations.ExprShape |
| | | 9 | | open FSharp.Reflection |
| | | 10 | | open Microsoft.FSharp.Linq.RuntimeHelpers |
| | | 11 | | open System.Runtime.CompilerServices |
| | | 12 | | |
| | | 13 | | module internal TranslateMembers = |
| | | 14 | | open TranslatePatterns |
| | | 15 | | open SiteHoisting |
| | | 16 | | open TranslateBlock |
| | | 17 | | |
| | | 18 | | /// The marker operations: a literal name is a baked site; a computed name or runtime type |
| | | 19 | | /// arguments bind per key through a SiteCache. |
| | | 20 | | module Members = |
| | | 21 | | |
| | | 22 | | let private targetArg (rewriteIn: Rewrite) bound (target: Expr) = |
| | 9684 | 23 | | match target with |
| | 116 | 24 | | | StaticTarget t -> Binders.staticTarget t |
| | | 25 | | | _ -> |
| | 9568 | 26 | | let t = rewriteIn bound target |
| | 28704 | 27 | | Binders.dynamicArg (if t.Type = typeof<obj> then t else Expr.Coerce(t, typeof<obj>)) |
| | | 28 | | |
| | | 29 | | let private valueArg (rewriteIn: Rewrite) bound (value: Expr) = |
| | 5108 | 30 | | match value with |
| | 3253 | 31 | | | Value _ -> Binders.constant (Binders.typedArg value) |
| | | 32 | | // A unit-valued expression (a void call, `ignore x`) as a value: run, then `()`. |
| | 1859 | 33 | | | _ when value.Type = typeof<unit> -> Binders.typedArg (Expr.Sequential(rewriteIn bound value, Expr.Value(() |
| | 1851 | 34 | | | _ -> Binders.typedArg (rewriteIn bound value) |
| | | 35 | | |
| | | 36 | | let private argList (rewriteIn: Rewrite) bound (argExprs: Expr list) = |
| | 3200 | 37 | | let bindings = ResizeArray() |
| | 3200 | 38 | | let args = |
| | 9288 | 39 | | [ for a in argExprs do |
| | 4383 | 40 | | match a with |
| | 4 | 41 | | | TypeArgs _ -> unsupported "Dlr.typeArgs anywhere but as the first argument of a member call (a val |
| | 0 | 42 | | | NamedOf _ | ArgsOf _ -> unsupported "Dlr.namedOf / Dlr.argsOf here (they go in the arguments of a |
| | 0 | 43 | | | OutMarker _ | RefMarker _ -> unsupported "Dlr.out / Dlr.outAs / Dlr.ref here: they go directly in |
| | 3200 | 44 | | | NamedRecord(lets, fields) -> |
| | 66 | 45 | | bindings.AddRange lets |
| | 99 | 46 | | let inner = bindings |> Seq.fold (fun (b: Set<Var>) (v, _) -> b.Add v) bound |
| | 382 | 47 | | for (name, v) in fields -> Binders.named name (valueArg rewriteIn inner v) |
| | 3200 | 48 | | // Argument positions are generic-typed, so a `Coerce(_, obj)` here is the user's |
| | 3200 | 49 | | // `x :> obj` and means what `box x` means: an obj argument, runtime dispatch. |
| | 6040 | 50 | | | v -> yield valueArg rewriteIn bound v ] |
| | 3178 | 51 | | List.ofSeq bindings, args |
| | | 52 | | |
| | | 53 | | let private bind (rewriteIn: Rewrite) bound (bindings: (Var * Expr) list) (call: Expr) = |
| | 7947 | 54 | | List.foldBack (fun (v, value) body -> Expr.Let(v, rewriteIn bound value, body)) bindings call |
| | | 55 | | |
| | 894 | 56 | | let private indexList (rewriteIn: Rewrite) bound (indexes: Expr list) = [ for i in indexes -> valueArg rewriteIn |
| | | 57 | | |
| | | 58 | | let private finish (block: Block) discard (resultType: Type) (call: Expr) = |
| | 3406 | 59 | | if discard then call else block.Convert resultType call |
| | | 60 | | |
| | | 61 | | /// A call with `Dlr.out` / `Dlr.ref` arguments (#131). The outs come back as F# returns a |
| | | 62 | | /// method's out parameters: the result is a tuple of the return value then each out in |
| | | 63 | | /// order, or — when the result has no slot for the return value, which is then discarded — |
| | | 64 | | /// the outs alone (the bare value for one); each out's type is its element of the result |
| | | 65 | | /// type. A ref's value is read from its `let mutable` at the call, after every other argument |
| | | 66 | | /// (the callers bind those in order: `sequenced`), and the method's write is assigned back. |
| | | 67 | | /// Through `Binders.ByRefSite`, whose holder `makeCall` returns and is unpacked here. |
| | | 68 | | let private byRefCall (rewriteIn: Rewrite) bound (argExprs: Expr list) (resultType: Type) (convertReturn: Type - |
| | | 69 | | // Each out's stated type (`Dlr.outAs<'T>`), or None to take it from the result's shape. |
| | 4683 | 70 | | let stated = argExprs |> List.choose (function OutMarker t -> Some t | _ -> None) |
| | 1298 | 71 | | let outCount = stated.Length |
| | | 72 | | let shapeError () = |
| | 20 | 73 | | raise (DlrTranslationException(sprintf "dlr { } does not support a call with %d Dlr.out argument(s) whos |
| | 4072 | 74 | | let agrees (outTypes: Type list) = List.forall2 (fun s t -> match s with Some s -> s = t | None -> true) sta |
| | | 75 | | // The shapes in order, the first that agrees with the stated types: the return value then |
| | | 76 | | // the outs; the outs alone (two or more); the one out's bare value — for a tuple-typed |
| | | 77 | | // result only when Dlr.outAs states that type, so a plain Dlr.out keeps a mismatched |
| | | 78 | | // tuple a shape error (the analyzer's too). A reference or a struct tuple: `let struct |
| | | 79 | | // (ok, v) = …` allocates no tuple. |
| | | 80 | | let returnType, outTypes = |
| | 1472 | 81 | | if outCount = 0 then (if resultType = typeof<unit> then None else Some resultType), [] |
| | 1244 | 82 | | elif resultType = typeof<unit> then shapeError () |
| | | 83 | | else |
| | 1232 | 84 | | let elements = if FSharpType.IsTuple resultType then List.ofArray (FSharpType.GetTupleElements resul |
| | 2414 | 85 | | if elements.Length = outCount + 1 && agrees elements.Tail then Some elements.Head, elements.Tail |
| | 84 | 86 | | elif outCount >= 2 && elements.Length = outCount && agrees elements then None, elements |
| | 110 | 87 | | elif outCount = 1 && (elements.IsEmpty || stated = [ Some resultType ]) && agrees [ resultType ] the |
| | 8 | 88 | | else shapeError () |
| | 1278 | 89 | | let pendingOuts = System.Collections.Generic.Queue<Type>(outTypes) |
| | | 90 | | // Per byref argument, in order: an out's type, or a ref's place (its type and how to |
| | | 91 | | // write it back). |
| | 1278 | 92 | | let byRefs = ResizeArray<Choice<Type, Type * (Expr -> Expr)>>() |
| | 1278 | 93 | | let namedBindings = ResizeArray<Var * Expr>() |
| | 1278 | 94 | | let args = |
| | 5246 | 95 | | [ for a in argExprs do |
| | 4043 | 96 | | match a with |
| | 1278 | 97 | | | OutMarker _ -> |
| | 1396 | 98 | | let t = pendingOuts.Dequeue() |
| | 1396 | 99 | | byRefs.Add(Choice1Of2 t) |
| | 1396 | 100 | | yield Binders.byRefArg true t (Expr.Value(null, typeof<obj>)) null |
| | 62 | 101 | | | RefMarker(Var v) when v.IsMutable -> |
| | 124 | 102 | | byRefs.Add(Choice2Of2(v.Type, fun value -> Expr.VarSet(v, value))) |
| | 62 | 103 | | yield Binders.byRefArg false v.Type (rewriteIn bound (Expr.Var v)) (box v) |
| | 1278 | 104 | | // A `let mutable` a closure captures is a ref cell by the time it is quoted. |
| | 645 | 105 | | | RefMarker(PropertyGet(Some(Var cell as cellExpr), p, [])) when cell.Type.IsGenericType && cell.Typ |
| | 645 | 106 | | byRefs.Add(Choice2Of2(p.PropertyType, fun value -> Expr.PropertySet(cellExpr, p, value))) |
| | 643 | 107 | | yield Binders.byRefArg false p.PropertyType (rewriteIn bound (Expr.PropertyGet(cellExpr, p))) (b |
| | 643 | 108 | | | RefMarker other -> unsupported "Dlr.ref of anything but a let mutable (its value goes in, and the |
| | 1278 | 109 | | // Named arguments, as `argList` takes them: the record's field temporaries |
| | 1278 | 110 | | // wrap the call, in source order. |
| | 1278 | 111 | | | NamedRecord(lets, fields) -> |
| | 651 | 112 | | namedBindings.AddRange lets |
| | 661 | 113 | | let inner = namedBindings |> Seq.fold (fun (b: Set<Var>) (v, _) -> b.Add v) bound |
| | 703 | 114 | | for (name, v) in fields -> Binders.named name (valueArg rewriteIn inner v) |
| | 643 | 115 | | | NamedOf _ | ArgsOf _ -> unsupported "Dlr.namedOf / Dlr.argsOf in a call with Dlr.out, Dlr.outAs or |
| | 641 | 116 | | | TypeArgs _ -> unsupported "Dlr.typeArgs anywhere but as the first argument of a member call" a |
| | 1880 | 117 | | | v -> yield valueArg rewriteIn bound v ] |
| | 1270 | 118 | | let call = makeCall returnType.IsNone args |
| | | 119 | | // The holder (Binders.byRefHolderType): the result as obj, then each byref's value, typed. |
| | 1270 | 120 | | let results = Var("byRefResults", call.Type) |
| | 6730 | 121 | | let at (i: int) = Binders.byRefHolderPath call.Type i |> List.fold (fun (e: Expr) f -> Expr.FieldGet(e, f)) |
| | 1270 | 122 | | let bound' = Set.add results bound |
| | 1270 | 123 | | let writeBacks = |
| | 3998 | 124 | | [ for i, b in Seq.indexed byRefs do |
| | 2185 | 125 | | match b with |
| | 66 | 126 | | | Choice2Of2(_, write) -> yield rewriteIn bound' (write (at (i + 1))) |
| | 1964 | 127 | | | Choice1Of2 _ -> () ] |
| | 8878 | 128 | | let outValues = [ for i, b in Seq.indexed byRefs do match b with Choice1Of2 _ -> yield at (i + 1) | Choice2O |
| | | 129 | | // The result tuple, of the result type's kind: a struct one is the ValueTuple constructor. |
| | 2376 | 130 | | let newTuple (values: Expr list) = if resultType.IsValueType then Tuples.newQuotation resultType values else |
| | | 131 | | let value = |
| | 1270 | 132 | | match returnType, outValues with |
| | 32 | 133 | | | None, [] -> Expr.Value(()) |
| | 22 | 134 | | | Some t, [] -> convertReturn t (at 0) |
| | 1172 | 135 | | | Some t, outs -> newTuple (convertReturn t (at 0) :: outs) |
| | 28 | 136 | | | None, [ single ] -> single |
| | 16 | 137 | | | None, outs -> newTuple outs |
| | 1336 | 138 | | let body = List.foldBack (fun w rest -> Expr.Sequential(w, rest)) writeBacks value |
| | 1270 | 139 | | List.foldBack (fun (v, value) body -> Expr.Let(v, rewriteIn bound value, body)) (List.ofSeq namedBindings) ( |
| | | 140 | | |
| | | 141 | | /// The tuple bindings of `splitArgs`, added to the bound set for the argument rewrites. |
| | | 142 | | let private withTuple (bound: Set<Var>) (tupleBindings: (Var * Expr) list) = |
| | 2933 | 143 | | tupleBindings |> List.fold (fun (b: Set<Var>) (v, _) -> b.Add v) bound |
| | | 144 | | |
| | | 145 | | /// The name and the type arguments of a keyed site, each either static (a constant in the |
| | | 146 | | /// key) or an expression evaluated per call in the scope the site is emitted in. |
| | | 147 | | type KeySpec = Choice<string, Expr> * Choice<Type list, Expr> |
| | | 148 | | |
| | | 149 | | /// A delegate over `parameters` returning obj, compiled once per site: a `Func<…>` while |
| | | 150 | | /// its arity allows; past that the delegate type would be emitted at run time, which a |
| | | 151 | | /// quotation must not name (see `Binders.WideSite`), so it is a `Func<obj[], obj>` over the |
| | | 152 | | /// parameters packed (`packArguments` at the call) and unpacked to their types inside. |
| | 7928 | 153 | | let private isWide (parameters: Var list) = not (DelegateMembers.funcFits parameters.Length) |
| | | 154 | | let private delegateTypeOver (parameters: Var list) = |
| | 3972 | 155 | | if isWide parameters then typeof<Func<obj[], obj>> |
| | 29136 | 156 | | else Expression.GetDelegateType(Array.ofList ([ for v in parameters -> v.Type ] @ [ typeof<obj> ])) |
| | | 157 | | let private lambdaOver (parameters: Var list) (body: Expr) = |
| | 5038 | 158 | | if not (isWide parameters) then Expr.NewDelegate(delegateTypeOver parameters, parameters, body) |
| | | 159 | | else |
| | 16 | 160 | | let packed = Var("packed", typeof<obj[]>) |
| | 16 | 161 | | let atArg = typeof<NamedOfCache>.GetMethod("At") |
| | 16 | 162 | | let unpacked = |
| | 16 | 163 | | List.foldBack (fun (i, v: Var) (inner: Expr) -> |
| | 272 | 164 | | let element = Expr.Call(atArg, [ Expr.Var packed; Expr.Value i ]) |
| | 816 | 165 | | Expr.Let(v, (if v.Type = typeof<obj> then element else Expr.Coerce(element, v.Type)), inner)) |
| | 16 | 166 | | (List.indexed parameters) body |
| | 16 | 167 | | Expr.NewDelegate(typeof<Func<obj[], obj>>, [ packed ], unpacked) |
| | | 168 | | let private packArguments (parameters: Var list) (arguments: Expr list) = |
| | 2874 | 169 | | if not (isWide parameters) then arguments |
| | 592 | 170 | | else [ Expr.NewArray(typeof<obj>, [ for a in arguments -> if a.Type = typeof<obj> then a else Expr.Coerce(a, |
| | | 171 | | |
| | | 172 | | /// An operation whose binder inputs — the member name, the type arguments, or both — are |
| | | 173 | | /// only known at run time: the operation's delegate is compiled once here with its call |
| | | 174 | | /// sites as parameters (lifted from a template built for a placeholder key), and a |
| | | 175 | | /// SiteCache constant creates the sites per distinct `(name, types)` key; the emitted |
| | | 176 | | /// code is `let sites = cache.Get((name, types)) in delegate.Invoke(sites.[0], …, target, args…)`. |
| | | 177 | | /// Argument names in `Dlr.named` stay static. This is the core over prepared arguments; |
| | | 178 | | /// the name and type expressions must be valid where the result is placed. |
| | | 179 | | let private keyedSiteTyped (key: KeySpec) (targetInfo: Binders.Arg) (argInfos: Binders.Arg list) (site: string - |
| | 1257 | 180 | | let targetVar = Var("target", targetInfo.Type) |
| | | 181 | | // A byref argument (`Dlr.out` / `Dlr.ref`) is passed as its value: a quotation variable cannot be a byref. |
| | 3028 | 182 | | let argVars = argInfos |> List.mapi (fun i a -> Var(sprintf "a%d" i, (if a.Type.IsByRef then a.Expr.Type els |
| | | 183 | | let template (name: string, types: Type list) = |
| | 5451 | 184 | | let args = List.map2 (fun (info: Binders.Arg) (v: Var) -> { info with Expr = Expr.Var v }) argInfos argV |
| | 4557 | 185 | | site name types { targetInfo with Expr = Expr.Var targetVar } args |
| | | 186 | | // The operation's shape does not depend on the key, only its sites do: build it once |
| | | 187 | | // for a placeholder, lift every site constant into a parameter, and compile that one |
| | | 188 | | // delegate now. Per key, the cache creates the sites and hands them back in the |
| | | 189 | | // same order. |
| | | 190 | | let placeholderName, nameE = |
| | 1257 | 191 | | match fst key with |
| | 40 | 192 | | | Choice1Of2 name -> name, Expr.Value name |
| | 1217 | 193 | | | Choice2Of2 e -> "name", e |
| | | 194 | | let placeholderTypes, typesE = |
| | 1257 | 195 | | match snd key with |
| | 1213 | 196 | | | Choice1Of2 ts -> ts, Expr.Value(ts, typeof<Type list>) |
| | 44 | 197 | | | Choice2Of2 e -> [], e |
| | 1257 | 198 | | let placeholder = template (placeholderName, placeholderTypes) |
| | 1257 | 199 | | let sites = SiteCache<string * Type list>.Sites placeholder |
| | | 200 | | // A wide site's type names an emitted delegate type: keep it out of the quotation (see |
| | | 201 | | // `Binders.WideSite`) by typing the parameter as the base `CallSite`. |
| | 7108 | 202 | | let siteVars = sites |> List.mapi (fun i s -> s, Var(sprintf "site%d" i, (let t = s.GetType() in if t.GetGen |
| | | 203 | | let rec lift (e: Expr) = |
| | 7089 | 204 | | match e with |
| | 2674 | 205 | | | Value(v, _) when (v :? CallSite) -> |
| | 7796 | 206 | | match siteVars |> List.tryFind (fun (s, _) -> obj.ReferenceEquals(s, v)) with |
| | 2542 | 207 | | | Some(_, var) -> Expr.Var var |
| | 0 | 208 | | | None -> e |
| | 4547 | 209 | | | _ -> Quotation.rebuild lift e |
| | 1257 | 210 | | let body = lift placeholder |
| | | 211 | | // A discarded result is a void site: the delegate still returns obj, so hand back null. |
| | | 212 | | let boxed = |
| | 2466 | 213 | | if body.Type = typeof<obj> then body |
| | 144 | 214 | | elif body.Type = typeof<unit> || body.Type = typeof<Void> then Expr.Sequential(body, Expr.Value(null, ty |
| | 40 | 215 | | else Expr.Coerce(body, typeof<obj>) |
| | 6381 | 216 | | let parameters = [ for _, v in siteVars -> v ] @ targetVar :: argVars |
| | 1257 | 217 | | let cache = SiteCache<string * Type list>(template) |
| | 1257 | 218 | | let cacheType = typeof<SiteCache<string * Type list>> |
| | 1257 | 219 | | let sitesVar = Var("sites", typeof<CallSite[]>) |
| | 1257 | 220 | | let at = cacheType.GetMethod("At") |
| | 3193 | 221 | | let siteArgs = siteVars |> List.mapi (fun i (_, v) -> Expr.Coerce(Expr.Call(at, [ Expr.Var sitesVar; Expr.Va |
| | 4151 | 222 | | let arguments = siteArgs @ targetInfo.Expr :: [ for a in argInfos -> a.Expr ] |
| | 1257 | 223 | | let siteDelegate = delegateTypeOver parameters |
| | | 224 | | // Through the hoister like every compiled tree: a wide site's placeholder in the template |
| | | 225 | | // is rewritten there (its site arrives as a parameter, which the rewrite converts). |
| | 1257 | 226 | | let linq = LeafExpressionConverter.QuotationToExpression (lambdaOver parameters boxed) :?> LambdaExpression |
| | 1257 | 227 | | let compiled = (SiteHoister().Visit linq :?> LambdaExpression).Compile() |
| | 1257 | 228 | | let invocation = Expr.Call(Expr.Value(compiled, siteDelegate), siteDelegate.GetMethod("Invoke"), packArgumen |
| | 1257 | 229 | | Expr.Let(sitesVar, Expr.Call(Expr.Value(cache, cacheType), cacheType.GetMethod("Get"), [ Expr.NewTuple [ nam |
| | 1257 | 230 | | placeholder.Type |
| | | 231 | | |
| | | 232 | | /// The keyed call, boxed to `obj` whatever the operation's own type. |
| | 24 | 233 | | let private keyedSiteRaw key targetInfo argInfos site : Expr = fst (keyedSiteTyped key targetInfo argInfos site) |
| | | 234 | | |
| | | 235 | | /// `keyedSiteRaw`'s call converted to `resultType`: cast back where the operation already is |
| | | 236 | | /// of that type (a member read as a function or delegate type), converted otherwise (a |
| | | 237 | | /// call's result, which may be a delegate typed as a function or back, #207). |
| | | 238 | | let private keyedSiteCore (block: Block) (key: KeySpec) (targetInfo: Binders.Arg) (argInfos: Binders.Arg list) ( |
| | 1233 | 239 | | let call, operationType = keyedSiteTyped key targetInfo argInfos site |
| | 2466 | 240 | | if operationType = resultType then Expr.Coerce(call, resultType) else block.Convert resultType call |
| | | 241 | | |
| | | 242 | | /// The key of a computed name / run-time type arguments, its expressions rewritten in |
| | | 243 | | /// the block's scope. |
| | | 244 | | let private keySpec (rewriteIn: Rewrite) bound (nameExpr: Expr) (typeArgs: TypeArgsSpec) : KeySpec = |
| | 3735 | 245 | | (match nameExpr with Literal name -> Choice1Of2(string name) | e -> Choice2Of2(rewriteIn bound e)), |
| | 3735 | 246 | | (match typeArgs with StaticTypes ts -> Choice1Of2 ts | RuntimeTypes e -> Choice2Of2(rewriteIn bound e)) |
| | | 247 | | |
| | | 248 | | /// `keyedSiteCore` over argument expressions, in the block's scope. |
| | | 249 | | let private keyedSite (block: Block) (rewriteIn: Rewrite) bound (nameExpr: Expr) (typeArgs: TypeArgsSpec) (targe |
| | 1195 | 250 | | let bindings, argInfos = argList rewriteIn bound argExprs |
| | 1195 | 251 | | keyedSiteCore block (keySpec rewriteIn bound nameExpr typeArgs) (targetArg rewriteIn bound target) argInfos |
| | 1195 | 252 | | |> bind rewriteIn bound bindings |
| | | 253 | | |
| | | 254 | | /// An invocation whose arguments include `Dlr.namedOf pairs`: the operation is compiled |
| | | 255 | | /// per distinct name list — the names decide the site's arity, so the whole delegate is |
| | | 256 | | /// per key — through a bounded `NamedOfCache` constant, taking the target, the fixed |
| | | 257 | | /// arguments and the named values (`obj`, dispatched on runtime type). `operation` builds |
| | | 258 | | /// the site expression for a target and its full argument list. `None` when there is no |
| | | 259 | | /// `namedOf` in `argExprs`. With a computed member name / run-time type arguments |
| | | 260 | | /// (`key`), their expressions are evaluated in the block's scope and passed into the |
| | | 261 | | /// per-name-list delegate as parameters, where `operation` gets them for a `keyedSiteCore`. |
| | | 262 | | let private namedOfCallKeyed (block: Block) (rewriteIn: Rewrite) bound (target: Expr) (argExprs: Expr list) (res |
| | 1451 | 263 | | let namedOfs = argExprs |> List.choose (function NamedOf pairs -> Some pairs | _ -> None) |
| | 1451 | 264 | | let argsOfs = argExprs |> List.choose (function ArgsOf values -> Some values | _ -> None) |
| | 1213 | 265 | | if namedOfs.IsEmpty && argsOfs.IsEmpty then None |
| | | 266 | | else |
| | 98 | 267 | | if namedOfs.Length > 1 then unsupported "more than one Dlr.namedOf in one call (concatenate the lists)" |
| | 100 | 268 | | if argsOfs.Length > 1 then unsupported "more than one Dlr.argsOf in one call (concatenate the lists)" ar |
| | | 269 | | // Named arguments are the call's trailing ones (the binder's CallInfo names the |
| | | 270 | | // last arguments), so nothing positional may follow Dlr.namedOf. |
| | 474 | 271 | | (match argExprs |> List.tryFindIndex (function NamedOf _ -> true | _ -> false) with |
| | 146 | 272 | | | Some i when argExprs |> List.skip (i + 1) |> List.exists (function NamedRecord _ -> false | _ -> true |
| | 2 | 273 | | unsupported "a positional argument after Dlr.namedOf (named arguments come last)" argExprs.[i] |
| | 94 | 274 | | | _ -> ()) |
| | 188 | 275 | | let pairsExpr = match namedOfs with [ p ] -> p | _ -> Expr.Value(([]: (string * obj) list), typeof<(stri |
| | 188 | 276 | | let positionalExpr = match argsOfs with [ p ] -> p | _ -> Expr.Value(([]: obj list), typeof<obj list>) |
| | | 277 | | /// The argument list's layout: fixed arguments by index, the positional splat, the |
| | | 278 | | /// named splat — so the compiled call keeps the source order. |
| | | 279 | | let layout = |
| | 94 | 280 | | let mutable next = 0 |
| | 188 | 281 | | argExprs |> List.choose (fun a -> |
| | 184 | 282 | | match a with |
| | 46 | 283 | | | NamedOf _ -> Some(Choice3Of3 ()) |
| | 55 | 284 | | | ArgsOf _ -> Some(Choice2Of3 ()) |
| | 343 | 285 | | | _ -> (let i = next in next <- next + 1; Some(Choice1Of3 i))) |
| | 372 | 286 | | let fixedExprs = argExprs |> List.filter (fun a -> not (isSplat a)) |
| | 94 | 287 | | let bindings, fixedInfos = argList rewriteIn bound fixedExprs |
| | 94 | 288 | | let targetInfo = targetArg rewriteIn bound target |
| | 94 | 289 | | let targetVar = Var("target", targetInfo.Type) |
| | 271 | 290 | | let fixedVars = fixedInfos |> List.mapi (fun i a -> Var(sprintf "a%d" i, a.Type)) |
| | 94 | 291 | | let valuesVar = Var("values", typeof<obj[]>) |
| | 94 | 292 | | let at = typeof<NamedOfCache>.GetMethod("At") |
| | | 293 | | // A computed name / run-time type list are evaluated out here and passed in as |
| | | 294 | | // parameters: the delegate does not see the block's scope. |
| | | 295 | | let keyVars, keyExprs, innerKey = |
| | 94 | 296 | | match key with |
| | 81 | 297 | | | None -> [], [], None |
| | | 298 | | | Some(name, types) -> |
| | 50 | 299 | | let nameVar, nameE = (match name with Choice1Of2 n -> None, Choice1Of2 n | Choice2Of2 e -> (let |
| | 41 | 300 | | let typesVar, typesE = (match types with Choice1Of2 ts -> None, Choice1Of2 ts | Choice2Of2 e -> |
| | 26 | 301 | | let vars = [ nameVar; typesVar ] |> List.choose id |
| | 13 | 302 | | List.map fst vars, List.map snd vars, Some((nameE, typesE): KeySpec) |
| | | 303 | | // One delegate type for every key at this site: the names change the sites inside, |
| | | 304 | | // not the parameters, so the call is a typed Invoke, not DynamicInvoke. |
| | 94 | 305 | | let parameters = targetVar :: fixedVars @ keyVars @ [ valuesVar ] |
| | 94 | 306 | | let siteDelegate = delegateTypeOver parameters |
| | | 307 | | let compile (names: string list) : Delegate = |
| | 721 | 308 | | let fixed' = List.map2 (fun (info: Binders.Arg) (v: Var) -> { info with Expr = Expr.Var v }) fixedIn |
| | | 309 | | // `fixedInfos` are grouped per source argument (a Dlr.named record is several): |
| | | 310 | | // walk the fixed expressions again to know how many each contributed. |
| | | 311 | | let fixedGroups = |
| | 1442 | 312 | | let counted = fixedExprs |> List.map (fun a -> match a with NamedRecord(_, fields) -> fields.Len |
| | 635 | 313 | | let mutable offset = 0 |
| | 2335 | 314 | | [ for n in counted -> (let g = List.take n (List.skip offset fixed') in offset <- offset + n; g) |
| | 2124 | 315 | | let value i = Binders.dynamicArg (Expr.Call(at, [ Expr.Var valuesVar; Expr.Value i ])) |
| | 2939 | 316 | | let positionalCount = names |> List.takeWhile (fun n -> n.Length = 0) |> List.length |
| | 2671 | 317 | | let positional = [ for i in 0 .. positionalCount - 1 -> value i ] |
| | 2500 | 318 | | let named = names |> List.skip positionalCount |> List.mapi (fun j name -> Binders.named name (value |
| | | 319 | | let args = |
| | 1270 | 320 | | layout |> List.collect (function |
| | 86 | 321 | | | Choice1Of3 i -> fixedGroups.[i] |
| | 67 | 322 | | | Choice2Of3 () -> positional |
| | 1212 | 323 | | | Choice3Of3 () -> named) |
| | 635 | 324 | | let body = operation (defaultArg innerKey (Choice1Of2 "", Choice1Of2 [])) { targetInfo with Expr = E |
| | | 325 | | let boxed = |
| | 1266 | 326 | | if body.Type = typeof<obj> then body |
| | 12 | 327 | | elif body.Type = typeof<unit> || body.Type = typeof<Void> then Expr.Sequential(body, Expr.Value( |
| | 4 | 328 | | else Expr.Coerce(body, typeof<obj>) |
| | 635 | 329 | | let linq = LeafExpressionConverter.QuotationToExpression (lambdaOver parameters boxed) :?> LambdaExp |
| | 635 | 330 | | (SiteHoister().Visit linq :?> LambdaExpression).Compile() |
| | 94 | 331 | | let cache = NamedOfCache(compile) |
| | 94 | 332 | | let cacheType = typeof<NamedOfCache> |
| | 94 | 333 | | let pairsVar = Var("pairs", typeof<(string * obj) list>) |
| | 94 | 334 | | let positionalVar = Var("positional", typeof<obj list>) |
| | 94 | 335 | | let delegateVar = Var("d", siteDelegate) |
| | 94 | 336 | | let values = Expr.Call(cacheType.GetMethod("Values"), [ Expr.Var positionalVar; Expr.Var pairsVar ]) |
| | 94 | 337 | | let call = |
| | 94 | 338 | | Expr.Let(positionalVar, rewriteIn bound positionalExpr, |
| | 94 | 339 | | Expr.Let(pairsVar, rewriteIn bound pairsExpr, |
| | 94 | 340 | | Expr.Let(delegateVar, Expr.Coerce(Expr.Call(Expr.Value(cache, cacheType), cacheType.GetMethod("G |
| | 365 | 341 | | Expr.Call(Expr.Var delegateVar, siteDelegate.GetMethod("Invoke"), packArguments parameters ( |
| | 282 | 342 | | (if discard then Expr.Sequential(call, Expr.Value(())) else block.Convert resultType call) |
| | 94 | 343 | | |> bind rewriteIn bound bindings |
| | 94 | 344 | | |> Some |
| | | 345 | | |
| | | 346 | | /// An invocation whose arguments include `Dlr.namedOf pairs`, with a literal member name. |
| | | 347 | | let private namedOfCall (block: Block) (rewriteIn: Rewrite) bound (target: Expr) (argExprs: Expr list) (resultTy |
| | 1636 | 348 | | namedOfCallKeyed block rewriteIn bound target argExprs resultType discard None (fun _ t args -> operation t |
| | | 349 | | |
| | | 350 | | /// An expression typed as a delegate type a member can be read as (#201), with the function |
| | | 351 | | /// type its invoker takes past fourteen parameters (`Binders.delegateRead`). |
| | 2855 | 352 | | let private (|DelegateRead|_|) (e: Expr) = Binders.delegateRead e.Type |
| | | 353 | | |
| | | 354 | | /// `(?) x name` with a computed name (no type arguments): see keyedSite. |
| | | 355 | | let private computedName block rewriteIn bound (nameExpr: Expr) (target: Expr) (argExprs: Expr list) (resultType |
| | 5368 | 356 | | keyedSite block rewriteIn bound nameExpr (StaticTypes []) target argExprs resultType (fun name _ targetArg a |
| | | 357 | | |
| | | 358 | | /// `Dlr.addAssign`/`subtractAssign`: bind the target and value once, then both branches |
| | | 359 | | /// of the IsEvent decision refer to them. A computed name goes through the SiteCache |
| | | 360 | | /// like any other member operation. |
| | | 361 | | let private compoundAssign (block: Block) (rewriteIn: Rewrite) bound (subtract: bool) (nameExpr: Expr) (target: |
| | 94 | 362 | | match nameExpr with |
| | | 363 | | | Literal name -> |
| | 45 | 364 | | let targetInfo = targetArg rewriteIn bound target |
| | 45 | 365 | | let v = rewriteIn bound value |
| | 45 | 366 | | let tv = Var("target", targetInfo.Type) |
| | 45 | 367 | | let vv = Var("value", v.Type) |
| | | 368 | | // A literal value keeps C#'s constant conversions (a byte member += 1) even though |
| | | 369 | | // it is read through a variable here. |
| | | 370 | | let valueArg = |
| | 45 | 371 | | let a = Binders.typedArg (Expr.Var vv) |
| | 45 | 372 | | match value with |
| | 14 | 373 | | | Value _ -> Binders.constant a |
| | 31 | 374 | | | _ -> a |
| | 45 | 375 | | let body = Binders.compoundAssign block.Context (string name) subtract { targetInfo with Expr = Expr.Var |
| | 43 | 376 | | Expr.Let(tv, targetInfo.Expr, Expr.Let(vv, v, body)) |
| | | 377 | | | _ -> |
| | 4 | 378 | | computedName block rewriteIn bound nameExpr target [ value ] typeof<unit> (fun name targetArg args -> |
| | 4 | 379 | | // The name-cache template already makes target and value delegate parameters. |
| | 16 | 380 | | Expr.Sequential(Binders.compoundAssign block.Context name subtract targetArg (List.head args), Expr. |
| | | 381 | | |
| | | 382 | | /// The expression, if it is a marker operation. |
| | | 383 | | let tryOperation (block: Block) (rewriteIn: Rewrite) (bound: Set<Var>) (e: Expr) : Expr option = |
| | 140947 | 384 | | let context = block.Context |
| | 140947 | 385 | | let convert = block.Convert |
| | 140947 | 386 | | let rewrite = rewriteIn bound |
| | 70045 | 387 | | let targetArg = targetArg rewriteIn |
| | 70045 | 388 | | let valueArg = valueArg rewriteIn |
| | 70045 | 389 | | let argList = argList rewriteIn |
| | 70045 | 390 | | let bind = bind rewriteIn |
| | 70045 | 391 | | let indexList = indexList rewriteIn |
| | 70045 | 392 | | let finish = finish block |
| | 70045 | 393 | | let computedName = computedName block rewriteIn bound |
| | 140947 | 394 | | match e with |
| | 4596 | 395 | | | MemberOp(InvokeMember(target, nameExpr, argExpr)) when (snd (splitArgs argExpr)) |> List.exists isByRefMar |
| | 609 | 396 | | let tupleBindings, argExprs = splitArgs argExpr |
| | 609 | 397 | | if not tupleBindings.IsEmpty then unsupported "Dlr.out / Dlr.outAs / Dlr.ref in a tuple held in a variab |
| | | 398 | | let typeArgs, argExprs = |
| | 609 | 399 | | match argExprs with |
| | 6 | 400 | | | TypeArgs spec :: rest -> spec, rest |
| | 603 | 401 | | | args -> StaticTypes [], args |
| | | 402 | | // C#'s order, always: the target, a computed name / type list, then the arguments, |
| | | 403 | | // each impure one bound in turn (a Dlr.named record's temporaries at its place). |
| | 3654 | 404 | | let keys = [ (match nameExpr with Literal _ -> None | k -> Some k); (match typeArgs with RuntimeTypes k |
| | 609 | 405 | | let bindings, vars, target', keys', argExprs' = sequenced (Some target) keys [] argExprs |
| | 609 | 406 | | let bound' = Set.union bound vars |
| | 1827 | 407 | | let nameExpr', keys' = (match nameExpr with Literal _ -> nameExpr, keys' | _ -> List.head keys', List.ta |
| | 1827 | 408 | | let typeArgs' = (match typeArgs with RuntimeTypes _ -> RuntimeTypes(List.head keys') | t -> t) |
| | 609 | 409 | | let targetInfo = targetArg bound' target'.Value |
| | | 410 | | let makeCall = |
| | 609 | 411 | | match nameExpr', typeArgs' with |
| | 583 | 412 | | | Literal name, StaticTypes ts -> fun discard args -> Binders.invokeMemberByRef context (string name |
| | | 413 | | // A computed name or run-time type arguments: a site per key, as for any member |
| | | 414 | | // call; the holder comes back as it is, for byRefCall to unpack. |
| | | 415 | | | _ -> |
| | 12 | 416 | | let key = keySpec rewriteIn bound' nameExpr' typeArgs' |
| | | 417 | | fun discard args -> |
| | 12 | 418 | | let holder = Binders.byRefHolderOf (targetInfo :: args) |
| | 36 | 419 | | Expr.Coerce(keyedSiteRaw key targetInfo args (fun name ts t a -> Binders.invokeMemberByRef c |
| | 1799 | 420 | | byRefCall rewriteIn bound' argExprs' e.Type convert makeCall |> bind bound bindings |> Some |
| | | 421 | | | MemberOp(InvokeMember(target, nameExpr, argExpr)) -> |
| | 924 | 422 | | let tupleBindings, argExprs = splitArgs argExpr |
| | | 423 | | let typeArgs, argExprs = |
| | 924 | 424 | | match argExprs with |
| | 38 | 425 | | | TypeArgs spec :: rest -> spec, rest |
| | 886 | 426 | | | args -> StaticTypes [], args |
| | | 427 | | // A computed name / type list is evaluated by the keyed site ahead of the call, |
| | | 428 | | // so it too is sequenced when impure. |
| | 5544 | 429 | | let keys = [ (match nameExpr with Literal _ -> None | k -> Some k); (match typeArgs with RuntimeTypes k |
| | 2571 | 430 | | let ordered = hoists tupleBindings argExprs || keys |> List.exists (fun k -> not (isPure k)) |
| | | 431 | | let bindings, bound', target, nameExpr, typeArgs, argExprs = |
| | 920 | 432 | | if ordered then |
| | 126 | 433 | | let bindings, vars, target', keys', argExprs' = sequenced (Some target) keys tupleBindings argEx |
| | 378 | 434 | | let nameExpr', keys' = (match nameExpr with Literal _ -> nameExpr, keys' | _ -> List.head keys', |
| | 378 | 435 | | let typeArgs' = (match typeArgs with RuntimeTypes _ -> RuntimeTypes(List.head keys') | t -> t) |
| | 126 | 436 | | bindings, Set.union bound vars, target'.Value, nameExpr', typeArgs', argExprs' |
| | 794 | 437 | | else tupleBindings, withTuple bound tupleBindings, target, nameExpr, typeArgs, argExprs |
| | 920 | 438 | | let discard = e.Type = typeof<unit> |
| | 1840 | 439 | | let hasNamedOf = argExprs |> List.exists isSplat |
| | 1840 | 440 | | match nameExpr, typeArgs with |
| | 868 | 441 | | | Literal name, StaticTypes ts when hasNamedOf -> |
| | 677 | 442 | | (namedOfCall block rewriteIn bound' target argExprs e.Type discard (fun t args -> Binders.invokeMemb |
| | | 443 | | | Literal name, StaticTypes ts -> |
| | 795 | 444 | | let argBindings, args = argList bound' argExprs |
| | 2373 | 445 | | Binders.invokeMemberOrApply context (string name) ts discard (targetArg bound' target) args |> finis |
| | 52 | 446 | | | _ when hasNamedOf -> |
| | 13 | 447 | | (namedOfCallKeyed block rewriteIn bound' target argExprs e.Type discard (Some(keySpec rewriteIn boun |
| | 74 | 448 | | keyedSiteCore block key t args typeof<obj> (fun name ts targetArg args -> Binders.invokeMemberOr |
| | | 449 | | | _ -> |
| | 39 | 450 | | keyedSite block rewriteIn bound' nameExpr typeArgs target argExprs e.Type (fun name ts targetArg arg |
| | 126 | 451 | | Binders.invokeMemberOrApply context name ts discard targetArg args) |
| | 912 | 452 | | |> bind bound bindings |
| | 912 | 453 | | |> Some |
| | 2977 | 454 | | | MemberOp(GetMember(target, nameExpr)) when FSharpType.IsFunction e.Type -> |
| | | 455 | | // Read as an F# function: a curried invoker of the member (method, delegate or F# |
| | | 456 | | // function), so `let f: int -> int -> int = dlr { return x?Add }` then `f 1 2`. |
| | 244 | 457 | | match nameExpr with |
| | 118 | 458 | | | Literal name -> Binders.functionMember context (string name) e.Type (targetArg bound target) |
| | 12 | 459 | | | _ -> computedName nameExpr target [] e.Type (fun name targetArg _ -> Binders.functionMember context na |
| | 120 | 460 | | |> Some |
| | | 461 | | | MemberOp(GetMember(target, nameExpr)) & DelegateRead functionType -> |
| | | 462 | | // Read as a delegate type (#201): the member's value, or an invoker of it when it |
| | | 463 | | // is a method, so `Api.Fold(dlr { return x?Add })` passes `Add` as the `Func`. |
| | 156 | 464 | | match nameExpr with |
| | 74 | 465 | | | Literal name -> Binders.delegateMember context (string name) e.Type functionType (targetArg bound targ |
| | 12 | 466 | | | _ -> computedName nameExpr target [] e.Type (fun name targetArg _ -> Binders.delegateMember context na |
| | 78 | 467 | | |> Some |
| | | 468 | | | MemberOp(GetMember(target, nameExpr)) -> |
| | 5554 | 469 | | match nameExpr with |
| | 4454 | 470 | | | Literal name -> Binders.getMember context (string name) (targetArg bound target) |> convert e.Type |
| | 2651 | 471 | | | _ -> computedName nameExpr target [] e.Type (fun name targetArg _ -> Binders.getMember context name ta |
| | 2775 | 472 | | |> Some |
| | 65567 | 473 | | | Op opAddAssign [ nameExpr; Unboxed value; Unboxed target ] -> Some(compoundAssign block rewriteIn bound fa |
| | 65518 | 474 | | | Op opSubtractAssign [ nameExpr; Unboxed value; Unboxed target ] -> Some(compoundAssign block rewriteIn bou |
| | | 475 | | | MemberOp(SetMember(target, nameExpr, value)) -> |
| | 160 | 476 | | match nameExpr with |
| | 154 | 477 | | | Literal name -> Binders.setMember context (string name) (targetArg bound target) (valueArg bound value |
| | | 478 | | | _ -> |
| | 2 | 479 | | computedName nameExpr target [ value ] typeof<unit> (fun name targetArg args -> |
| | 6 | 480 | | Binders.setMember context name targetArg (List.head args)) |
| | 78 | 481 | | |> Some |
| | 186 | 482 | | | New(_, argExprs) when argExprs |> List.exists (function OutMarker _ -> true | _ -> false) -> |
| | 2 | 483 | | unsupported "Dlr.out / Dlr.outAs in Dlr.new': its result is the constructed T, with no room for an out v |
| | 104 | 484 | | | New(t, argExprs) when argExprs |> List.exists isByRefMarker -> |
| | | 485 | | // The site's result is `T` itself (see below): the return value unboxes to it. |
| | 8 | 486 | | let convertReturn (rt: Type) (e: Expr) = if rt = t then Expr.Call(unboxTo.MakeGenericMethod t, [ e ]) el |
| | 4 | 487 | | let bindings, vars, _, _, argExprs' = sequenced None [] [] argExprs |
| | 8 | 488 | | byRefCall rewriteIn (Set.union bound vars) argExprs' e.Type convertReturn (fun _ args -> Binders.invokeC |
| | 8 | 489 | | |> bind bound bindings |> Some |
| | | 490 | | | New(t, argExprs) -> |
| | | 491 | | // The site is typed `T` itself (the binder types a constructor's result as `T`, |
| | | 492 | | // which an obj-typed site rejects for a struct), so no Convert. One argument of a |
| | | 493 | | // tuple type is several, as for a member call: F# picks the one-argument overload |
| | | 494 | | // for `Dlr.new'<T> args` and coerces the tuple. |
| | | 495 | | let tupleBindings, argExprs = |
| | 48 | 496 | | match argExprs with |
| | 30 | 497 | | | [ single ] -> splitArgs single |
| | 18 | 498 | | | many -> [], many |
| | | 499 | | let bindings, bound', argExprs = |
| | 48 | 500 | | if hoists tupleBindings argExprs then |
| | 10 | 501 | | let bindings, vars, _, _, argExprs' = sequenced None [] tupleBindings argExprs |
| | 10 | 502 | | bindings, Set.union bound vars, argExprs' |
| | 38 | 503 | | else tupleBindings, withTuple bound tupleBindings, argExprs |
| | 52 | 504 | | match namedOfCall block rewriteIn bound' (Expr.Value(null, typeof<obj>)) argExprs e.Type false (fun _ ar |
| | 12 | 505 | | | Some call -> call |> bind bound bindings |> Some |
| | | 506 | | | None -> |
| | 44 | 507 | | let argBindings, args = argList bound' argExprs |
| | 176 | 508 | | Binders.invokeConstructor context t args |> bind bound' argBindings |> bind bound bindings |> Some |
| | | 509 | | // The value's `?`: applied, a call; read at a function type, the target as that function. |
| | 334 | 510 | | | Application(EtaReduced(Op opCall [ Unboxed target ]), argExpr) |
| | 65556 | 511 | | | Op opApply [ argExpr; Unboxed target ] when (snd (splitArgs argExpr)) |> List.exists isByRefMarker -> |
| | 34 | 512 | | let tupleBindings, argExprs = splitArgs argExpr |
| | 34 | 513 | | if not tupleBindings.IsEmpty then unsupported "Dlr.out / Dlr.outAs / Dlr.ref in a tuple held in a variab |
| | 34 | 514 | | let bindings, vars, target', _, argExprs' = sequenced (Some target) [] [] argExprs |
| | 34 | 515 | | let bound' = Set.union bound vars |
| | 34 | 516 | | let targetInfo = targetArg bound' target'.Value |
| | 68 | 517 | | byRefCall rewriteIn bound' argExprs' e.Type convert (fun discard args -> Binders.invokeByRef context dis |
| | 68 | 518 | | |> bind bound bindings |> Some |
| | 306 | 519 | | | Application(EtaReduced(Op opCall [ Unboxed target ]), argExpr) |
| | 65304 | 520 | | | Op opApply [ argExpr; Unboxed target ] -> |
| | 81 | 521 | | let discard = e.Type = typeof<unit> |
| | 81 | 522 | | let tupleBindings, argExprs = splitArgs argExpr |
| | | 523 | | let bindings, bound', target, argExprs = |
| | 81 | 524 | | if hoists tupleBindings argExprs then |
| | 10 | 525 | | let bindings, vars, target', _, argExprs' = sequenced (Some target) [] tupleBindings argExprs |
| | 10 | 526 | | bindings, Set.union bound vars, target'.Value, argExprs' |
| | 71 | 527 | | else tupleBindings, withTuple bound tupleBindings, target, argExprs |
| | 89 | 528 | | match namedOfCall block rewriteIn bound' target argExprs e.Type discard (fun t args -> Binders.invokeOrA |
| | 24 | 529 | | | Some call -> call |> bind bound bindings |> Some |
| | | 530 | | | None -> |
| | 73 | 531 | | let argBindings, args = argList bound' argExprs |
| | 357 | 532 | | Binders.invokeOrApply context discard (targetArg bound' target) args |> finish discard e.Type |> bin |
| | 65265 | 533 | | | Op opCall [ Unboxed target ] when FSharpType.IsFunction e.Type -> |
| | 48 | 534 | | Binders.functionTarget context e.Type (targetArg bound target) |> Some |
| | 65215 | 535 | | | Op opCall [ _ ] -> |
| | 2 | 536 | | unsupported "Dlr.call read at a non-function type (a value read as a type is Dlr.implicit; to invoke, ap |
| | 65213 | 537 | | | Op opItem [ indexes; Unboxed target ] -> |
| | 45 | 538 | | let tupleBindings, indexExprs = splitArgs indexes |
| | 45 | 539 | | let bound' = withTuple bound tupleBindings |
| | 168 | 540 | | Binders.getIndex context (targetArg bound target) (indexList bound' indexExprs) |> convert e.Type |> bin |
| | 65168 | 541 | | | Op opSetItem [ indexes; value; Unboxed target ] -> |
| | 32 | 542 | | let tupleBindings, indexExprs = splitArgs indexes |
| | 32 | 543 | | let bound' = withTuple bound tupleBindings |
| | 128 | 544 | | Binders.setIndex context (targetArg bound target) (indexList bound' indexExprs) (valueArg bound' value) |
| | | 545 | | | BinaryOp(op, Unboxed left, Unboxed right) -> |
| | 357 | 546 | | Binders.binaryOperation context op (valueArg bound left) (valueArg bound right) |> convert e.Type |> Som |
| | | 547 | | | UnaryOp(op, Unboxed operand) -> |
| | 30 | 548 | | Binders.unaryOperation context op (valueArg bound operand) |> convert e.Type |> Some |
| | 65007 | 549 | | | Op opCast [ Unboxed value ] -> |
| | 13 | 550 | | let v = rewrite value |
| | 52 | 551 | | Binders.convertExplicit context e.Type (if v.Type = typeof<obj> then v else Expr.Coerce(v, typeof<obj>)) |
| | 64994 | 552 | | | Op opImplicit [ Unboxed value ] -> |
| | 52 | 553 | | let v = rewrite value |
| | 208 | 554 | | convert e.Type (if v.Type = typeof<obj> then v else Expr.Coerce(v, typeof<obj>)) |> Some |
| | | 555 | | // The marker anywhere but as a target would run its getter at run time and throw the |
| | | 556 | | // outside-a-block error from inside one; say what is wrong instead. Likewise an |
| | | 557 | | // argument marker anywhere but in a call's argument list (those were consumed above). |
| | 4 | 558 | | | StaticTarget _ -> unsupported "Dlr.Static<T>.Overloads anywhere but as the target of a call" e |
| | 64942 | 559 | | | Op opNamed _ -> unsupported "Dlr.named anywhere but as an argument of a call (a member call, Dlr.invoke, D |
| | 64936 | 560 | | | Op opNamedOf _ -> unsupported "Dlr.namedOf anywhere but as an argument of a call (a member call, Dlr.invok |
| | 64932 | 561 | | | Op opArgsOf _ -> unsupported "Dlr.argsOf anywhere but as an argument of a call (a member call, Dlr.invoke, |
| | 2 | 562 | | | OutMarker _ | RefMarker _ -> unsupported "Dlr.out / Dlr.outAs / Dlr.ref anywhere but directly in the argum |
| | 0 | 563 | | | TypeArgs _ -> unsupported "Dlr.typeArgs anywhere but as the first argument of a member call" e |
| | 64930 | 564 | | | _ -> None |