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 a7512ef6a24f3..db71a286b6dd0 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -135,3 +135,26 @@ impl Poll> { #[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 + #[cfg_attr(not(bootstrap), lang = "into_async_iter_into_iter")] + 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 fabdd4ee25d45..b53cf4592445c 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)] @@ -125,6 +128,7 @@ mod any; mod array; mod ascii; mod asserting; +mod async_iter; mod atomic; mod bool; mod cell; 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