One of our current proposals is to extend method (and perhaps class) type argument inference and resolution so that:
If the number of type arguments is fewer than the arity of the method/class; and
the number of type arguments is the arity of the method/class minus the number of concept witnesses in the set of type parameters for that method/class; then
insert the missing type parameters into their correct position in the type arguments, padding the type arguments to the arity; and
perform witness type inference.
Example
instance EqInt : Eq<Int> { /* ... */ }
instance OrdBool : Ord<bool> { /* ... */ }
instance NumDouble : Num<double> { /* ... */ }
void DoThing<A, B>(A a, B b) where EqA : Eq<A> where OrdB : Ord<B> { /* ... */ }
void DoAnotherThing<A, [ConceptWitness]NumA, B>(A[] as, B[] bs) where NumA : struct, Num<A> { /* ... */ }
// ...
DoThing<int, bool>(10, true);
// becomes DoThing<int, bool, EqA, OrdB>
// which then infers to <int, bool, EqInt, OrdBool>
DoAnotherThing<double, int>({5.5, 10.6, 97.2}, {27, 53});
// becomes DoAnotherThing<double, NumA, int>
// which then infers to <double, NumDouble, int>
Pros
Allows for concepts to be used more easily in places where the type cannot be inferred, but the witness for the type is a) obvious from the type, and b) clunky to write.
Helps us build a story about concept parameters being (truly) implicit: one need never worry about them unless there is an ambiguity.
Cons
Another magical concept thing that changes the way bits of C# work.
Needs some invasive surgery on how type arguments work.
One of our current proposals is to extend method (and perhaps class) type argument inference and resolution so that:
Example
Pros
Cons