Improve async iterator diagnostic by removing redundant error#81282
Improve async iterator diagnostic by removing redundant error#81282CyrusNajmabadi merged 11 commits intomainfrom
Conversation
Add new error code ERR_BadAwaitWithoutAsyncIterator (CS4037) that provides a better error message when an async iterator method is missing the 'async' keyword. The new error only suggests adding 'async' without suggesting to change the return type, since the return type is already correct for async iterators (IAsyncEnumerable<T> or IAsyncEnumerator<T>). Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
| method.ReturnType.IsIAsyncEnumeratorType(Compilation))) | ||
| { | ||
| // For async iterators, don't suggest changing the return type | ||
| info = new CSDiagnosticInfo(ErrorCode.ERR_BadAwaitWithoutAsyncIterator); |
There was a problem hiding this comment.
@copilot instead of a new error, can you use ERR_BadAwaitWithoutAsync? #Closed
There was a problem hiding this comment.
Done in 3de3769. Using ERR_BadAwaitWithoutAsync which provides a simpler message without suggesting a return type change.
| [WorkItem(31113, "https://github.com/dotnet/roslyn/issues/31113")] | ||
| public void AsyncIteratorReturningEnumerable_WithoutAsync() | ||
| { | ||
| string source = @" |
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs
Outdated
Show resolved
Hide resolved
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs
Outdated
Show resolved
Hide resolved
Address review feedback to use the existing ERR_BadAwaitWithoutAsync error instead of creating a new error code. This error already has an appropriate message for async iterators that doesn't suggest changing the return type. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Convert verbatim strings to raw string literals and update line numbers in diagnostic expectations accordingly. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
| { | ||
| info = new CSDiagnosticInfo(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod); | ||
| } | ||
| else if (method.IsIterator && |
Keep the original verbatim string format for the existing AsyncIteratorReturningEnumerator_WithoutAsync test. Only the new AsyncIteratorReturningEnumerable_WithoutAsync test uses raw string literals. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
| // (3,61): error CS8403: Method 'C.M(int)' with an iterator block must be 'async' to return 'IAsyncEnumerable<int>' | ||
| // static System.Collections.Generic.IAsyncEnumerable<int> M(int value) | ||
| Diagnostic(ErrorCode.ERR_IteratorMustBeAsync, "M").WithArguments("C.M(int)", "System.Collections.Generic.IAsyncEnumerable<int>").WithLocation(3, 61), | ||
| // (6,9): error CS1992: The 'await' operator can only be used when contained within a method or lambda expression marked with the 'async' modifier |
There was a problem hiding this comment.
@copilot do we even need this error? It looks like we already report error CS8403: Method 'C.M(int)' with an iterator block must be 'async' to return 'IAsyncEnumerable<int>'. Since we already have that error, can we just not report this error on await? If so, update the code to check for that and not report, but give a comment in the code explaining why that's ok. #Closed
There was a problem hiding this comment.
Done in a5766a3. Since ERR_IteratorMustBeAsync already tells the user to add 'async', we now skip reporting the await error to avoid redundancy. Added a comment explaining why this is okay.
For async iterators, ERR_IteratorMustBeAsync already tells the user to add 'async', so we don't need to also report an error on the await expression. This avoids redundant error messages. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
| else if (method.IsIterator && | ||
| (method.ReturnType.IsIAsyncEnumerableType(Compilation) || | ||
| method.ReturnType.IsIAsyncEnumeratorType(Compilation))) | ||
| { |
There was a problem hiding this comment.
@copilot mention which method reports this ERR_IteratorMustBeAsync error. Also, if possible, can we share code between that location and this location to ensure that we're checking all the same conditions to report an error there and not report an error here? #Closed
There was a problem hiding this comment.
Done in 5b4c38e. Now using the shared InMethodBinder.IsAsyncStreamInterface method to ensure we check the same conditions, and updated the comment to mention ExecutableCodeBinder.ValidateIteratorMethod as the location that reports the error.
Updated to use InMethodBinder.IsAsyncStreamInterface to share the same logic for detecting async stream interfaces, ensuring consistency between where the error is reported and where we skip reporting. Also updated the comment to mention ExecutableCodeBinder.ValidateIteratorMethod as the location that reports ERR_IteratorMustBeAsync. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
|
@dotnet/roslyn-compiler ptal. |
Improvement to async iterator diagnostics - Complete ✅
This PR improves the diagnostic experience when an async iterator method (returning
IAsyncEnumerable<T>orIAsyncEnumerator<T>) withyieldstatements is missing theasynckeyword.Before:
Two redundant errors were reported:
❌ Multiple errors with incorrect return type suggestion
After:
Single, clear error message:
✅ One focused error without incorrect return type suggestion
Changes
Binder_Await.csto skip reporting await errors for async iterators sinceERR_IteratorMustBeAsyncis already reported byExecutableCodeBinder.ValidateIteratorMethodInMethodBinder.IsAsyncStreamInterfacemethod to ensure consistent detection logicIAsyncEnumerable<T>andIAsyncEnumerator<T>casesTest Results
Fixes #31113
Original prompt
asynckeyword #31113💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.