Open
Description
There are cases when using SRTP with overloads where a class that is not sealed is not resolved, when in fact the compiler has a good candidate.
Repro steps
Try this script
//[<Sealed>]
type Id<'t>(v:'t) = member __.getValue = v
type Interface<'t> = abstract member getValue : 't
type Monad =
static member inline InvokeReturn (x:'T) : '``Monad<'T>`` =
let inline call (mthd : ^M, output : ^R) = ((^M or ^R) : (static member Return: _ -> _) output)
call (Unchecked.defaultof<Monad>, Unchecked.defaultof<'``Monad<'T>``>) x
static member Return (_:Interface<'a>) = fun (_:'a) -> Unchecked.defaultof<Interface<'a>> : Interface<'a>
static member Return (_:seq<'a> ) = fun x -> Seq.singleton x : seq<'a>
static member Return (_:option<'a> ) = fun x -> Some x : option<'a>
static member Return (_:Id<'a> ) = fun x -> Id x : Id<'a>
static member inline InvokeBind (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 Bind: _*_ -> _) input, f)
call (Unchecked.defaultof<Monad>, source, Unchecked.defaultof<'``Monad<'U>``>, binder)
static member Bind (source : Interface<'T>, f : 'T -> Interface<'U>) = f source.getValue : Interface<'U>
static member Bind (source : seq<'T> , f : 'T -> seq<'U> ) = Seq.collect f source : seq<'U>
static member Bind (source : Id<'T> , f : 'T -> Id<'U> ) = f source.getValue : Id<'U>
static member Bind (source :option<'T> , f : 'T -> _ ) = Option.bind f source : option<'U>
let inline result (x:'T) = Monad.InvokeReturn x :'``Monad<'T>``
let inline (>>=) (x:'``Monad<'T>``) (f:'T->'``Monad<'U>``) = Monad.InvokeBind x f :'``Monad<'U>``
type ReaderT<'R,'``monad<'T>``> = ReaderT of ('R -> '``monad<'T>``)
let runReaderT (ReaderT x) = x : 'R -> '``Monad<'T>``
type ReaderT<'R,'``monad<'T>``> with
static member inline Return _ = fun (x : 'T) -> ReaderT (fun _ -> result x) : ReaderT<'R, '``Monad<'T>``>
static member inline Bind (ReaderT (m:_->'``Monad<'T>``), f:'T->_) = ReaderT (fun r -> m r >>= (fun a -> runReaderT (f a) r)) : ReaderT<'R, '``Monad<'U>``>
let test1 : ReaderT<string, option<_>> = ReaderT result >>= result
let test2 : ReaderT<string, Id<_>> = ReaderT result >>= result
let test3 : ReaderT<string, seq<_>> = ReaderT result >>= result
Expected behavior
Compile fine, inferring test1
, test2
, test3
Actual behavior
Only test1
is inferred, since it's an option
type (sealed).
Then we get this error:
error FS0332: Could not resolve the ambiguity inherent in the use of the operator 'Return' at or near this program point. Consider using type annotations to resolve the ambiguity.
Which doesn't add any useful information.
Known workarounds
Uncomment the first line and test2
will be inferred.
However for test3
there's no workaround without fixing the compiler.
Related information
I submitted a very easy fix for this issue
Basically we don't fail, because:
- If type inference comes with a candidate (other than the default inferred ie. obj) we use it.
- Even in the case where this is really an error, this error message is not telling us anything interesting, in turn it "hides" the real error message, which tell us that a default type
obj
was used and it doesn't match this (very useful to debug) list of candidate methods.
Another option would be to check if the candidate was inferred using a default type, but again, that error message is more useful than just 'Could not resolve the ambiguity'.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
In Progress