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
Fix lowering for async-iterator method with type parameter #30105
Conversation
@@ -31,7 +33,8 @@ private sealed class AsyncIteratorRewriter : AsyncRewriter | |||
{ | |||
Debug.Assert(method.IteratorElementType != null); | |||
|
|||
// PROTOTYPE(async-streams): Why does AsyncRewriter have logic to ignore accessibility? |
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.
📝 removed the unnecessary _ignoreAccessibility
field from AsyncRewriter
.
} | ||
|
||
/// <summary> | ||
/// Generates the body of the replacement method, which initializes the state machine. Unlike regular async methods, we won't start it. | ||
/// </summary> | ||
protected override BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType) | ||
{ | ||
// PROTOTYPE(async-streams): TODO review this (what is this error case at the start?) |
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.
📝 Removed this comment, as I don't think this case can be reached with async-iterators. But left the code as I don't think it's harmful.
var elementType = asyncMethod.IteratorElementType; | ||
//this.ElementType = TypeMap.SubstituteType(elementType).Type; // PROTOTYPE(async-streams): TODO | ||
var elementType = TypeMap.SubstituteType(asyncMethod.IteratorElementType).Type; | ||
this.ElementType = elementType; |
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.
📝 This is the central part of this PR (fixes the async-iterator scenario with a generic type parameter).
@@ -174,10 +174,7 @@ protected override void GenerateControlFields() | |||
|
|||
// if it is an enumerable, and either Environment.CurrentManagedThreadId or Thread.ManagedThreadId are available | |||
// add a field: int initialThreadId | |||
bool addInitialThreadId = |
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.
📝 both changes in this file just refactoring (extract method) in preparation for later PR related to thread ID.
@@ -2157,7 +2157,6 @@ public override BoundNode VisitForEachStatement(BoundForEachStatement node) | |||
{ | |||
_pendingBranches.Add(new PendingBranch(node, this.State)); | |||
} | |||
//if (_trackExceptions) NotePossibleException(node); // PROTOTYPE(async-streams) |
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 created a PR against master
to remove _trackExceptions
entirely.
@@ -15,6 +15,8 @@ internal partial class AsyncRewriter : StateMachineRewriter | |||
/// </summary> | |||
private sealed class AsyncIteratorRewriter : AsyncRewriter | |||
{ | |||
private readonly TypeSymbol _elementType; |
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.
_elementType [](start = 40, length = 12)
If this value is only used in one location, consider using stateMachineType.ElementType
directly there rather than creating a field. #Resolved
Should the error message say Refers to: src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncForeachTests.cs:85 in 28b53a5. [](commit_id = 28b53a5feef3d2a43c541f918ad48bc14200dcbf, deletion_comment = False) |
@@ -7,6 +7,7 @@ | |||
|
|||
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen | |||
{ | |||
using Microsoft.CodeAnalysis.CSharp.Symbols; | |||
using Roslyn.Test.Utilities; | |||
using static Instruction; |
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.
Please move outside namespace
.
} | ||
}"; | ||
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) | ||
.WithOptimizationLevel(OptimizationLevel.Debug); |
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.
TestOptions.DebugDll
@@ -1075,6 +1138,101 @@ .maxstack 3 | |||
} | |||
} | |||
|
|||
[ConditionalFact(typeof(WindowsDesktopOnly))] | |||
public void AsyncIteratorWithGenericReturn() |
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.
AsyncIteratorWithGenericReturn [](start = 20, length = 30)
Consider testing class C<T> { IAsyncEnumerable<T> M() { ... } }
as well.
d831009
to
d64f2d3
Compare
@@ -59,6 +59,9 @@ async IAsyncEnumerable<int> GetValuesFromServer() | |||
### Detailed design for async `foreach` statement | |||
PROTOTYPE(async-streams): TODO | |||
|
|||
Async foreach is disallowed on collections of type dynamic, as there is no async equivalent of the non-generic `IEnumerable` interface. | |||
|
|||
|
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 remove this extra line
@dotnet/roslyn-compiler for a second review, since Andy is out. Thanks |
/// <summary> | ||
/// Returns true if either Thread.ManagedThreadId or Environment.CurrentManagedThreadId are available | ||
/// </summary> | ||
protected bool CanGetThreadId() |
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.
Doesn't this method need to verify that the GetMethod
exists for System_Environment__CurrentManagedThreadId
? The current invariant guaranteed here doesn't line up with what is needed in MakeCurrenThreadId
#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.
This method is just a refactoring from IteratorRewriter (extracted for later re-use)
In reply to: 221787577 [](ancestors = 221787577)
@@ -1613,35 +1613,44 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r | |||
{ | |||
base.AddSynthesizedAttributes(moduleBuilder, ref attributes); | |||
|
|||
if (this.IsAsync || this.IsIterator) | |||
bool isAsync = this.IsAsync; | |||
bool isIterator = this.IsIterator; |
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 reason that these should be locals? Curious if it's just style or you're protecting against mutations that happen below. #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.
I made those locals because they are used multiple times, but there is no fundamental or other reason.
In reply to: 221787737 [](ancestors = 221787737)
@@ -101,17 +99,18 @@ protected override void GenerateControlFields() | |||
boolType, | |||
GeneratedNames.MakeAsyncIteratorPromiseIsActiveFieldName(), isPublic: true); | |||
|
|||
// the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class | |||
TypeSymbol elementType = ((AsyncStateMachine)stateMachineType).ElementType; |
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.
📝 Did we consider parameterizing the base type on the state machine type? #WontFix
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.
@@ -16,6 +16,7 @@ internal sealed class AsyncStateMachine : StateMachineTypeSymbol | |||
private readonly TypeKind _typeKind; | |||
private readonly MethodSymbol _constructor; | |||
private readonly ImmutableArray<NamedTypeSymbol> _interfaces; | |||
internal readonly TypeSymbol ElementType; // only for async-iterators |
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.
IteratorElementType? #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.
Extract helper methods for current thread ID
Rebased my changes to resolve conflict. |
Fixes mismatch between
T
from the original methodC.M<T>()
and its lowered formunpronounceable<T>.MoveNext()
.Addresses various minor PROTOTYPE comments.