Skip to content

Weird value returned after (maybe failed) overload resolution #155

@gusty

Description

@gusty

This bug is not about taking the wrong overload, which is an ongoing problem not easy to solve, but about returning a value not corresponding to any of the overloads.

I'm under the impression that overload resolution fails and then some buggy code returns a no sense value instead of a compile error.

Here's a repro


open System

type Default6 = class end
type Default5 = class inherit Default6 end
type Default4 = class inherit Default5 end
type Default3 = class inherit Default4 end
type Default2 = class inherit Default3 end
type Default1 = class inherit Default2 end

type [<Struct>]Result2<'T, 'E> = Ok2 of OkField:'T | Error2 of ErrorField:'E

type Bind =
    static member (>>=) (source: Lazy<'T>   , f: 'T -> Lazy<'U>    ) = lazy (f source.Value).Value    : Lazy<'U>
    static member (>>=) (source: seq<'T>    , f: 'T -> seq<'U>     ) = Seq.collect f source           : seq<'U>
    static member (>>=) (source             , f: 'T -> _           ) = Option.bind   f source         : option<'U>
    static member (>>=) (source             , f: 'T -> _           ) = List.collect  f source         : list<'U>
    static member (>>=) (source             , f: 'T -> _           ) = Array.collect f source         : 'U []
    static member (>>=) (source             , f: 'T -> _           ) = async.Bind (source, f)         : Async<'U>
    static member (>>=) (source             , k: 'T -> _           ) = Result.bind k source           : Result<'U,'E>
    static member (>>=) (source: Result2<'T,'E>   , k: 'T -> Result2<'U,'E>) = Unchecked.defaultof<_> : Result2<'U,'E>

    static member inline Invoke (source: '``Monad<'T>``) (binder: 'T -> '``Monad<'U>``) : '``Monad<'U>`` =
        let inline call (_mthd: 'M, input: 'I, _output: 'R, f) = ((^M or ^I or ^R) : (static member (>>=) : _*_ -> _) input, f)
        call (Unchecked.defaultof<Bind>, source, Unchecked.defaultof<'``Monad<'U>``>, binder)


type Return =
    inherit Default1

    static member inline InvokeOnInstance (x: 'T) = (^``Applicative<'T>`` : (static member Return : ^T -> ^``Applicative<'T>``) x)

    static member inline Invoke (x: 'T) : '``Applicative<'T>`` =
        let inline call (mthd: ^M, output: ^R) = ((^M or ^R) : (static member Return : _*_ -> _) output, mthd)
        call (Unchecked.defaultof<Return>, Unchecked.defaultof<'``Applicative<'T>``>) x    

    static member        Return (_: seq<'a>        , _: Default2) = fun  x      -> Seq.singleton x : seq<'a>
    static member inline Return (_: 'R             , _: Default1) = fun (x: 'T) -> Return.InvokeOnInstance x      : 'R
    static member        Return (_: Lazy<'a>       , _: Return  ) = fun x -> Lazy<_>.CreateFromValue x : Lazy<'a>
    static member        Return (_: option<'a>     , _: Return  ) = fun x -> Some x                               : option<'a>
    static member        Return (_: list<'a>       , _: Return  ) = fun x -> [ x ]                                : list<'a>
    static member        Return (_: 'a []          , _: Return  ) = fun x -> [|x|]                                : 'a []
    static member        Return (_: 'a Async       , _: Return  ) = fun (x: 'a) -> async.Return x
    static member        Return (_: Result<'a,'e>  , _: Return  ) = fun x -> Ok x                                 : Result<'a,'e> 
    static member        Return (_: ResizeArray<'a>, _: Return  ) = fun x -> ResizeArray<'a> (Seq.singleton x)


type Delay =
    inherit Default1

    static member inline Delay (_mthd: Default3, x: unit-> ^``Monad<'T>`` when ^``Monad<'T>`` : struct     , _: Default2) = Bind.Invoke (Return.Invoke ()) x : ^``Monad<'T>``
    static member inline Delay (_mthd: Default4, x: unit-> ^``Monad<'T>`` when ^``Monad<'T>`` : not struct , _: Default1) = Bind.Invoke (Return.Invoke ()) x : ^``Monad<'T>``

    static member        Delay (_mthd: Default2, x: unit-> _                                              , _          ) = Seq.delay x      : seq<'T>
    static member        Delay (_mthd: Default2, x: unit-> 'R -> _                                        , _          ) = (fun s -> x () s): 'R -> _

    static member inline Invoke (source : unit -> '``Monad<'T>``) : '``Monad<'T>`` =
        let inline call (mthd: ^M, input: unit -> ^I) = ((^M or ^I) : (static member Delay : _*_*_ -> _) mthd, input, Unchecked.defaultof<Delay>)
        call (Unchecked.defaultof<Delay>, source)


let res = Delay.Invoke (fun () -> [5] )
printfn "res is %A" res

Running this prints res is [object Object], but if we comment out the first overload of Delay, we get res is [5] which is the expected result.

Not sure, but it seems to be a problem when there are constraints in the overload, like not struct.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions