Return types in shadowing members are not considered in generic constraint resolution to avoid ambiguity.
Description
It seems that when a member is shadowing an inherited member with a different return type, the return type is not considered to avoid any ambiguity when the compiler is attempting to resolve the member.
Repro steps
Self-explanatory example:
type Mother() =
member this.Hello() =
Unchecked.defaultof<int32>
type Daughter() =
inherit Mother()
member this.Hello() =
Unchecked.defaultof<string>
type SomeoneHolder<'Someone when 'Someone: (member Hello : unit -> string)> =
{ Someone: 'Someone }
let someoneHolder =
{ Someone = Daughter() }
Expected behavior
It should compile.
Actual behavior
It does not, with the error below:
[FS0001] A unique overload for method 'Hello' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates:
member Daughter.Hello : unit -> string,member Mother.Hello : unit -> int32
Known workarounds
None.
Related information
Provide any related information (optional):
The return type
- Operating system: Windows 10 Enterprise
- .NET Runtime kind (.NET Core, .NET Framework, Mono): .NET Core 3.1
- Editing Tools (e.g. Visual Studio Version, Visual Studio): Rider
What was interesting to me wasn't so much that return types aren't considered (this is the default for both C# and F#) but that overload resolution takes shadowed members into account here.
@NinoFloris I kinda disagree:
type Daddy() =
member this.Hello() =
Unchecked.defaultof<int32>
type SomeoneHolder<'Someone when 'Someone: (member Hello : unit -> string)> =
{ Someone: 'Someone }
let someoneHolder =
{ Someone = Daddy() }
[FS0001] This expression was expected to have type
'string'
but here has type'int32'
Maybe we're not on the same page.
The return type needs to respect the signature given in the generic constraint.
So... why not the same behavior for a shadowing member?
Also, I don't think it's that surprising that shadowing members are actually processed by the generic constraint resolution process.
=> All in all there is an issue of consistency.
It does surprise me that the shadowed member is being taken into accdount.
Since this involves SRTP constraint resolution I will investigate as part of https://github.com/dotnet/fsharp/pull/6805.
We (@kerry-perret and I) discussed this briefly over the weekend and found that the code as written is documented as not being allowed. Mainly, member constraints can only be used with SRTP, and cannot be used on types (i.e., even changing ' to ^ won't allow this code to compile):

Still, the error is confusing and it appears as if the compiler actually tries to resolve the member constraint here.