rspeele / TaskBuilder.fs

F# computation expression builder for System.Threading.Tasks

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Code is not sufficiently generic

NinoFloris opened this issue · comments

Was porting an old project (netcoreapp2.2) to 3.1 today, noticed something that did compile back then that doesn't anymore.

This code is not sufficiently generic. The type variable ^TEntity when ^TEntity : not struct could not be generalized because it would escape its scope

Note the compiler inferred an SRTP type var ^TEntity here even though no SRTP constraints are used.

open FSharp.Control.Tasks.V2.ContextInsensitive
open Microsoft.EntityFrameworkCore

type DbSet<'TEntity when 'TEntity: not struct> with
    member this.TryFindAsync(keyValues) = task {
        let! r = this.FindAsync(keyValues)
        if obj.ReferenceEquals(r, null) then return ValueNone
        else return ValueSome r
    }

What seems to have happened here is EF moving from returning Task<'T> in 2.x to ValueTask<'T> in 3.x that caused this error to surface.

I've produced a minimal repro

open FSharp.Control.Tasks.V2.ContextInsensitive

type Foo<'T> =
    member this.FindAsync() = ValueTask<_>(Unchecked.defaultof<'T>)
    member this.TryFindAsync() = task {
        let! r = this.FindAsync()
        if obj.ReferenceEquals(r, null) then return ValueNone
        else return ValueSome r
    }

My hunch is something is iffy around the SRTP based 'tasklike' Bind as ValueTask isn't directly supported.

Also, adding inline to the new member TryFindAsync to potentially flow the SRTP var doesn't work either and returns a different error:

The signature and implementation are not compatible because the type parameter in the class/signature has a different compile-time requirement to the one in the member/implementation

Finally to confirm my hunch I tried this code in Ply under netstandard2.0, where Ply has no explicit ValueTask overloads, only similar tasklike support, and under netcoreapp2.2 (which does have the overloads) both compile without errors. Something is going wrong with the SRTP constrained overloads in Taskbuilder.

/cc: @gusty