Conversation
| { | ||
| managedThreadId = MakeCurrentThreadId(); | ||
|
|
||
| var thenBuilder = ArrayBuilder<BoundStatement>.GetInstance(); |
There was a problem hiding this comment.
Give the size, since it's known statically. #Resolved
| } | ||
| }"); | ||
| CompileAndVerify(comp); | ||
| CompileAndVerify(comp, verify: Verification.Skipped); |
There was a problem hiding this comment.
Why does this fail verification? #Resolved
There was a problem hiding this comment.
|
|
||
| When in dispose mode, MoveNext continues to suspend (N) and resume (-1) until the end of the method is reached (-2). | ||
|
|
||
| The result of invoking `DisposeAsync` from states -1 or N is unspecified. This compiler throws `NotSupportException` for those cases. |
There was a problem hiding this comment.
What about calling DisposeAsync simultaneously on multiple threads? Undefined? #Resolved
There was a problem hiding this comment.
Correct. That's also unspecified #Resolved
| ); | ||
| } | ||
|
|
||
| [ConditionalFact(typeof(WindowsDesktopOnly))] |
There was a problem hiding this comment.
What bug is tracking this being enabled on CoreClr again? #Resolved
| yield return 1; | ||
| while (true) | ||
| { | ||
| await Task.Delay(10); |
There was a problem hiding this comment.
Why not Task.Yield? #Resolved
There was a problem hiding this comment.
Habit and didn't know about Yield(). The main goal is to avoid the optimization for already completed tasks.
In reply to: 244785798 [](ancestors = 244785798)
There was a problem hiding this comment.
Understood. The problem with Delay is that over the totality of our unit tests it ends up causing a noticable performance issue. At least historically it's done that. #Resolved
| token.ThrowIfCancellationRequested(); | ||
| } | ||
| } | ||
| public static async System.Threading.Tasks.Task Main() |
There was a problem hiding this comment.
Why the fully qualified name here? #Resolved
| { | ||
| await task; | ||
| } | ||
| catch (System.OperationCanceledException) { } |
There was a problem hiding this comment.
Consider logging that the operation was cancelled successfully. #Resolved
| { | ||
| var enumerator = M().GetAsyncEnumerator(); | ||
| await enumerator.DisposeAsync(); | ||
| System.Console.Write(""done""); |
There was a problem hiding this comment.
Consider a test where you call MoveNext after DisposeAsync. I did not see one in the file (may have missed it). #Resolved
There was a problem hiding this comment.
I think that is covered by DisposeAsyncTwiceAfterRunning below.
In reply to: 244787127 [](ancestors = 244787127)
| private readonly bool _isEnumerable; | ||
|
|
||
| // We use state=-3 to distinguish the initial state from the running state (-1) | ||
| private const int InitialState = -3; |
There was a problem hiding this comment.
-3; [](start = 45, length = 3)
The -3 constant is used twice in this PR. Consider adding a named constant to StateMachinesState. #Resolved
| /// <summary> | ||
| /// States for `yield return` are decreasing from -3. | ||
| /// </summary> | ||
| private int _nextYieldReturnState = StateMachineStates.FinishedStateMachine - 1; // -3 |
There was a problem hiding this comment.
StateMachineStates.FinishedStateMachine - 1; // -3 [](start = 43, length = 52)
This is another location where we could use a named constant for -3 #Resolved
|
Done with review pass (iteration #2) #Resolved |
|
@agocke Did you have any more feedback? Thanks #Resolved |
|
|
||
| When in dispose mode, MoveNext continues to suspend (N) and resume (-1) until the end of the method is reached (-2). | ||
|
|
||
| The result of invoking `DisposeAsync` from states -1 or N is unspecified. This compiler throws `NotSupportException` for those cases. |
There was a problem hiding this comment.
This compiler throws [](start = 74, length = 20)
Perhaps "The compiler generates throw NotSupportedException ..." or "The generated code throws NotSupportedException ..." #Pending
There was a problem hiding this comment.
Definitely. I'll include this fix in my next async-streams PR.
In reply to: 245376450 [](ancestors = 245376450)
|
|
||
| /// <summary> | ||
| /// Lower the body, adding an entry state (-3) at the start, | ||
| /// so that we can differentiate a async-iterator that was never moved forward with MoveNextAsync() |
There was a problem hiding this comment.
a [](start = 41, length = 1)
an? #Pending
There was a problem hiding this comment.
| F.Assignment(F.Local(resultVariable), F.This())); | ||
|
|
||
| var extraReset = GetExtraResetForIteratorGetEnumerator(); | ||
| if (extraReset != null) |
There was a problem hiding this comment.
extraReset != null [](start = 20, length = 18)
Would it make sense to pass in the builder to GetExtraResetForIteratorGetEnumerator()? (That would also allow adding multiple statements, although we probably don't have such a scenario today.) #WontFix
There was a problem hiding this comment.
That can be refactored easily when the need arises.
In reply to: 245383654 [](ancestors = 245383654)
| thenBuilder.Add( | ||
| method.IsStatic || method.ThisParameter.Type.IsReferenceType ? // if this is a reference type, no need to copy it since it is not assignable | ||
| F.Goto(thisInitialized) : // goto thisInitialized | ||
| (BoundStatement)F.StatementList()); |
There was a problem hiding this comment.
(BoundStatement)F.StatementList() [](start = 24, length = 33)
Why add an empty statement list? #Pending
There was a problem hiding this comment.
I don't know. That's existing code though, so I'll leave as-is given the deadline.
In reply to: 245386255 [](ancestors = 245386255)
There was a problem hiding this comment.
The behavior for
DisposeAsyncis only specified if the method is at the beginning, the end or ayield return. It is unspecified if the method is suspended at anawaitor running.Per discussion with LDM, although it doesn't not guarantee that users couldn't call
DisposeAsyncat the wrong time (there are still possible race conditions that we can't guard against) we'll throw in such cases.To that effect:
yield returnandawaitare split:yield returnuses negative numbers (-4 and down),awaituses positive numbers (0 and up, as in regular async methods)The APIs could be mis-used in other ways , but we will not guard those:
MoveNextAsync()on two separate threads is unspecified,MoveNextAsync()afterDisposeAsync()is unspecified, but the implementation just returnsfalse(no items left).Fixes #30109