Repository navigation
Replies: 6 comments
Does this mean the |
I would be seriously unhappy if it did. π |
|
That depends on factors that contribute to the type inference. Being Update: updated. |
|
Would this proposal allow me to write eg. |
|
Taking a look at F# spec, it uses a simpler rule for the name resolution, it only fallbacks to the generic type when there's only a single one, so |
Uh oh!
There was an error while loading. Please reload this page.
Constructor type argument inference
Consider
Tis a name with arity zero.Only if the existing rules are unable to find a constructor to bind, we continue to the next step to retain backward compatibility. In other words, we do so if either of the following conditions are true:
Tdoes not exist or is inaccessibleTis (a) not a class or struct (b) not a type parameterTis static or abstractTdoes not have a constructor or struct constraintAfter that, we gather all the types in scope with the same name regardless of the arity (the arity here would be always greater than zero, because we already tried all names with the arity zero). Then we add all accessible constructors to a set of candidates and run an overload resolution pass. For example, considering:
We resolve
new C(...)just like how we do generic method overload resolution,At the end, if no unfixed type parameters exist then type inference (and the overload resolution) succeeds and we have a single best constructor to be invoked.
Note that "closeness" rules are at play as well, so when we gather generic types, we do so step-by-step for types that are closer to the call-site.
For example, we resolve
new C(42)in the following code:Just like we resolve
C(42)in the following:Therefore, it would not be ambiguous.
Collection Initializers
If the type arguments couldn't be inferred, in the presence of collection initializers, we will try to run the same pass on
Addmethods. Sonew List { 1, 2, 3 }works as expected.Currently, a collection initializer is allowed to call different
Addoverloads based on each element type. To keep the rules simple, we only consider the first element of the initializer when we run the overload resolution pass to resolve the type, and produce error for other elements, if needed.For example, we would fail to infer
C<int>fornew C { { 1, 2 }, 2 };here:Because the matching overload for the first element does not fix the type parameter
T.Obejct Initializers
We won't depend on the object initializers to infer any type argument, so an object initializer is permitted only if all type arguments are already inferred from provided arguments.
Alternatives
When we gather all constructors to the candidate set, there could be conflicting overloads, and if that happened, those should be removed from the set. Alternatively, we could consider "omitted type arguments" to specify the arity without mentioning the type arguments, e.g.
new C<,>()so we don't have to do a complex name resolution to determine the arity. Just that we will try to infer type arguments from the constructor arguments or the collection initializer, if any.Vartiations
A similar approach could be taken to infer type arguments on static method invocations.
All reactions