Skip to content

VerificationException on runtime, due to upcast to obj inside the task state machine #16154

@Thorium

Description

@Thorium

There I was, minding my own business, of writing generic higher order functions in asynchronous code, when she hit me, the task-state-machine. She has hit me before, but this time I think she left some traces of her, so I could saw a glimpse of that monster. So I'll report it here, even this will probably be closed "as designed", it might help some other guy struggling in seduction by her.

I haven't been able to repro it in short code, yet, but this is what is going on.
Observe the following code:

open System.Linq
type Shape = {x: int; y: int}

let returnFilter condition =
    task {
        if condition = "a" then
            let filter1 : IQueryable<Shape> -> IQueryable<Shape> =
                fun data -> data.Where(fun a -> a.x = 1)
            return Some filter1
        elif condition = "b" then
            let filter2 : IQueryable<Shape> -> IQueryable<Shape> =
                fun data -> data.Where(fun a -> a.y <> 2)
            return Some filter2
        else
            return None
    }

...and then composing these filters back and forth, e.g.

    let data = [{x = 1; y = 1}; {x = 2; y = 2}].AsQueryable()
    task {
        let! getfilter1 = returnFilter "a"
        let! getfilter2 = returnFilter "b"
        match getfilter1, getfilter2 with
        | Some filter1, Some filter2 ->
            return data |> filter2 |> filter1 |> Seq.toList
        // ...and so on...

Expected behavior

Silly me, by the code I expected the type of returnFilter is:
string -> Task<(IQueryable<Shape> -> IQueryable<Shape>) option>

Actual behavior

Well, the actual type of returnFilter is:
string -> Task<(#IQueryable<Shape> -> IQueryable<Shape>) option>

The code compiled well.
But this hash # made all the difference, because combining different returnFilters together caused them to be automatically upcasted to obj.

Thus the code threw at runtime:

System.Security.VerificationException: Method returnFilter: type argument 'System.Object' violates the constraint of type parameter 'a'.
   at ...(my code location of "task{")...
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)

What I historically do is change the code from task to async and all is good, but not this time:

System.Security.VerificationException: Method returnFilter: type argument 'System.Object' violates the constraint of type parameter 'a'.
    at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](AsyncActivation`1 ctxt, TResult result1, FSharpFunc`2 part2) in D:\\a\\_work\\1\\s\\src\\FSharp.Core\\async.fs:line 510
   at ...(mycode)...
   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in D:\\a\\_work\\1\\s\\src\\FSharp.Core\\async.fs:line 114
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ...(mycode)...

Known workarounds

Do write the parameters explicitly.
You can even declare a type for your function:

type ShapeFilter = IQueryable<Shape> -> IQueryable<Shape>
let returnFilter condition : Task<Option<ShapeFilter>>=
   //... and now the compiler is happy, and the runtime is happy.

Related information

Provide any related information (optional):

  • Operating system Windows 11
  • .NET Runtime kind: dotnet 8.0.100-rc.1.23463.5, .NET 4.8.09032
  • Editing Tools Visual Studio 2022 Version 17.7.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-Compiler-StateMachinesSequence, list, task and other state machine compilationBugImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.Regression

    Type

    No fields configured for Bug.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions