It's not a limitation of the compiler - it's a limitation of the language (and quite possibly the CLR as well; I'm not sure).
Fundamentally those are clashing overloads - it's like trying to overload by return type. It's not supported.
It is possible to declare methods such that these calls all compile to invocations of different methods:
a.Do<int>();
a.Do<string>();
a.Do<int?>();
... but it always involves optional parameters and/or parameter arrays, and it's horrible.
Also note that although you can't overload by generic constraints, you can overload by the generic "arity" (the number of type parameters):
public void Foo() {}
public void Foo<T>() {}
public void Foo<T1, T2>() {}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…