Rollup merge of #119222 - eholk:into-async-iterator, r=compiler-errors,dtolnay

Add `IntoAsyncIterator`

This introduces the `IntoAsyncIterator` trait and uses it in the desugaring of the unstable `for await` loop syntax. This is mostly added for symmetry with `Iterator` and `IntoIterator`.

r? `@compiler-errors`

cc `@rust-lang/libs-api,` `@rust-lang/wg-async`
This commit is contained in:
Michael Goulet 2023-12-22 21:41:04 -05:00 committed by GitHub
commit eef023c806
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 93 additions and 14 deletions

View file

@ -1814,7 +1814,25 @@ fn lower_expr_for(
arena_vec![self; head],
)
}
ForLoopKind::ForAwait => self.arena.alloc(head),
// ` unsafe { Pin::new_unchecked(&mut into_async_iter(<head>)) }`
ForLoopKind::ForAwait => {
// `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
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(

View file

@ -308,6 +308,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
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;

View file

@ -135,3 +135,26 @@ pub fn async_gen_ready(t: T) -> Self {
#[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<Item = Self::Item>;
/// 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<I: AsyncIterator> IntoAsyncIterator for I {
type Item = I::Item;
type IntoAsyncIter = I;
fn into_async_iter(self) -> Self::IntoAsyncIter {
self
}
}

View file

@ -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};

View file

@ -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));
}

View file

@ -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 array;
mod ascii;
mod asserting;
mod async_iter;
mod atomic;
mod bool;
mod cell;

View file

@ -33,7 +33,14 @@ error[E0223]: ambiguous associated type
--> $DIR/issue-109071.rs:15:22
|
LL | fn T() -> Option<Self::Item> {}
| ^^^^^^^^^^ help: use fully-qualified syntax: `<Windows<T> as IntoIterator>::Item`
| ^^^^^^^^^^
|
help: use fully-qualified syntax
|
LL | fn T() -> Option<<Windows<T> as IntoAsyncIterator>::Item> {}
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LL | fn T() -> Option<<Windows<T> as IntoIterator>::Item> {}
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 4 previous errors

View file

@ -5,22 +5,17 @@ LL | let iter = core::async_iter::from_iter(0..3);
| ---- move occurs because `iter` has type `FromIter<std::ops::Range<i32>>`, 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

View file

@ -2,7 +2,14 @@ error[E0223]: ambiguous associated type
--> $DIR/suggest-trait-in-ufcs-in-hrtb.rs:5:38
|
LL | impl<S> Foo for Bar<S> where for<'a> <&'a S>::Item: Foo {}
| ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<&'a S as IntoIterator>::Item`
| ^^^^^^^^^^^^^
|
help: use fully-qualified syntax
|
LL | impl<S> Foo for Bar<S> where for<'a> <&'a S as IntoAsyncIterator>::Item: Foo {}
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LL | impl<S> Foo for Bar<S> where for<'a> <&'a S as IntoIterator>::Item: Foo {}
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 1 previous error

View file

@ -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