Skip to content
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

Merged
merged 13 commits into from Oct 2, 2018

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Sep 22, 2018

Fixes mismatch between T from the original method C.M<T>() and its lowered form unpronounceable<T>.MoveNext().
Addresses various minor PROTOTYPE comments.

@jcouv jcouv added this to the 16.0 milestone Sep 22, 2018
@jcouv jcouv self-assigned this Sep 22, 2018
@jcouv jcouv requested a review from a team as a code owner September 22, 2018 21:40
@@ -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?
Copy link
Member Author

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?)
Copy link
Member Author

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;
Copy link
Member Author

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 =
Copy link
Member Author

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)
Copy link
Member Author

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.

@jcouv
Copy link
Member Author

jcouv commented Sep 24, 2018

@agocke @cston @dotnet/roslyn-compiler for review. This is addressing a number of small follow-up issues (PROTOTYPE markers) in async-streams feature. Thanks

@@ -15,6 +15,8 @@ internal partial class AsyncRewriter : StateMachineRewriter
/// </summary>
private sealed class AsyncIteratorRewriter : AsyncRewriter
{
private readonly TypeSymbol _elementType;
Copy link
Member

@cston cston Sep 26, 2018

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

@cston
Copy link
Member

cston commented Sep 26, 2018

            // (6,33): error CS9001: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public definition for 'GetAsyncEnumerator'

Should the error message say public instance? In this case, there is a public method. #Resolved


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;
Copy link
Member

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);
Copy link
Member

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()
Copy link
Member

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.

@@ -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.


Copy link
Member Author

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

@jcouv
Copy link
Member Author

jcouv commented Oct 1, 2018

@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()
Copy link
Member

@jaredpar jaredpar Oct 1, 2018

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

Copy link
Member Author

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;
Copy link
Member

@jaredpar jaredpar Oct 1, 2018

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

Copy link
Member Author

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;
Copy link
Member

@jaredpar jaredpar Oct 1, 2018

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean to avoid the cast? I could look into that


In reply to: 221788308 [](ancestors = 221788308)

@@ -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
Copy link
Member

@jaredpar jaredpar Oct 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IteratorElementType? #Resolved

Copy link
Member

@jaredpar jaredpar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@jcouv
Copy link
Member Author

jcouv commented Oct 2, 2018

Rebased my changes to resolve conflict.

@jcouv jcouv merged commit 4bf785c into dotnet:features/async-streams Oct 2, 2018
@jcouv jcouv deleted the async-streams6 branch October 2, 2018 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants