-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
enable main methods to be asynchronous #18157
enable main methods to be asynchronous #18157
Conversation
@@ -597,18 +597,47 @@ internal bool IsEntryPointCandidate | |||
|
|||
/// <summary> | |||
/// Checks if the method has an entry point compatible signature, i.e. | |||
/// - the return type is either void or int | |||
/// - the return type is either void, int, Task, or Task<int> |
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 <see cref #Resolved
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.
Done #Resolved
} | ||
else | ||
{ | ||
return false; |
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 a concern that ValueTask is not matched 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.
For now we are just supporting Task, however, the comments in this method describe how to (very easily) support any "task-like" object including ValueTask.
@dotnet/roslyn-compiler This is now out for review. |
Looks like there's a warning preventing build from succeeding:
|
@@ -1104,7 +1104,7 @@ internal enum ErrorCode | |||
ERR_VarargsAsync = 4006, | |||
ERR_ByRefTypeAndAwait = 4007, | |||
ERR_BadAwaitArgVoidCall = 4008, | |||
ERR_MainCantBeAsync = 4009, | |||
// ERR_MainCantBeAsync = 4009, |
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.
Should we delete the corresponding resource string?
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.
Done
return false; | ||
} | ||
|
||
if (!IsAsyncMainReturnType(returnType) && IsAsync) |
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 should add a test case for this too.
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.
Already had an async void
test, I'll add an async int
test too
{ | ||
return false; | ||
} | ||
// Change this to `namedType.IsNonGenericTaskType` if you want to support "task-like" objects. |
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.
Nit: in general we don't break up if / else if structures with comments like this. Instead put them into the body, or add a meta comment to the local function.
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.
Done
|
||
class A | ||
{ | ||
async static Task<float> Main() |
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.
Should add variants that check for async Task / Task<T>
and have a Main(string[])
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.
Done
@jcouv Thanks! Should have it fixed by now. |
@@ -597,18 +597,48 @@ internal bool IsEntryPointCandidate | |||
|
|||
/// <summary> | |||
/// Checks if the method has an entry point compatible signature, i.e. | |||
/// - the return type is either void or int | |||
/// - the return type is either void, int, <see cref="System.Threading.Tasks.Task" />, | |||
/// or <see cref="System.Threading.Tasks.Task{T}" /> Where T is an int. |
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.
Where [](start = 61, length = 5)
Nit: capitalization on "where"
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.
Done #Resolved
{ | ||
if (this.IsVararg) | ||
|
||
bool IsAsyncMainReturnType(TypeSymbol type) |
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.
Should the new logic be conditional on language version?
If so, please add a test with language version 7.
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.
Done. Added a version of each of these tests that uses langversion 7
return false; | ||
} | ||
|
||
if (!IsAsyncMainReturnType(returnType) && IsAsync) |
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.
IsAsyncMainReturnType(returnType) [](start = 17, length = 33)
Consider pulling IsAsyncMainReturnType(returnType)
into a local. #Closed
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.
Done #Closed
// async static Task<float> Main() | ||
Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main()").WithLocation(6, 30), | ||
// error CS5001: Program does not contain a static 'Main' method suitable for an entry point | ||
Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1) ); | ||
} |
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 adding a test without async
(Main
method returns a Task
by hand).
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.
Never mind, I see that you use string replacement to achieve that.
In reply to: 108235403 [](ancestors = 108235403)
Makes me wonder if this diagnostic should provide more explicit directions about what is allowed (might be lengthy though). Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs:1429 in 3228961. [](commit_id = 3228961, deletion_comment = False) |
} | ||
}"; | ||
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); | ||
compilation.VerifyDiagnostics(Diagnostic(ErrorCode.ERR_MainCantBeAsync, "Main").WithArguments("A.Main(string[])").WithLocation(6, 23)); |
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.
If you use a C# 7 compiler but set language version = 6, using a C# 7 feature like tuples will give you a better error ("Please use C# 7").
Can we do the same here? Look at CheckFeatureAvailability
method.
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.
Done.
} | ||
|
||
[Fact] | ||
public void MainCanBeAsync() |
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.
Note: please add a test verifying we don't allow variants where main has a ref return.
static ref Task Main() { ... }
Context is that we incorrectly allow this for int
today: #17923
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'll cherry-pick your PR into my branch and add a test.
compilation.VerifyDiagnostics( | ||
// (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. | ||
// async static Task Main(string[] args) | ||
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static Task Main(string[] args) |
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.
Would it be possible for the diagnostic to point to a narrow piece of syntax? For example "Main" or maybe "async"?
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've added a comment and will get back to this shortly
The Main method cannot have a ref return. closes dotnet#17923
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.
LGTM
Nit: I think the marker convention would be PROTOTYPE(async-main) for this branch, not just PROTOTYPE.
I'm merging now even though the tests aren't done. The tests were all passing and I only made a change to a comment. |
This is the first chunk in enabling Async-Main. It merely concerns itself with deciding which methods have valid entrypoint signatures.