- Effect of language version on overload resolution in presence of
params
collections - Partial type inference: '_' in method and object creation type argument lists
(#8061)
Issues were encountered when earlier C# versions were specified. For example, the runtime team added params ReadOnlySpan<object>
and users that combined .NET 9 and C# 12, such as with the .csproj
fragment that follows, received an error:
<LangVersion>12</LangVersion>
<TargetFramework>net9.0</TargetFramework>
The feature 'params collections' is currently in Preview and unsupported. To use Preview features, use the 'preview' language version.
This happens because the changes we made to overload resolution to prefer params ReadOnlySpan<T>
are unconditional but using the feature is guarded by LangVersion
.
Looking at how we have handled guarding other features on LangVersion
finds variations where different features have been handled differently and features have been handled differently at different points in C# history.
A primary reason for LangVersion
was included in Roslyn is to support teams where some members are on a later version of the compiler - for example because they are using a later version of Visual Studio.
For at least much of the Roslyn history, if using a feature would cause an error if used with an earlier compiler (SDK/VS version), then consumption was not supported. Otherwise it was.
Available options for handling overload resolution in this case are given below.
There are concerns on ignoring language version on consumption because of how much it is tied to collection expressions. We expect the compiler would inject C# 11+ code patterns into C# 10 (or early) code bases which would not be expecting collection expressions.
This approach would result in the new rules only applying to C# 13 and above.
Applicable function member refers to expanding params
at the callsite to act as a collection expression.
You could still explicitly call the method, but it would not be chosen during overload resolution for params
.
This is a variation of the previous option.
While selecting a different overload is a breaking change, we sometimes take this kind of change.
If code starts working in the C# 13 compiler's version of C# 11, that can create an issue in teams. And also, if the selected overload changes when you do not change your compiler, but upgrade your language version and call a different overload, that's a break.
Additional language version guards in the compiler add complexity and increasing the test matrix. But not applying the guard means that if a user upgrades their compiler they could see different overload resolution, even if they continue to use the same lower version of C#. Since we have said we will evolve the behavior of collection expressions to make them better, you could get a change in code (although not a semantic change) every year.
We will guard based on language version - approach Guard applicable function member changes on LangVersion.
(#7582)
We reviewed a proposal for skipping inferrable type arguments in the type argument list for invocation expressions and object creation expressions.
In addition to type arguments, there are other potential uses (more in the proposal):
// This code is to show the possible application
// and is not an indication of syntax.
G<_,>
_[] // arrays
_? // nullable types
- `_` (underscore)
- `var`
- `` (empty)
- `..`
- `*`
- `__`
We will continue to explore top level type inference.
It is too early to make a decision on syntax, but we lean to using var
as the most semantically correct.
To preserve this space, we may begin disallowing _
as a type name. If you wish to use it as a type name, you would need to prefix: @_
.