{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/24750","repository_url":"https://api.github.com/repos/dotnet/roslyn","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/24750/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/24750/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/24750/events","html_url":"https://github.com/dotnet/roslyn/pull/24750","id":296042198,"number":24750,"title":"Implement async foreach statement","user":{"login":"jcouv","id":12466233,"avatar_url":"https://avatars2.githubusercontent.com/u/12466233?v=4","gravatar_id":"","url":"https://api.github.com/users/jcouv","html_url":"https://github.com/jcouv","followers_url":"https://api.github.com/users/jcouv/followers","following_url":"https://api.github.com/users/jcouv/following{/other_user}","gists_url":"https://api.github.com/users/jcouv/gists{/gist_id}","starred_url":"https://api.github.com/users/jcouv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jcouv/subscriptions","organizations_url":"https://api.github.com/users/jcouv/orgs","repos_url":"https://api.github.com/users/jcouv/repos","events_url":"https://api.github.com/users/jcouv/events{/privacy}","received_events_url":"https://api.github.com/users/jcouv/received_events","type":"User","site_admin":false},"labels":[{"id":166673288,"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Compilers","name":"Area-Compilers","color":"5319e7","default":false},{"id":790171513,"url":"https://api.github.com/repos/dotnet/roslyn/labels/New%20Feature%20-%20Async%20Streams","name":"New Feature - Async Streams","color":"bfd4f2","default":false}],"state":"open","locked":false,"assignee":{"login":"jcouv","id":12466233,"avatar_url":"https://avatars2.githubusercontent.com/u/12466233?v=4","gravatar_id":"","url":"https://api.github.com/users/jcouv","html_url":"https://github.com/jcouv","followers_url":"https://api.github.com/users/jcouv/followers","following_url":"https://api.github.com/users/jcouv/following{/other_user}","gists_url":"https://api.github.com/users/jcouv/gists{/gist_id}","starred_url":"https://api.github.com/users/jcouv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jcouv/subscriptions","organizations_url":"https://api.github.com/users/jcouv/orgs","repos_url":"https://api.github.com/users/jcouv/repos","events_url":"https://api.github.com/users/jcouv/events{/privacy}","received_events_url":"https://api.github.com/users/jcouv/received_events","type":"User","site_admin":false},"assignees":[{"login":"jcouv","id":12466233,"avatar_url":"https://avatars2.githubusercontent.com/u/12466233?v=4","gravatar_id":"","url":"https://api.github.com/users/jcouv","html_url":"https://github.com/jcouv","followers_url":"https://api.github.com/users/jcouv/followers","following_url":"https://api.github.com/users/jcouv/following{/other_user}","gists_url":"https://api.github.com/users/jcouv/gists{/gist_id}","starred_url":"https://api.github.com/users/jcouv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jcouv/subscriptions","organizations_url":"https://api.github.com/users/jcouv/orgs","repos_url":"https://api.github.com/users/jcouv/repos","events_url":"https://api.github.com/users/jcouv/events{/privacy}","received_events_url":"https://api.github.com/users/jcouv/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/dotnet/roslyn/milestones/18","html_url":"https://github.com/dotnet/roslyn/milestone/18","labels_url":"https://api.github.com/repos/dotnet/roslyn/milestones/18/labels","id":1675130,"number":18,"title":"16.0","description":"The version *after* the next major version.","creator":{"login":"gafter","id":3804346,"avatar_url":"https://avatars3.githubusercontent.com/u/3804346?v=4","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"open_issues":611,"closed_issues":100,"state":"open","created_at":"2016-03-31T00:06:25Z","updated_at":"2018-02-09T23:19:31Z","due_on":null,"closed_at":null},"comments":4,"created_at":"2018-02-09T23:19:31Z","updated_at":"2018-02-10T17:29:46Z","closed_at":null,"author_association":"MEMBER","pull_request":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/24750","html_url":"https://github.com/dotnet/roslyn/pull/24750","diff_url":"https://github.com/dotnet/roslyn/pull/24750.diff","patch_url":"https://github.com/dotnet/roslyn/pull/24750.patch"},"body":"I'm still working on this PR. \r\nIn particular, there is a bug with evaluation order with deconstruction (the `Deconstruct` should be invoked after `success` check) and I have a few other small PROTOTYPE markers I want to address.\r\n\r\nThe PR implements support for `foreach await (...) { ... }`.\r\nAs with regular `foreach`, the collection can either implement an interface `IAsyncEnumerable<T>` or a pattern (ie. having a proper `GetEnumerator` that returns a type with proper `WaitForNextAsync` and `TryGetNext` methods).\r\n\r\nIf the collection implements `IAsyncEnumerable<T>`, then it also implements `IAsyncDisposable`. The collection could implement the async enumerable pattern and directly implement `IAsyncDisposable`. In those cases and also when the collection type is unsealed (ie. derived type may be disposable) we'll make sure to async-dispose the collection (or at least try).\r\n\r\nThe lowered form generally looks like:\r\n```C#\r\nE e = ((C)(x)).GetAsyncEnumerator()\r\ntry\r\n{\r\n    while (await e.WaitForNextAsync()) /* outer loop */\r\n    {\r\n        while (true) /* inner loop */\r\n        {\r\n            V v = (V)e.TryGetNext(out bool success);\r\n            if (!success) goto outer_loop_continue;\r\n            /* loop.Body */\r\n            /* loop.ContinueLabel: */\r\n        }\r\n        outer_loop_continue:\r\n    }\r\n    /* loop.BreakLabel: */\r\n}\r\nfinally { await e.DisposeAsync(); }\r\n```\r\n\r\nUmbrella issue for async streams: https://github.com/dotnet/roslyn/issues/24037\r\nSpec for async-streams: https://github.com/dotnet/csharplang/blob/master/proposals/async-streams.md\r\nSpec for regular `foreach`: https://github.com/dotnet/csharplang/blob/master/spec/statements.md#the-foreach-statement\r\n\r\nNew spec questions:\r\n- [ ] Should we disallow `struct` async enumerator?\r\n- [ ] Extension methods for `GetAsyncEnumerator`, `WaitForNextAsync`, and `TryGetNext` do not contribute. This mirrors behavior for regular `foreach`. But I'd like to confirm.\r\n- [ ] Should the pattern for async enumerators also recognize when a task-like is returned instead of `Task<bool>`?\r\n- [ ] I think we'll need to block `dynamic` since there is no async counterpart to the non-generic `IEnumerable` that would convert `dynamic` to.\r\n- [ ] 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."},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/364674105","html_url":"https://github.com/dotnet/roslyn/pull/24750#issuecomment-364674105","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/24750","id":364674105,"user":{"login":"jcouv","id":12466233,"avatar_url":"https://avatars2.githubusercontent.com/u/12466233?v=4","gravatar_id":"","url":"https://api.github.com/users/jcouv","html_url":"https://github.com/jcouv","followers_url":"https://api.github.com/users/jcouv/followers","following_url":"https://api.github.com/users/jcouv/following{/other_user}","gists_url":"https://api.github.com/users/jcouv/gists{/gist_id}","starred_url":"https://api.github.com/users/jcouv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jcouv/subscriptions","organizations_url":"https://api.github.com/users/jcouv/orgs","repos_url":"https://api.github.com/users/jcouv/repos","events_url":"https://api.github.com/users/jcouv/events{/privacy}","received_events_url":"https://api.github.com/users/jcouv/received_events","type":"User","site_admin":false},"created_at":"2018-02-10T17:29:46Z","updated_at":"2018-02-10T17:29:46Z","author_association":"MEMBER","body":"@alrz Indeed. Found this one: https://github.com/dotnet/csharplang/issues/600 (Proposal: Allow GetEnumerator method to be implemented via extension methods)"}}
{"actor":{"display_login":"jcouv"}}