Closed sergey-tihon closed 4 years ago
Looks like any use of for loops is failing because of #241
I still can reproduce it when I do
let toStr =
ProvidedMethod("ToString", [], typeof<string>, isStatic = false,
invokeCode = fun args ->
let this = args.[0]
let (pNames, pValues) =
Array.ofList members
|> Array.map (fun (pField, pProp) ->
let pValObj = Expr.FieldGet(this, pField)
pProp.Name, Expr.Coerce(pValObj, typeof<obj>)
)
|> Array.unzip
let pValuesArr = Expr.NewArray(typeof<obj>, List.ofArray pValues)
<@@
let values = (%%pValuesArr : array<obj>)
let rec formatValue (v:obj) =
if isNull v then "null"
else
let vTy = v.GetType()
if vTy = typeof<string>
then String.Format("\"{0}\"",v)
elif vTy.IsArray
then
let elements =
//(v :?> seq<_>) |> Seq.map formatValue
// !!! READ HERE
[| for x in (v :?> Collections.IEnumerable) do
yield formatValue x
|]
String.Format("[{0}]", String.Join("; ", elements))
else v.ToString()
let strs = values |> Array.mapi (fun i v ->
String.Format("{0}={1}",pNames.[i], formatValue v))
String.Format("{{{0}}}", String.Join("; ",strs))
@@>)
toStr.SetMethodAttrs(MethodAttributes.Public ||| MethodAttributes.Virtual)
let objToStr = (typeof<obj>).GetMethod("ToString",[||])
ty.DefineMethodOverride(toStr, objToStr)
ty.AddMember <| toStr
This code fails during dotnet build
(of proj that uses TP) with error
error FS3033: The type provider 'SwaggerProvider.SwaggerTypeProvider' reported an error: The method or operation is not implemented.
but when I replace
let elements =
// !!! READ HERE
[| for x in (v :?> Collections.IEnumerable) do
yield formatValue x
|]
by
let elements =
(v :?> seq<_>) |> Seq.map formatValue
it compile without errors
P.S. IIRC it worked before ...
A simple <@ a - b @>
doesn't work. Repro https://github.com/kevmal/tpsub
Test fails with the same Message: System.NotSupportedException : Specified method is not supported.
My quick fix ended up being adding to CodeGenerator
| Call (None,meth,[a1;a2]) when meth.DeclaringType.FullName = "Microsoft.FSharp.Core.Operators" ->
let emit op =
let t1 = a1.Type
emitExpr ExpectedStackState.Value a1
emitExpr ExpectedStackState.Value a2
let dec = (convTypeToTgt typeof<decimal>)
if t1 = dec then
let meth = dec.GetMethod meth.Name
ilg.Emit(I_call(Normalcall, transMeth meth, None))
else
ilg.Emit(op)
emitConvIfNecessary t1
popIfEmptyExpected expectedState
match meth.Name with
| "op_Subtraction" -> emit (I_sub)
| "op_Division" -> emit (I_div)
| "op_Modulus" -> emit (I_rem)
| _ -> emitCallExpr None meth [a1;a2]
| Call (objOpt,meth,args) -> emitCallExpr objOpt meth args
where emitCallExpr
was just the former Call
branch.
Formerly ProvidedTypes.fs had SpecificCall
branches like
| SpecificCall <@ (-) @>(None, [t1; t2; _], [a1; a2]) ->
assert(t1 = t2)
emitExpr ExpectedStackState.Value a1
emitExpr ExpectedStackState.Value a2
if t1 = typeof<decimal> then
ilg.Emit(OpCodes.Call, typeof<decimal>.GetMethod "op_Subtraction")
else
ilg.Emit(OpCodes.Sub)
emitConvIfNecessary t1
popIfEmptyExpected expectedState
Which are currently removed, this form would no longer work since it wont match "target" methods. Which raises the question if the SpecificCall
branches that are there (for GetArray
) are ever hit?
@sergey-tihon Try this again if you get a chance.
IL_0176: call !!2 [FSharp.Core]Microsoft.FSharp.Core.Operators::op_Subtraction
should be replaced with the appropriate IL.
Let's count it as solved for now.
Description
for
loop used in quotation compiles but fails at runtime with exceptionthe quotation is
Actual behavior
Error message on Mono is even less readable
Known workarounds
Rewrite loop using
Seq.iter
. Following code worksRelated information
More details are here -https://github.com/fsprojects/SwaggerProvider/pull/105#issuecomment-368220077
Generated code decompiled to
C#
IL
code of the loop