Skip to content

cancellableTaskResult use! fails to resolve the correct overload #369

Description

@qrzychu

Describe the bug

When I try to use use! node = tryGetNode path, I get an error that there is no Bind for IDisposable (more or less)

To Reproduce

open System
open System.Threading
open System.Threading.Tasks
open FsToolkit.ErrorHandling

type Node(name: string) =
    member _.Name = name
    interface IDisposable with
        member _.Dispose() = printfn "disposed %s" name

let tryGetNode (path: string) : Task<Result<Node, string>> = Task.FromResult(Ok(new Node(path)))

// D: no member lookup inside -> shows which Using overload got committed
let caseD () =
    cancellableTaskResult {
        use! node = tryGetNode "d" // error here
        return 1
    }

printfn "D = %A" ((caseD () CancellationToken.None).Result)

Funnily enough, adding an annotation `use! (node : Node) = tryGetNode "d" ``` makes the error go away in Rider, but not in the compiler.

This:

        let! (node : Node) = tryGetNode "d"
        use _ = node
        return 1

work just fine (but requires the annotation), but I don't like the fact that I have to do this

Expected behavior

The above should just work

I am getting an error:

d.fsx(20,9): error FS0041: No overloads match for method 'Bind'.

Known types of arguments: Runtime.CompilerServices.TaskAwaiter<Result<Node,string>> * ('a -> CancellableTaskResultBuilderBaseCode<int,int,'b,^c>) when 'a :> IAsyncDisposable and ^c: (member AwaitUnsafeOnCompleted: byref<Runtime.CompilerServices.ICriticalNotifyCompletion> * byref<CompilerServices.ResumableStateMachine<CancellableTaskResultBuilderBaseStateMachineData<int,'b,^c>>> -> unit)

Available overloads:
 - member CancellableTaskResultBuilderBase.Bind: [<InlineIfLambda>] getAwaiterT: (CancellationToken -> ^Awaiter) * continuation: ('TResult1 -> CancellableTaskResultBuilderBaseCode<'TOverall,'TResult2,'Error,^Builder>) -> CancellableTaskResultBuilderBaseCode<'TOverall,'TResult2,'Error,^Builder> when ^Awaiter :> Runtime.CompilerServices.ICriticalNotifyCompletion and ^Awaiter: (member get_IsCompleted: unit -> bool) and ^Awaiter: (member GetResult: unit -> 'TResult1) and ^Builder: (member AwaitUnsafeOnCompleted: byref<Runtime.CompilerServices.ICriticalNotifyCompletion> * byref<CompilerServices.ResumableStateMachine<CancellableTaskResultBuilderBaseStateMachineData<'TOverall,'Error,^Builder>>> -> unit) // Argument 'getAwaiterT' doesn't match
 - member CancellableTaskResultBuilderBase.Bind: awaiterT: ^Awaiter * continuation: ('TResult1 -> CancellableTaskResultBuilderBaseCode<'TOverall,'TResult2,'Error,^Builder>) -> CancellableTaskResultBuilderBaseCode<'TOverall,'TResult2,'Error,^Builder> when ^Awaiter :> Runtime.CompilerServices.ICriticalNotifyCompletion and ^Awaiter: (member get_IsCompleted: unit -> bool) and ^Awaiter: (member GetResult: unit -> 'TResult1) and ^Builder: (member AwaitUnsafeOnCompleted: byref<Runtime.CompilerServices.ICriticalNotifyCompletion> * byref<CompilerServices.ResumableStateMachine<CancellableTaskResultBuilderBaseStateMachineData<'TOverall,'Error,^Builder>>> -> unit) // Argument 'continuation' doesn't match
 - member CancellableTaskResultBuilderBase.Bind<^Awaiter,'TResult1,'Error,'TOverall,'TResult2,^Builder when ^Awaiter :> Runtime.CompilerServices.ICriticalNotifyCompletion and ^Awaiter: (member get_IsCompleted: unit -> bool) and ^Awaiter: (member GetResult: unit -> Result<'TResult1,'Error>) and ^Builder: (member AwaitUnsafeOnCompleted: byref<Runtime.CompilerServices.ICriticalNotifyCompletion> * byref<CompilerServices.ResumableStateMachine<CancellableTaskResultBuilderBaseStateMachineData<'TOverall,'Error,^Builder>>> -> unit)> : [<InlineIfLambda>] getAwaiterTResult: (CancellationToken -> ^Awaiter) * continuation: ('TResult1 -> CancellableTaskResultBuilderBaseCode<'TOverall,'TResult2,'Error,^Builder>) -> CancellableTaskResultBuilderBaseCode<'TOverall,'TResult2,'Error,^Builder> when ^Awaiter :> Runtime.CompilerServices.ICriticalNotifyCompletion and ^Awaiter: (member get_IsCompleted: unit -> bool) and ^Awaiter: (member GetResult: unit -> Result<'TResult1,'Error>) and ^Builder: (member AwaitUnsafeOnCompleted: byref<Runtime.CompilerServices.ICriticalNotifyCompletion> * byref<CompilerServices.ResumableStateMachine<CancellableTaskResultBuilderBaseStateMachineData<'TOverall,'Error,^Builder>>> -> unit) // Argument 'getAwaiterTResult' doesn't match
 - member CancellableTaskResultBuilderBase.Bind<^Awaiter,'TResult1,'Error,'TOverall,'TResult2,^Builder when ^Awaiter :> Runtime.CompilerServices.ICriticalNotifyCompletion and ^Awaiter: (member get_IsCompleted: unit -> bool) and ^Awaiter: (member GetResult: unit -> Result<'TResult1,'Error>) and ^Builder: (member AwaitUnsafeOnCompleted: byref<Runtime.CompilerServices.ICriticalNotifyCompletion> * byref<CompilerServices.ResumableStateMachine<CancellableTaskResultBuilderBaseStateMachineData<'TOverall,'Error,^Builder>>> -> unit)> : awaiterTResult: ^Awaiter * continuation: ('TResult1 -> CancellableTaskResultBuilderBaseCode<'TOverall,'TResult2,'Error,^Builder>) -> CancellableTaskResultBuilderBaseCode<'TOverall,'TResult2,'Error,^Builder> when ^Awaiter :> Runtime.CompilerServices.ICriticalNotifyCompletion and ^Awaiter: (member get_IsCompleted: unit -> bool) and ^Awaiter: (member GetResult: unit -> Result<'TResult1,'Error>) and ^Builder: (member AwaitUnsafeOnCompleted: byref<Runtime.CompilerServices.ICriticalNotifyCompletion> * byref<CompilerServices.ResumableStateMachine<CancellableTaskResultBuilderBaseStateMachineData<'TOverall,'Error,^Builder>>> -> unit) // Argument 'continuation' doesn't match

I think this is because the IDisposable Using binding for the CE is an extension, not a proper member, and the compiler never reaches the extension resolution.

Is there anything that can be done here in my code or here in the library? or do we have to take it to the compiler people?

Once again, the best feature of F# (computation expressions!) is the worst feature of F#

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions