From 8e34391d6a6e924cbea588d7e418b39aaebb6616 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 8 Dec 2023 12:33:14 -0800 Subject: [PATCH 1/3] Add IntoAsyncIterator --- library/core/src/async_iter/async_iter.rs | 22 ++++++++++++++++++++++ library/core/src/async_iter/mod.rs | 2 +- library/core/tests/async_iter/mod.rs | 17 +++++++++++++++++ library/core/tests/lib.rs | 4 ++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 library/core/tests/async_iter/mod.rs diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index ed9cb5bfea50f..9ef74991dbbe0 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -135,3 +135,25 @@ impl Poll> { #[cfg_attr(not(bootstrap), lang = "AsyncGenFinished")] pub const FINISHED: Self = Poll::Ready(None); } + +/// Convert something into an async iterator +#[unstable(feature = "async_iterator", issue = "79024")] +pub trait IntoAsyncIterator { + /// The type of the item yielded by the iterator + type Item; + /// The type of the resulting iterator + type IntoAsyncIter: AsyncIterator; + + /// Converts `self` into an async iterator + fn into_async_iter(self) -> Self::IntoAsyncIter; +} + +#[unstable(feature = "async_iterator", issue = "79024")] +impl IntoAsyncIterator for I { + type Item = I::Item; + type IntoAsyncIter = I; + + fn into_async_iter(self) -> Self::IntoAsyncIter { + self + } +} diff --git a/library/core/src/async_iter/mod.rs b/library/core/src/async_iter/mod.rs index 0c6f637711b37..e1f1c9075823d 100644 --- a/library/core/src/async_iter/mod.rs +++ b/library/core/src/async_iter/mod.rs @@ -124,5 +124,5 @@ mod async_iter; mod from_iter; -pub use async_iter::AsyncIterator; +pub use async_iter::{AsyncIterator, IntoAsyncIterator}; pub use from_iter::{from_iter, FromIter}; diff --git a/library/core/tests/async_iter/mod.rs b/library/core/tests/async_iter/mod.rs new file mode 100644 index 0000000000000..0c30bd1dfeac9 --- /dev/null +++ b/library/core/tests/async_iter/mod.rs @@ -0,0 +1,17 @@ +use core::async_iter::{self, AsyncIterator, IntoAsyncIterator}; +use core::pin::pin; +use core::task::Poll; + +#[test] +fn into_async_iter() { + let async_iter = async_iter::from_iter(0..3); + let mut async_iter = pin!(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)); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c531117bed5ad..c651391ff844e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -4,6 +4,8 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] +#![feature(async_iter_from_iter)] +#![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_align_offset)] @@ -55,6 +57,7 @@ #![feature(maybe_uninit_write_slice)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(min_specialization)] +#![feature(noop_waker)] #![feature(numfmt)] #![feature(num_midpoint)] #![feature(isqrt)] @@ -126,6 +129,7 @@ mod any; mod array; mod ascii; mod asserting; +mod async_iter; mod atomic; mod bool; mod cell; From acb6f17adf78f79db10ec189d719380d35cacee7 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 18 Dec 2023 17:08:19 -0800 Subject: [PATCH 2/3] Use `IntoAsyncIterator` in `for await` loop desugaring --- compiler/rustc_ast_lowering/src/expr.rs | 20 +++++++++++++++++++- compiler/rustc_hir/src/lang_items.rs | 1 + library/core/src/async_iter/async_iter.rs | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2d61f3bceec73..a384601a24dd4 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1803,7 +1803,25 @@ impl<'hir> LoweringContext<'_, 'hir> { arena_vec![self; head], ) } - ForLoopKind::ForAwait => self.arena.alloc(head), + // ` unsafe { Pin::new_unchecked(&mut into_async_iter()) }` + ForLoopKind::ForAwait => { + // `::core::async_iter::IntoAsyncIterator::into_async_iter()` + let iter = self.expr_call_lang_item_fn( + head_span, + hir::LangItem::IntoAsyncIterIntoIter, + arena_vec![self; head], + ); + let iter = self.expr_mut_addr_of(head_span, iter); + // `Pin::new_unchecked(...)` + let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut( + head_span, + hir::LangItem::PinNewUnchecked, + arena_vec![self; iter], + )); + // `unsafe { ... }` + let iter = self.arena.alloc(self.expr_unsafe(iter)); + iter + } }; let match_expr = self.arena.alloc(self.expr_match( diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 7691cd11c4f55..3f3b57ba94f98 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -308,6 +308,7 @@ language_item_table! { FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; AsyncIteratorPollNext, sym::async_iterator_poll_next, async_iterator_poll_next, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(0); + IntoAsyncIterIntoIter, sym::into_async_iter_into_iter, into_async_iter_into_iter, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(0); Option, sym::Option, option_type, Target::Enum, GenericRequirement::None; OptionSome, sym::Some, option_some_variant, Target::Variant, GenericRequirement::None; diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index 9ef74991dbbe0..d5282514cc61b 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -145,6 +145,7 @@ pub trait IntoAsyncIterator { type IntoAsyncIter: AsyncIterator; /// Converts `self` into an async iterator + #[cfg_attr(not(bootstrap), lang = "into_async_iter_into_iter")] fn into_async_iter(self) -> Self::IntoAsyncIter; } From aaa3e7642b950f9749ec2c19da86f4f29fcfd2f0 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 19 Dec 2023 12:22:41 -0800 Subject: [PATCH 3/3] Update test outputs --- .../issue-109071.no_gate.stderr | 9 ++++++++- tests/ui/async-await/for-await-consumes-iter.stderr | 13 ++++--------- .../suggest-trait-in-ufcs-in-hrtb.stderr | 9 ++++++++- tests/ui/typeck/issue-110052.stderr | 9 ++++++++- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr index 866a53f57fc23..2fceeb15ea983 100644 --- a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr @@ -33,7 +33,14 @@ error[E0223]: ambiguous associated type --> $DIR/issue-109071.rs:15:22 | LL | fn T() -> Option {} - | ^^^^^^^^^^ help: use fully-qualified syntax: ` as IntoIterator>::Item` + | ^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | fn T() -> Option< as IntoAsyncIterator>::Item> {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | fn T() -> Option< as IntoIterator>::Item> {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/async-await/for-await-consumes-iter.stderr b/tests/ui/async-await/for-await-consumes-iter.stderr index 48b2e8a51d830..a3e5bbcabf5d0 100644 --- a/tests/ui/async-await/for-await-consumes-iter.stderr +++ b/tests/ui/async-await/for-await-consumes-iter.stderr @@ -5,22 +5,17 @@ LL | let iter = core::async_iter::from_iter(0..3); | ---- move occurs because `iter` has type `FromIter>`, which does not implement the `Copy` trait LL | let mut count = 0; LL | for await i in iter { - | ------------------- - | | | - | | value moved here - | inside of this loop + | ---- `iter` moved due to this method call ... LL | for await i in iter { | ^^^^ value used here after move | -help: consider cloning the value if the performance cost is acceptable +note: `into_async_iter` takes ownership of the receiver `self`, which moves `iter` + --> $SRC_DIR/core/src/async_iter/async_iter.rs:LL:COL +help: you can `clone` the value and consume it, but this might not be your desired behavior | LL | for await i in iter.clone() { | ++++++++ -help: borrow this binding in the pattern to avoid moving the value - | -LL | for await i in ref iter { - | +++ error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr index c0f0c41422736..cabaa76a8867d 100644 --- a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr +++ b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr @@ -2,7 +2,14 @@ error[E0223]: ambiguous associated type --> $DIR/suggest-trait-in-ufcs-in-hrtb.rs:5:38 | LL | impl Foo for Bar where for<'a> <&'a S>::Item: Foo {} - | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<&'a S as IntoIterator>::Item` + | ^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | impl Foo for Bar where for<'a> <&'a S as IntoAsyncIterator>::Item: Foo {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | impl Foo for Bar where for<'a> <&'a S as IntoIterator>::Item: Foo {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/typeck/issue-110052.stderr b/tests/ui/typeck/issue-110052.stderr index b25b6c0c0b78c..5eb10d9a30e86 100644 --- a/tests/ui/typeck/issue-110052.stderr +++ b/tests/ui/typeck/issue-110052.stderr @@ -2,7 +2,14 @@ error[E0223]: ambiguous associated type --> $DIR/issue-110052.rs:6:30 | LL | for<'iter> dyn Validator<<&'iter I>::Item>:, - | ^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<&'iter I as IntoIterator>::Item` + | ^^^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | for<'iter> dyn Validator<<&'iter I as IntoAsyncIterator>::Item>:, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | for<'iter> dyn Validator<<&'iter I as IntoIterator>::Item>:, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error