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

Rename AsyncIterator back to Stream, introduce an AFIT-based AsyncIterator trait #119550

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

yoshuawuyts
Copy link
Member

This PR introduces a new AFIT-based AsyncIterator trait, and renames the existing AsyncIterator trait back to Stream. WG Async does not yet have internal consensus on what the right API for "async iterator" should be. What seems to be missing is actual feedback from implementation and usage. So to that end I'm proposing we temporarily introduce both formulations of the "async iterator" trait.

Personally I've been wanting to make this change for several years now, but the lack of stable AFITs has been a limiting factor. Now that AFITs have landed in Rust 1.75 (December 2023), we should be OK to begin experimenting with this in-tree. The reason for choosing the Stream name is because in its current form the existing trait isn't actually the "async version of iterator". It's closer to the "async version of pinned iterator", but with future state machine internals exposed. Contrasted with the AFIT-based AsyncIterator trait, this formulation seems distinct enough that it warrants having its own name. And Stream seems like the obvious choice for that.

The deep connection between the "async iterator" trait and various language features is why we can't just continue experimenting with it in the ecosystem. Once this PR lands, this will enable WG Async to integrate the AFIT-based version of AsyncIterator with async gen {} blocks, async gen fn functions, and for..await in loops.

ref #79024

cc/ @rust-lang/wg-async @rust-lang/libs-api

r? @compiler-errors, both you and Eric have most recently been working on this code. I've mostly just renamed things, but I figured you might want to take a look. No worries if you're busy though.

The current formulation of `AsyncIterator` is not "the async version of iterator". It is closer to: "the async version of lending iterator". This is because the `poll_next` method pins the future states, as well as the generator state.

This is the first in two commits: in the second commit we will reintroduce the `AsyncIterator` trait which does not pin the generator state - accurately encoding an "async version of iterator". The intent is for both implementations to exist side-by-side on nightly, giving us an opportunity to experiment with the different formulations and analyze the trade-offs.
This is the second commit in the series, introducing an Async Functions in Traits based `AsyncIterator` trait. This is a necessary step towards experimenting with AFIT-based `async gen {}` blocks, and `for await..in` loops.
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Jan 3, 2024
@rustbot
Copy link
Collaborator

rustbot commented Jan 3, 2024

rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead.

cc @rust-lang/rust-analyzer

Some changes occurred to the core trait solver

cc @rust-lang/initiative-trait-system-refactor

@rust-log-analyzer

This comment has been minimized.

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

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

Is there going to be any bridging impls between the AFIT-based AsyncIterator and async gen/Stream impls? Can such a bridging impl even be written soundly?

Comment on lines 9 to 17
let mut async_iter = async_iter.into_async_iter();

let waker = core::task::Waker::noop();
let mut cx = &mut core::task::Context::from_waker(&waker);

assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(0)));
assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(1)));
assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(2)));
assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(None));
assert_eq!(pin!(async_iter.next()).poll(&mut cx), Poll::Ready(Some(0)));
assert_eq!(pin!(async_iter.next()).poll(&mut cx), Poll::Ready(Some(1)));
assert_eq!(pin!(async_iter.next()).poll(&mut cx), Poll::Ready(Some(2)));
assert_eq!(pin!(async_iter.next()).poll(&mut cx), Poll::Ready(None));
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 find this diff does a pretty good job showing the differences in pinning between the two formulations. Just like with the non-async Iterator trait, the AFIT-based AsyncIterator trait doesn't require the iterator to be pinned. Instead it's only the individual futures which have to be pinned. While the Stream trait requires the entire iterator to be pinned for the entire duration.

One of the things we want to investigate is the precise lowering of async gen blocks and functions to the AFIT-based AsyncIterator trait impls. The theory is that both traits should have equivalent lowerings, modulo Stream being able to hold local borrows across yield points. This is something that is currently also not allowed in non-async gen blocks and functions, so by also not allowing it AsyncIterator is merely consistent.

Copy link
Member

@compiler-errors compiler-errors Jan 3, 2024

Choose a reason for hiding this comment

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

This is something that is currently also not allowed in non-async gen blocks and functions, so by also not allowing it AsyncIterator is merely consistent.

I don't think this is "merely consistent" -- I consider it to be a really big mistake of the Iterator trait and a major ergonomic issue that is not present in async {} blocks (so it's consistent with gen, but not async blocks). If we can avoid this for async gen from the get-go, I have no idea why we wouldn't just do so.

Copy link
Member Author

@yoshuawuyts yoshuawuyts Jan 3, 2024

Choose a reason for hiding this comment

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

edit: On second thought, let me condense what I wanted to say more briefly: I don't think we should get into the details of the different approaches in this PR, and instead focus on answering the question how we can reach a consensus.

I believe that the most productive way of achieving that is by gaining actual implementation experience. That way we can compare both approaches side by side, and decide based on that how we want to proceed.

edit: Unless you're worried that it's not possible to hold values across .await points in this formulation of AsyncIterator? Because this explicitly does support that. I agree it would be really bad if that didn't work.

@@ -13,42 +9,15 @@ use crate::task::{Context, Poll};
#[unstable(feature = "async_iterator", issue = "79024")]
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 chosen to keep the same issue for both traits, but given them different feature gates. Since stabilizing one means not stabilizing the other, this seemed appropriate to me. Or should we open separate tracking issues for both traits?

@rust-log-analyzer

This comment has been minimized.

@Kobzol
Copy link
Contributor

Kobzol commented Jan 3, 2024

Since this is just for experimentation, maybe it would be better to instead rename the AFIT-based version to Stream (or to AsyncIteratorAfit or whatever), to avoid unnecessary breakage of nightly users? There are some projects using the current AsyncIterator at the moment. Of course, nightly doesn't get stability promises, but it seems strictly better to create a new name for a new thing (and thus not break anything) than to rename the old thing and use the old name for the new thing (and thus break users of the old thing).

@taiki-e
Copy link
Member

taiki-e commented Jan 3, 2024

@Kobzol It seems confusing to name "AsyncIterator" for something with the same signature as Stream, which is widely used in the ecosystem, and "Stream" for something completely different. Also, the results you linked to seem to include quite a few irrelevant and forked repositories.

@Kobzol
Copy link
Contributor

Kobzol commented Jan 3, 2024

It seems confusing to name "AsyncIterator" for something with the same signature as Stream

That's orthogonal to what I was proposing I think. What you're describing is the current state. The Stream trait used by futures and tokio looks like the Future/poll based version (https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html), i.e. how AsyncIterator looks currently. This PR renames that back to Stream (how it was named before a previous renaming). I don't think that the correspondence to the ecosystem's trait is particularly important, or relevant to this PR. I was just trying to avoid unnecessary breakage.

Also, the results you linked to seem to include quite a few irrelevant and forked repositories.

That's true, but I also used a very simple query for a simple use statement. We can't know exactly how many people use the current trait (without doing e.g. a crater run, which would be overkill), but there are definitely some users, and I thought that it might be a good idea to not break them unnecessarily.

@kpreid
Copy link
Contributor

kpreid commented Jan 3, 2024

What seems to be missing is actual feedback from implementation and usage. So to that end I'm proposing we temporarily introduce both formulations of the "async iterator" trait.

In order to serve this goal well, I propose that the documentation for both traits should explicitly mention that they both exist and that one might try using the other one. This will encourage experimentation and feedback from people who merely use whatever they find in nightly docs without also following rust-lang development activity — who would then probably use whichever one they met first without exploring alternatives.

@yoshuawuyts
Copy link
Member Author

yoshuawuyts commented Jan 3, 2024

Is there going to be any bridging impls between the AFIT-based AsyncIterator and async gen/Stream impls? Can such a bridging impl even be written soundly?

@compiler-errors I was thinking we shouldn't - given we would only want to stabilize one of the traits, it seems preferable to me if both impls would work standalone. That way we can accurately evaluate them as competing designs without accidentally being limited by one another. I'm not sure to which degree that can be done though - I'm not a compiler expert - so please feel free to provide a reality check here.

@rust-log-analyzer

This comment has been minimized.

@yoshuawuyts
Copy link
Member Author

In order to serve this goal well, I propose that the documentation for both traits should explicitly mention that they both exist and that one might try using the other one.

@kpreid good call! - done

@rust-log-analyzer

This comment has been minimized.

@traviscross traviscross added WG-async Working group: Async & await I-async-nominated Nominated for discussion during an async working group meeting. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Jan 3, 2024
@traviscross
Copy link
Contributor

traviscross commented Jan 3, 2024

@rustbot labels +T-lang

In the same spirit that the AsyncFn* traits are a T-lang experiment and largely a T-lang concern, being as they are lang items, the close connection between this trait and lang concerns such as async gen { .. }, async gen fn, for await, etc., suggests that the lang team may have an interest in this work.

However, I'm going to withhold a T-lang nomination because...

@rustbot labels +WG-async +I-async-nominated

The async working group should first discuss this and develop a consensus on a direction here.

@guswynn
Copy link
Contributor

guswynn commented Jan 4, 2024

Its unclear to me how adding an additional nightly trait will help us gain information about which approach is preferred. A vast majority of real usages of Stream are on stable, and use the poll_next definition to great effect (and in fact, rely on its properties like Stream::next being guaranteed cancel-safe).

The main advantage of the AFIT approach (aiui) is that implementing the trait is significantly easier, but async gen fn {} and for await _ {} I believe cover those advantages. Are there ways we can get people experimenting with those, built on lower-level trait definition?

@yoshuawuyts
Copy link
Member Author

yoshuawuyts commented Jan 4, 2024

@guswynn I went into some detail about why async fn next is preferable over fn poll_next in my post here. You can skip to the conclusion for a summary of the points. The way I view it, procedurally we have roughly two paths forward with respect to async iteration:

  1. Continue having theoretical conversations about the different designs on Zulip and other places as we've been doing for the past five or so years. I've found this to be quite repetitive, and often not particularly constructive. This is because there is a lot of shared context missing between participants, and this necessarily means a lot of assumptions have to be made about what is or isn't possible.
  2. Actually write the code out, forcing us to establish shared context. This will yield two equivalent implementations which we can compare with one another. As a result we get to actually discuss the benefits and downsides of the code as it is written - and not as we imagine it would be.

This is one of the main lessons to take away from the stabilization process of async/.await. What ended up driving the decision for the lang team was to actually see two implementations of the same code written with both notations side by side. This, together with an argument map ended up being what drove the consensus process. I remember folks on T-Lang saying that in hindsight we should have just implemented both in the compiler behind different flags, so that people actually had an opportunity to try out both and compare them. Given it feels like we're in a comparable situation, I'm proposing we apply those lessons here, and actually write code. I would much prefer this over the current status quo, where it feels like we're often talking past each other and emotions regularly run high.

@guswynn
Copy link
Contributor

guswynn commented Jan 5, 2024

@yoshuawuyts I missed that blog post, thanks for the context!

Also, TIL about arguments maps (I also wasn't aware they were used previously for consensus-building in the async world). Will take a look!

@Sherlock-Holo
Copy link

AsyncIterator async fn next() use AFIT, that makes it not Send, will std lib provide a Send version AsyncIterator?

@yoshuawuyts
Copy link
Member Author

AsyncIterator async fn next() use AFIT, that makes it not Send, will std lib provide a Send version AsyncIterator?

The plan is for async functions in traits to be able to work with Send out of the box. There should be no need for duplicate definitions. So no, strictly speaking we would never want to provide a Send version of AsyncIterator, because AsyncIterator should be compatible with any Send bounds out of the box.

This is what a potential RTN feature would cover, which is an essential building block for all AFITs to work as expected.

@m-ou-se m-ou-se added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jan 10, 2024
@compiler-errors
Copy link
Member

I'm going to T-libs-api nominate this. I'd love to hear their thoughts on this experimentation and if they have any opinions on the trait split here.

@compiler-errors compiler-errors added the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Jan 11, 2024
@compiler-errors
Copy link
Member

Discussed offline briefly. I'll postpone on nominating this for T-libs-api to give a longer chance to elaborate on an WG-async consensus on how best to move forward with AsyncIterator API experimentation. I'd still love to hear libs-api feedback on this approach, but along the same lines as @traviscross's desire to nominate this for T-lang discussion (#119550 (comment)), I believe this can happen afterwards.

@rustbot labels -I-libs-api-nominated

@rustbot rustbot removed the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Jan 11, 2024
@yoshuawuyts
Copy link
Member Author

After some offline conversations I'm converting this to a draft PR until we have consensus within WG Async how we want to proceed. We may decide that this is the right direction for us, but we may want further code changes. A draft PR better reflects that the shape of the patch may not yet be final.

@yoshuawuyts yoshuawuyts marked this pull request as draft January 12, 2024 14:24
@joshtriplett
Copy link
Member

joshtriplett commented Jan 16, 2024

Given that these are nightly-only, and given that Stream already exists in the ecosystem, and given the assumption that async gen will need to do either one or the other, I don't think there's much value in keeping both around in the standard library competing with each other.

Why don't we try the experiment of switching AsyncIerator over to async fn next(), and folks who want to use Stream for comparison have a stable version in the ecosystem?

@eholk
Copy link
Contributor

eholk commented Jan 19, 2024

Its unclear to me how adding an additional nightly trait will help us gain information about which approach is preferred. A vast majority of real usages of Stream are on stable, and use the poll_next definition to great effect (and in fact, rely on its properties like Stream::next being guaranteed cancel-safe).

So one reason that Stream has been successful in the ecosystem is that until now that has been the only way to do it, at least with low overhead. Now that AFIT is stable, maybe a good path forward is to write the async fn next version as an external crate so we can get similar experience working with that in the ecosystem.

@yoshuawuyts
Copy link
Member Author

yoshuawuyts commented Jan 19, 2024

@eholk I published a crate for that in 2022 when AFITs first became available on nightly. I wrote a post announcing it was available to try out, and a follow-up nine months later evaluating it against the poll-next based design. When you say: "get similar experience", what are you suggesting we build concretely? Which questions do you hope to answer in that process?

I don't really know what we would gain from having the crates up for even longer in the ecosystem. The main questions I've been seeing revolve around the integration of the traits with various language features. And the best way I can think of answering those questions is by actually implementing them.

@Kobzol
Copy link
Contributor

Kobzol commented Jan 19, 2024

It's possible to experiment with AFIT and also poll_next out in the ecosystem, to determine how usable is the API. But what we can't test out in the ecosystem is the interaction of AFIT used as a backend of async generators/iterators. It makes sense to me to either leave AFIT in the ecosystem, or implement the actual lowering of it to async gen, so that we can actually compare it with poll_next in this regard (but that's possibly a ton of work). I'm not sure if there's a lot of value in "just" including AFIT in nightly, without the lowering part.

@joshtriplett
Copy link
Member

joshtriplett commented Jan 19, 2024

Clarifying something here: I do think we should experiment with an AFIT-based AsyncIterator in nightly in the standard library. What I was suggesting is that we don't need to keep the non-AFIT version in nightly, because we already have a non-AFIT version in the ecosystem.

@rpjohnst
Copy link
Contributor

It is also already possible to experiment with the usage and API of async gen+async fn next, even without a direct lowering implemented in the compiler, using the existing poll_next-based lowering: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=db419fc8771e85c433fd0db609fb637f

@bors
Copy link
Contributor

bors commented Jan 20, 2024

☔ The latest upstream changes (presumably #120136) made this pull request unmergeable. Please resolve the merge conflicts.

@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-llvm-16 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
GITHUB_ACTION=__run_7
GITHUB_ACTIONS=true
GITHUB_ACTION_REF=
GITHUB_ACTION_REPOSITORY=
GITHUB_ACTOR=yoshuawuyts
GITHUB_API_URL=https://api.github.com
GITHUB_BASE_REF=master
GITHUB_ENV=/home/runner/work/_temp/_runner_file_commands/set_env_12857ce6-dd04-4b06-bf52-e1f1c0cdb282
GITHUB_EVENT_NAME=pull_request
GITHUB_EVENT_NAME=pull_request
GITHUB_EVENT_PATH=/home/runner/work/_temp/_github_workflow/event.json
GITHUB_GRAPHQL_URL=https://api.github.com/graphql
GITHUB_HEAD_REF=async-iterator
GITHUB_JOB=pr
GITHUB_PATH=/home/runner/work/_temp/_runner_file_commands/add_path_12857ce6-dd04-4b06-bf52-e1f1c0cdb282
GITHUB_REF=refs/pull/119550/merge
GITHUB_REF_NAME=119550/merge
GITHUB_REF_PROTECTED=false
---
GITHUB_SERVER_URL=https://github.com
GITHUB_SHA=2afd8542a138b8485c1210bff510111234ac7945
GITHUB_STATE=/home/runner/work/_temp/_runner_file_commands/save_state_12857ce6-dd04-4b06-bf52-e1f1c0cdb282
GITHUB_STEP_SUMMARY=/home/runner/work/_temp/_runner_file_commands/step_summary_12857ce6-dd04-4b06-bf52-e1f1c0cdb282
GITHUB_TRIGGERING_ACTOR=yoshuawuyts
GITHUB_WORKFLOW_REF=rust-lang/rust/.github/workflows/ci.yml@refs/pull/119550/merge
GITHUB_WORKFLOW_SHA=2afd8542a138b8485c1210bff510111234ac7945
GITHUB_WORKSPACE=/home/runner/work/rust/rust
GOROOT_1_19_X64=/opt/hostedtoolcache/go/1.19.13/x64
---
Built container sha256:9c3c93a371e5aed5c18185b24f130d95d5140dbd72a9b325e7b6b49e521a4faa
Looks like docker image is the same as before, not uploading
https://ci-caches.rust-lang.org/docker/7ebc15c01a233894034d277c8cce4e949f4e7791f66b4727c8fb6e058a0b8171d6152e1441d677cef0653843ceeee469c097b8699b2bb74249e674f6aa1a8813
sha256:9c3c93a371e5aed5c18185b24f130d95d5140dbd72a9b325e7b6b49e521a4faa
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-16]
##[group]Clock drift check
  local time: Mon Jan 22 12:37:51 UTC 2024
  network time: Mon, 22 Jan 2024 12:37:51 GMT
  network time: Mon, 22 Jan 2024 12:37:51 GMT
##[endgroup]
sccache: Starting the server...
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-16', '--enable-llvm-link-shared', '--set', 'rust.thin-lto-import-instr-limit=10', '--set', 'change-id=99999999', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--set', 'build.optimized-compiler-builtins', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-16/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.thin-lto-import-instr-limit := 10
configure: change-id            := 99999999
---
---- [ui] tests/ui/associated-inherent-types/issue-109071.rs#with_gate stdout ----
diff of stderr:

32    |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33 LL |     fn T() -> Option<<Windows<T> as IntoIterator>::Item> {}
34    |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ LL |     fn T() -> Option<<Windows<T> as IntoStream>::Item> {}
35 
36 error: aborting due to 3 previous errors
37 



The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/associated-inherent-types/issue-109071.with_gate/issue-109071.with_gate.stderr
To only update this specific test, also pass `--test-args associated-inherent-types/issue-109071.rs`

error in revision `with_gate`: 1 errors occurred comparing output.
status: exit status: 1
status: exit status: 1
command: RUSTC_ICE="0" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/associated-inherent-types/issue-109071.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--cfg" "with_gate" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/associated-inherent-types/issue-109071.with_gate" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/associated-inherent-types/issue-109071.with_gate/auxiliary"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0637]: `&` without an explicit lifetime name cannot be used here
   |
   |
LL |     type Item = &[T]; //~ ERROR: `&` without an explicit lifetime name cannot be used here
   |                 ^ explicit lifetime name needed here
error[E0107]: missing generics for struct `Windows`
##[error]  --> /checkout/tests/ui/associated-inherent-types/issue-109071.rs:7:9
   |
   |
LL | impl<T> Windows { //~ ERROR: missing generics for struct `Windows`
   |         ^^^^^^^ expected 1 generic argument
note: struct defined here, with 1 generic parameter: `T`
  --> /checkout/tests/ui/associated-inherent-types/issue-109071.rs:5:8
   |
   |
LL | struct Windows<T> { t: T }
help: add missing generic argument
   |
   |
LL | impl<T> Windows<T> { //~ ERROR: missing generics for struct `Windows`

error[E0223]: ambiguous associated type
##[error]  --> /checkout/tests/ui/associated-inherent-types/issue-109071.rs:15:22
   |
   |
LL |     fn T() -> Option<Self::Item> {}
   |
help: use fully-qualified syntax
   |
   |
LL |     fn T() -> Option<<Windows<T> as IntoAsyncIterator>::Item> {}
Build completed unsuccessfully in 0:13:17
Build completed unsuccessfully in 0:13:17
LL |     fn T() -> Option<<Windows<T> as IntoIterator>::Item> {}
   |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LL |     fn T() -> Option<<Windows<T> as IntoStream>::Item> {}

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0107, E0223, E0637.
---
--- stderr -------------------------------
error[E0425]: cannot find value `stream` in this scope
##[error]  --> /checkout/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs:15:5
   |
LL |     stream.poll_next(ctx);

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0425`.

@bors
Copy link
Contributor

bors commented Jan 23, 2024

☔ The latest upstream changes (presumably #120251) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung
Copy link
Member

It is also already possible to experiment with the usage and API of async gen+async fn next, even without a direct lowering implemented in the compiler, using the existing poll_next-based lowering: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=db419fc8771e85c433fd0db609fb637f

Nice, I didn't know async gen was already wired up to to the AsyncIterator trait. :)

@RalfJung
Copy link
Member

What I was suggesting is that we don't need to keep the non-AFIT version in nightly, because we already have a non-AFIT version in the ecosystem.

If we want async gen blocks to be able to generate poll_next-based AsyncIterator (as is the case today), then such AsyncIterator need to be in nightly.

If we want to be able to compare the two lowerings, then it seems necessary to have both lowerings and both traits in nightly.

@traviscross
Copy link
Contributor

@rustbot labels -T-compiler -T-libs-api

This is waiting on lang work, so let's untag other teams for the moment to get it off of their agendas. We'll retag it later as appropriate.

@rustbot rustbot removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-async-nominated Nominated for discussion during an async working group meeting. S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). T-lang Relevant to the language team, which will review and decide on the PR/issue. WG-async Working group: Async & await WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)
Projects
None yet
Development

Successfully merging this pull request may close these issues.