Skip to content

Member call resolves to generic overload even when matching non-generic overload is available #19890

@brianberns

Description

@brianberns

I'm not calling this a bug, because I think it functions as designed, but I found it very surprising when I ran into it the wild:

namespace One

type Foo() = class end

[<AutoOpen>]
module FooExt =
    type Foo with
        member _.GetString() = "Non-generic"

namespace Two

[<AutoOpen>]
module FooExt =
    type One.Foo with
        member _.GetString<'t>() = $"Generic: {typeof<'t>.Name}"

namespace Three

open One
open Two

module Program =

    let foo = Foo()
    printfn $"{foo.GetString()}"   // output: "Generic: Object"

My expectation was that foo.GetString() would resolve to the non-generic version of GetString, but instead the compiler chose GetString<obj> with nary a peep. If I reverse the order of the open statements, then it resolves to the non-generic version, so I guess it's a case of "last namespace wins".

Suggestion: If the compiler can match a non-generic call with a non-generic member, that should probably take precedence over matching a generic member with an implicit obj type parameter, even if the generic member is in a more recent namespace. Silently filling that type parameter with obj when a non-generic match is available is at least worth a warning, I would think.

Note: In the real world, I was simply the consumer of the Foo type (which lives in an external NuGet package), so I had no visibility into exactly how it was defined across namespaces. Thus, the example code above ruins the surprise that I actually experienced. (IntelliSense gives no hint that they are in different namespaces.)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    New

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions