New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Determine the maximum supported language version #37018
base: main
Are you sure you want to change the base?
Conversation
ac0eac6
to
8507e0e
Compare
.NETCore (version 3.0) supports C# 8.0. .NETFramework (all versions), .NETStandard (all versions up through 2.1, the latest at this time), and .NETCore (all versions before 3.0) support version 7.3 of the C# language. Use of a later version with any of those frameworks is not supported, though it will not be blocked. To support certain features the IDE needs to know this maximum supported lang version in addition to the existing 'LangVersion' property. Here we capture that as the 'MaxSupportedLangVersion' property. The project systems will query for this property and pass it along to the language service. Note that other frameworks (e.g. Xamarin, Unity, etc.) are expected to set this property themselves if they wish to use something other than 7.3.
8507e0e
to
2226245
Compare
1. Replace incorrect '.NETCore' with correct '.NETCoreApp' when checking 'TargetFrameworkIdentifier'. 2. Remove unnecessary parentheses.
The 'TargetFrameworkVersion' property takes the form 'v1.0', 'v2.1', etc. To perform an actual version comparison in MSBuild we need to strip off the leading 'v' character. This allows us to specify 8.0 as the max supported C# language version for .NETCoreApp >= 3.0. This avoids a potential future problem where we release .NETCoreApp 5.0 and we inadvertently revert the language version to 7.3.
<_TargetFrameworkVersionAsVersion>$(TargetFrameworkVersion.Substring(1))</_TargetFrameworkVersionAsVersion> | ||
<MaxSupportedLangVersion Condition="'$(MaxSupportedLangVersion)' == '' AND | ||
'$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND | ||
'$(_TargetFrameworkVersionAsVersion)' >= '3.0'">8.0</MaxSupportedLangVersion> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
8.0 [](start = 90, length = 3)
Requesting @agocke to take a look at this. This is going to quickly become a problem when someone forgets to update this targets file in the future, Andy is there any way we can tie this to the general language version infra we already have? Otherwise, we should add something to build boss to check this and be sure they're in sync.
Note that other frameworks (e.g., Xamarin, Unity, etc.) are expected to override this by setting | ||
MaxSupportedLangVersion themselves. --> | ||
<!-- Strip the 'v' off the beginning of TargetFrameworkVersion so we can actually compare it as a version. --> | ||
<_TargetFrameworkVersionAsVersion>$(TargetFrameworkVersion.Substring(1))</_TargetFrameworkVersionAsVersion> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have _TargetFrameworkVersionWithoutV defined by SDK, and despite the fact that it is "private" by underscore convention, others use it.
Elsewhere, we are more defensive and do TrimStart(vV) instead of Substring(1).
I think maybe instead of creating yet another private variable people may depend upon, you could consider inlining it like: https://github.com/microsoft/msbuild/blob/0cd0e92a7243088977d31b56626b56d6116de016/src/Tasks/Microsoft.Common.CurrentVersion.targets#L328
Longer term, I would want to allow leading v as a valid version as mentioned here: dotnet/msbuild#3212 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess inlining wouldn't be good for perf when there is more than one version below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @rainersigwald for thoughts here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I lean toward "use the SDK _TargetFrameworkVersionWithoutV
", or we could use this as an excuse to implement $([MSBuild]::CompareVersions())
(but the coordinated insertion would be a pain; do it like this initially either way).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't count on _TargetFrameworkVersionWithoutV
having been defined, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, sure, this has to work outside the sdk. Then I'd switch to trimstart.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider clearing _TargetFrameworkAsVersion too. I really want to avoid more turds we get scared to clean up after we put in a proper feature in msbuild.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. Is there a canonical way of doing that? Will <_TargetFrameworkVersionAsVersion></_TargetFrameworkVersionAsVersion>
do it? I would assume so, but assumptions are dangerous when it comes to MSBuild. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, or the self-closing tag version <_TargetFrameworkVersionAsVersion />
. Both "set it to empty" instead of "deleting the variable", but that's basically indistinguishable.
But in this case can you just inline it? I only see one use . . .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inlining was my first suggestion, but there will be another version check in here eventually. Maybe better to have the code ready to evolve. When someone goes to add a second one, they may not catch what we've discussed here...
The `TargetFrameworkVersion` property typically starts with a `v` or `V`. To properly compare it as a version we're currently trimming off the `v` via `$(TargetFrameworkVersion.Substring(1))`. However, a safer option is `$(TargetFrameworkVersion.TrimStart(vV))` as this will also properly handle the case where there is no leading `v`.
61171fd
to
3d70690
Compare
I believe @agocke has a different implementation of this that will likely supersede this change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good from the IDE perspective.
<_TargetFrameworkVersionAsVersion>$(TargetFrameworkVersion.TrimStart(vV))</_TargetFrameworkVersionAsVersion> | ||
<MaxSupportedLangVersion Condition="'$(MaxSupportedLangVersion)' == '' AND | ||
'$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND | ||
'$(_TargetFrameworkVersionAsVersion)' >= '3.0'">8.0</MaxSupportedLangVersion> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any impact here of this PR implicitly changing the default langversion from "preview" to 8.0?
@tmeschter What do you think our next steps should be with this PR? Thanks! |
.NETCore (version 3.0) supports C# 8.0.
.NETFramework (all versions), .NETStandard (all versions up through 2.1,
the latest at this time), and .NETCore (all versions before 3.0) support
version 7.3 of the C# language. Use of a later version with any of those
frameworks is not supported, though it will not be blocked.
Certain IDE features need to know this maximum supported
lang version in addition to the existing 'LangVersion' property. Here we
capture that as the 'MaxSupportedLangVersion' property. The project
systems will query for this property and pass it along to the language
service.
Note that other frameworks (e.g. Xamarin, Unity, etc.) are expected to
set this property themselves if they wish to use something other than
7.3.