Skip to content

[Umbrella] Work items and test plan for async streams #24037

@jcouv

Description

@jcouv

Spec: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/async-streams.md
Championed issue: dotnet/csharplang#43

Notes on cancellation token and [EnumeratorCancellation]: http://blog.monstuff.com/archives/2019/03/async-enumerables-with-cancellation.html

FAQ and known issues


Async-iterator methods

Async using and foreach

Productivity (code fixers/refactorings/etc):

LDM open issues:

  • async LINQ
    • Parsing issue with return from e in async-collection select await e + 1; // await isn't a keyword
    • how does above scenario and return from e in async-collection select e + 1; lower into LINQ APIs? (the one with await involves Task<int> and the other one involves int directly) How many overloads of Select do we need?
  • Should there be some helper method to convert from IEnumerable to IAsyncEnumerable, or from Task to IAsyncEnumerable?
  • Should the generate token checks be in GetAsyncEnumerator or in MoveNextAsync? (if we do, we need to store the token and maybe dispose it too) (answer: no)
  • Revisit blocking off a word (either in parameter list, like params, or for variable name, like value) for token (answer: we're not going to use a keyword)
  • pattern-based await using should recognize a DisposeAsync method that returns a task-like (or only ValueTask)? (not applicable because no ref structs in async methods)
  • Should pattern-based foreach recognize ... GetAsyncEnumerator() (without CancellationToken)? (yes, LDM 1/9)
  • What attributes should be emitted on async-iterator state machines? (answer: AsyncIteratorStateMachineAttribute)
  • cancellation of async-streams (both as consumer and producer) (see LDM 11/28)
  • confirm syntax for async foreach
  • Should we disallow struct async enumerator? (no, same as regular async, see TestWithPattern_WithStruct_MoveNextAsyncReturnsTask)
  • Should DisposeAsync return a non-generic ValueTask, since there is now one? Or stick with Task?
  • Extension methods for GetAsyncEnumerator, WaitForNextAsync, and TryGetNext do not contribute. This mirrors behavior for regular foreach. But I'd like to confirm. (answer: this is probably something we want to support. Let's queue that for later in the implementation)
  • Should the pattern for async enumerators also recognize when a task-like is returned instead of Task<bool>? (answer: yes)
  • I think we'll need to block dynamic since there is no async counterpart to the non-generic IEnumerable that would convert dynamic to. (answer: seems ok)
  • Do we need async keyword on async iterator methods? I assume yes.
  • Since not enumerable lambdas, I assume the same for async-enumerable. (answer: correct. No async iterator lambda)
  • async-iterator without yield or await, should warn? (answer: without yield it's not recognized as an iterator, warn when no await)
  • I suspect we'll need to declare the loop variable differently: calling TryGetNext first, then checking success and only then dealing with conversions and deconstructions.

Championed issue: dotnet/csharplang#43 (includes LDM notes)

Test ideas for async foreach:

  • Verify that async-dispose doesn't have a similar bug with struct resource

Test ideas for async using:

  • Look up Lippert's blog on using with struct or generic type T
  • Does the pattern or the interface get picked up first? Is it observable? (maybe if the pattern allows task-like returning method)

Test ideas for async iterators:

  • From Andy: we should have at least one test that runs using a non-trivial sync context.
  • From Andy: would it be useful to emit asserts for invalid/unexpected states for at least a little while? We could do it only for debug codegen.
  • Test with yield or await in try/catch/finally
  • More tests with exception thrown in async-iterator
  • There is a case in GetIteratorElementType with IsDirectlyInIterator that relates to speculation, needs testing
  • yield break disallowed in finally and top-level script (see BindYieldBreakStatement); same for yield return (see BindYieldReturnStatement)
  • binding for yield return (BindYieldReturnStatement) validates escape rules, needs testing
  • test yield in async lambda (still error)
  • test with IAsyncEnumerable<dynamic>
  • other tests with dynamic?
  • test should cover both case with AwaitOnCompleted and AwaitUnsafeOnCompleted
  • test async IAsyncEnumerable<int> M() { return TaskLike(); }
  • Can we avoid making IAsyncEnumerable<T> special from the start? Making mark it with an attribute like we did for task-like?
  • Do some manual validation on debugging scenarios, including with exceptions (thrown after yield and after await).
  • Test with one or both or the threadID APIs missing.

BCL (Core)

BCL (mono)

BCL (package)


References:

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done Umbrellas

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions