-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Support EnumeratorCancellationAttribute in local functions #40959
Support EnumeratorCancellationAttribute in local functions #40959
Conversation
@@ -227,35 +230,39 @@ public override ImmutableArray<CustomModifier> RefCustomModifiers | |||
|
|||
private sealed class SynthesizedComplexParameterSymbol : SynthesizedParameterSymbolBase | |||
{ | |||
private readonly ImmutableArray<CustomModifier> _refCustomModifiers; | |||
private readonly ImmutableArray<CSharpAttributeData> _attributes; | |||
private readonly ParameterSymbol _baseParameter; |
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: consider enabling nullability analysis in this file, or asserting that baseParameter
is not null in constructor. #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 with review pass (iteration 1). Thanks!
@RikkiGibson Do you know the reason for CI failures? #Closed |
EE was using the old signatures of the internal SynthesizedParameterSymbol.Create methods. Working on how to rationalize the design/hierarchy of the synthesized parameter symbols in light of this. #Resolved |
src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs
Outdated
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs
Outdated
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs
Outdated
Show resolved
Hide resolved
Done with review pass (iteration 1). #Closed |
src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs
Outdated
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs
Outdated
Show resolved
Hide resolved
@@ -833,6 +834,34 @@ internal sealed override void PostDecodeWellKnownAttributes(ImmutableArray<CShar | |||
base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData); | |||
} | |||
|
|||
// Called after all method attributes, return attributes, and parameter attributes have been initialized on this method. | |||
protected void PostDecodeAllMethodAttributes(DiagnosticBag diagnostics) |
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.
PostDecodeAllMethodAttributes [](start = 23, length = 29)
nit: could be given a more specific name at the moment, since it only checks EnumeratorCancellation attribute #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.
LGTM Thanks (iteration 4)
src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs
Outdated
Show resolved
Hide resolved
if (enumeratorCancellationCount == 0 && | ||
ParameterTypesWithAnnotations.Any(p => p.Type.Equals(cancellationTokenType))) | ||
{ | ||
// Warn for CancellationToken parameters in async-iterators with no parameter decorated with [EnumeratorCancellation] |
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.
async-iterators [](start = 68, length = 15)
@jcouv I assume you added this code originally, where do we make sure this is an iterator?
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.
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.
@AlekseyTs From our discussion, there are three factors to make an async-iterator: (1) async
, (2) the return type, and (3) a yield
in the body.
But we enforce that you cannot have (1) and (2) without having (3). We produce an error in that case (see test below). So in other places in the code, we can just check for (1) and (2).
I have a vague recollection that there was some technical benefit to this approach, but I'm not longer sure.
@RikkiGibson Would you mind adding a comment in the code that you're moving to capture this? I'd add it in master, but that would only create a conflict for when you'll merge...
[Fact]
[WorkItem(31552, "https://github.com/dotnet/roslyn/issues/31552")]
public void AsyncIterator_WithThrowOnly()
{
string source = @"
class C
{
public static async System.Collections.Generic.IAsyncEnumerable<int> M()
{
throw new System.NotImplementedException();
}
}";
var comp = CreateCompilationWithAsyncIterator(source);
comp.VerifyDiagnostics(
// (4,74): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
// public static async System.Collections.Generic.IAsyncEnumerable<int> M()
Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(4, 74)
);
comp.VerifyEmitDiagnostics(
// (4,74): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
// public static async System.Collections.Generic.IAsyncEnumerable<int> M()
Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(4, 74),
// (4,74): error CS8420: The body of an async-iterator method must contain a 'yield' statement. Consider removing 'async' from the method declaration or adding a 'yield' statement.
// public static async System.Collections.Generic.IAsyncEnumerable<int> M()
Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, "M").WithArguments("System.Collections.Generic.IAsyncEnumerable<int>").WithLocation(4, 74)
);
var m = comp.SourceModule.GlobalNamespace.GetMember<MethodSymbol>("C.M");
Assert.False(m.IsIterator);
Assert.True(m.IsAsync);
}
} | ||
} | ||
|
||
PostDecodeAllMethodAttributes(diagnostics); |
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.
PostDecodeAllMethodAttributes [](start = 12, length = 29)
It feels like "AfterReturnTypeBoundAndParametersAreCreated" is more precise name. However, I don't think we need a dedicated method for this operation. In fact, I think that this is not the right place for this kind of checks. We haven't finalized the signature of the method yet and are likely to mutate it below. It feels like this check belongs in LazyAsyncMethodChecks, which is called in the right time. Also, it looks like for local functions the checks performed by LazyAsyncMethodChecks are duplicated. I think it would be good to consolidate that and avoid code duplication. #Closed
@@ -125,6 +125,8 @@ internal void GetDeclarationDiagnostics(DiagnosticBag addTo) | |||
GetAttributes(); | |||
GetReturnTypeAttributes(); | |||
|
|||
PostDecodeAllMethodAttributes(_declarationDiagnostics); |
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.
PostDecodeAllMethodAttributes(_declarationDiagnostics); [](start = 12, length = 55)
Should consolidate with other async-related checks performed for local functions and probably share code with regular methods so that there was one, well defined place where we perform async-related checks. #Closed
Done with review pass (iteration 5) #Closed |
@AlekseyTs Please let me know if I have adequately addressed your comments. |
{ | ||
foreach (var parameter in Parameters) | ||
{ | ||
var loc = parameter.Locations.FirstOrDefault() ?? location; |
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.
parameter.Locations.FirstOrDefault() ?? location [](start = 26, length = 48)
Consider calculating this lazily, i.e. only when we have something to report.
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 (iteration 7)
Related to #38801