Why is C# unable to infer the generic type argument type from a non-generic static method's signature?

Viewed 1479

I have conducted the following inference tests:

static class InferenceTest {
    static void TakeInt(int a) { }
    static int GiveInt() { return 0; }
    static int TakeAndGiveInt(int a) { return 0; }

    static void ConsumeAction1<T>(Action<T> a) { }
    static void ConsumeFunc1<T>(Func<T> f) { }
    static void ConsumeFunc2a<T1, T2>(Func<T1, T2> f) { }
    static void ConsumeFunc2b<T>(Func<int, T> f) { }
    static void ConsumeFunc2c<T>(Func<T, T> f) { }
    static void ConsumeFunc1Func2<T1, T2>(Func<T1> f1, Func<T1, T2> f2) { }

    static void Main() {
        ConsumeAction1(TakeInt);        //error
        ConsumeFunc1(GiveInt);          //ok
        ConsumeFunc2a(TakeAndGiveInt);  //error
        ConsumeFunc2b(TakeAndGiveInt);  //ok
        ConsumeFunc2c(TakeAndGiveInt);  //error
        ConsumeFunc1Func2(GiveInt, TakeAndGiveInt); //ok
    }
}

The results seem to suggest that the C# compiler is unable to infer the generic type arguments for the delegate function parameters from a non-generic method group.

What puzzles me the most is that C# is can infer the type arguments for Func<T1, T2> from the method return values in ConsumeFunc1Func2, but is unable to infer the types for Func<T, T> in ConsumeFunc2c.

This question is similar to the T of Func<S, T> is inferred from output of lambda expression only when S and T are different? question, but instead of lambdas with unknown parameter types we have non-generic method groups.

The Why can't C# infer type from this seemingly simple, obvious case question sort of answers the questions "Why are non-ambiguous non-generic methods not enough for inference?" and "Why is there a difference between the argument types and the return value type for inference?".

Questions:

Why can the C# compiler infer the type of Func<T> using the type of the return value, but fails to see the success in the Func<T, T> case?

Why can the C# compiler infer the T1 type argument for Func<T1, T2> from the Func<T1> in ConsumeFunc1Func2, but cannot infer the T type argument for Func<T, T> from itself in ConsumeFunc2c which seems to be easier?

2 Answers
Related