Search code examples
c#genericsimplicit-conversionoverload-resolution

Overload resolution with generics and implicit conversion


This code is not compiled:

static class Foo
{
    public static Bar Do(Func<Bar> f) => null;
    public static Bar<TOut> Do<TOut>(Func<Bar<TOut>> f) => null;
}

public class Bar
{
}

public class Bar<TOut>
{
    public static implicit operator Bar<TOut>(TOut i) => null;
}

// Here compiler complains:
// CS0029 Cannot implicitly convert type 'int' to 'Bar'
// CS1662 Cannot convert lambda expression to intended delegate type 
// because some of the return types in the block
// are not implicitly convertible to the delegate return type
Foo.Do(() => 1);

My expectation would be that compiler sees the return type of the lambda and that no valid overload can be selected unless int is converted to Bar<int>. However, I see that compiler resolves to the first method.

Which part of spec defines this behavior?


Solution

  • This is specified in Method Invocations, when the spec is talking about what method declarations count as a candidate for overload resolution, for an invocation of the form M(A):

    The set of candidate methods for the method invocation is constructed. For each method F associated with the method group M:

    • If F is non-generic, F is a candidate when:
      • M has no type argument list, and
      • F is applicable with respect to A.
    • If F is generic and M has no type argument list, F is a candidate when:
      • Type inference succeeds, inferring a list of type arguments for the call, and
      • [...]

    Just from those rules, we can see that the non-generic Do is a candidate, and the generic Do is not, because type inference fails. Try commenting out the non-generic Do, and you will see that it says something like "type arguments cannot be inferred".