From 78a6ae7355ed741beede552e77f829dd178532fa Mon Sep 17 00:00:00 2001 From: Yosh Date: Wed, 3 Jan 2024 15:40:34 +0100 Subject: [PATCH 1/8] Rename `AsyncIterator` back to `Stream` 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. --- compiler/rustc_ast_lowering/src/expr.rs | 24 ++--- compiler/rustc_ast_lowering/src/lib.rs | 10 +- compiler/rustc_hir/src/lang_items.rs | 6 +- compiler/rustc_span/src/symbol.rs | 6 +- .../src/solve/assembly/mod.rs | 6 +- .../src/solve/normalizes_to/mod.rs | 2 +- .../src/solve/trait_goals.rs | 2 +- .../src/traits/project.rs | 14 +-- .../src/traits/select/candidate_assembly.rs | 6 +- .../src/traits/select/confirmation.rs | 8 +- .../rustc_trait_selection/src/traits/util.rs | 6 +- compiler/rustc_ty_utils/src/instance.rs | 2 +- library/alloc/src/boxed.rs | 6 +- library/alloc/src/lib.rs | 2 +- library/core/src/lib.rs | 4 +- library/core/src/panic/unwind_safe.rs | 6 +- .../src/{async_iter => stream}/from_iter.rs | 16 ++-- .../core/src/{async_iter => stream}/mod.rs | 10 +- .../async_iter.rs => stream/stream.rs} | 95 +++++++++---------- library/core/tests/async_iter/mod.rs | 17 ---- library/core/tests/lib.rs | 6 +- library/core/tests/stream/mod.rs | 17 ++++ library/std/src/lib.rs | 6 +- .../crates/ide-db/src/generated/lints.rs | 8 +- .../issue-109071.no_gate.stderr | 4 +- .../ui/async-await/feature-async-for-loop.rs | 6 +- .../async-await/feature-async-for-loop.stderr | 4 +- .../ui/async-await/for-await-consumes-iter.rs | 4 +- .../for-await-consumes-iter.stderr | 6 +- tests/ui/async-await/for-await-passthrough.rs | 8 +- tests/ui/async-await/for-await.rs | 4 +- tests/ui/coroutine/async-gen-deduce-yield.rs | 6 +- .../coroutine/async-gen-yield-ty-is-unit.rs | 8 +- tests/ui/coroutine/async_gen_fn_iter.rs | 10 +- .../suggest-trait-in-ufcs-in-hrtb.stderr | 4 +- tests/ui/typeck/issue-110052.stderr | 4 +- 36 files changed, 176 insertions(+), 177 deletions(-) rename library/core/src/{async_iter => stream}/from_iter.rs (58%) rename library/core/src/{async_iter => stream}/mod.rs (96%) rename library/core/src/{async_iter/async_iter.rs => stream/stream.rs} (56%) delete mode 100644 library/core/tests/async_iter/mod.rs create mode 100644 library/core/tests/stream/mod.rs diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index ba858d49acf6e..a9be0a36e98e5 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -776,7 +776,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let features = match await_kind { FutureKind::Future => None, - FutureKind::AsyncIterator => Some(self.allow_for_await.clone()), + FutureKind::Stream => Some(self.allow_for_await.clone()), }; let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features); let gen_future_span = self.mark_span_with_reason( @@ -830,9 +830,9 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::LangItem::FuturePoll, arena_vec![self; new_unchecked, get_context], ), - FutureKind::AsyncIterator => self.expr_call_lang_item_fn( + FutureKind::Stream => self.expr_call_lang_item_fn( span, - hir::LangItem::AsyncIteratorPollNext, + hir::LangItem::AsyncStreamPollNext, arena_vec![self; new_unchecked, get_context], ), }; @@ -924,8 +924,8 @@ impl<'hir> LoweringContext<'_, 'hir> { arena_vec![self; *expr], ), // Not needed for `for await` because we expect to have already called - // `IntoAsyncIterator::into_async_iter` on it. - FutureKind::AsyncIterator => expr, + // `IntoStream::into_stream` on it. + FutureKind::Stream => expr, }; // match { @@ -1643,7 +1643,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ForLoopKind::ForAwait => { // we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this - // to make_lowered_await with `FutureKind::AsyncIterator` which will generator + // to make_lowered_await with `FutureKind::Stream` which will generator // calls to `poll_next`. In user code, this would probably be a call to // `Pin::as_mut` but here it's easy enough to do `new_unchecked`. @@ -1657,7 +1657,7 @@ impl<'hir> LoweringContext<'_, 'hir> { )); // `unsafe { ... }` let iter = self.arena.alloc(self.expr_unsafe(iter)); - let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator); + let kind = self.make_lowered_await(head_span, iter, FutureKind::Stream); self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span }) } }; @@ -1692,12 +1692,12 @@ impl<'hir> LoweringContext<'_, 'hir> { arena_vec![self; head], ) } - // ` unsafe { Pin::new_unchecked(&mut into_async_iter()) }` + // ` unsafe { Pin::new_unchecked(&mut into_stream()) }` ForLoopKind::ForAwait => { - // `::core::async_iter::IntoAsyncIterator::into_async_iter()` + // `::core::stream::IntoStream::into_stream()` let iter = self.expr_call_lang_item_fn( head_span, - hir::LangItem::IntoAsyncIterIntoIter, + hir::LangItem::IntoAsyncStreamIntoStream, arena_vec![self; head], ); let iter = self.expr_mut_addr_of(head_span, iter); @@ -2118,7 +2118,7 @@ impl<'hir> LoweringContext<'_, 'hir> { enum FutureKind { /// We are awaiting a normal future Future, - /// We are awaiting something that's known to be an AsyncIterator (i.e. we are in the header of + /// We are awaiting something that's known to be an Stream (i.e. we are in the header of /// a `for await` loop) - AsyncIterator, + Stream, } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 92fd29c47aff3..ae4351c005af8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -131,7 +131,7 @@ struct LoweringContext<'a, 'hir> { allow_try_trait: Lrc<[Symbol]>, allow_gen_future: Lrc<[Symbol]>, - allow_async_iterator: Lrc<[Symbol]>, + allow_async_stream: Lrc<[Symbol]>, allow_for_await: Lrc<[Symbol]>, /// Mapping from generics `def_id`s to TAIT generics `def_id`s. @@ -177,10 +177,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { [sym::gen_future].into() }, - allow_for_await: [sym::async_iterator].into(), + allow_for_await: [sym::async_stream].into(), // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // interact with `gen`/`async gen` blocks - allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), + allow_async_stream: [sym::gen_future, sym::async_stream].into(), generics_def_id_map: Default::default(), host_param_id: None, } @@ -1959,7 +1959,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None), CoroutineKind::Gen { return_impl_trait_id, .. } => (return_impl_trait_id, None), CoroutineKind::AsyncGen { return_impl_trait_id, .. } => { - (return_impl_trait_id, Some(self.allow_async_iterator.clone())) + (return_impl_trait_id, Some(self.allow_async_stream.clone())) } }; @@ -2021,7 +2021,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (assoc_ty_name, trait_lang_item) = match coro { CoroutineKind::Async { .. } => (sym::Output, hir::LangItem::Future), CoroutineKind::Gen { .. } => (sym::Item, hir::LangItem::Iterator), - CoroutineKind::AsyncGen { .. } => (sym::Item, hir::LangItem::AsyncIterator), + CoroutineKind::AsyncGen { .. } => (sym::Item, hir::LangItem::AsyncStream), }; let bound_args = self.arena.alloc(hir::GenericArgs { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3f3b57ba94f98..f11c778998960 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -212,7 +212,7 @@ language_item_table! { Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); - AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); + AsyncStream, sym::async_stream, async_stream_trait, Target::Trait, GenericRequirement::Exact(0); CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None; Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1); Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; @@ -307,8 +307,8 @@ language_item_table! { Context, sym::Context, context, Target::Struct, GenericRequirement::None; 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); + AsyncStreamPollNext, sym::async_stream_poll_next, async_stream_poll_next, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(0); + IntoAsyncStreamIntoStream, sym::into_async_stream_into_stream, into_async_stream_into_stream, 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/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0b44071496ea8..a152addf78bdf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -427,8 +427,8 @@ symbols! { async_fn_in_trait, async_fn_track_caller, async_for_loop, - async_iterator, - async_iterator_poll_next, + async_stream, + async_stream_poll_next, atomic, atomic_mod, atomics, @@ -896,7 +896,7 @@ symbols! { instruction_set, integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below integral, - into_async_iter_into_iter, + into_async_stream_into_stream, into_future, into_iter, intra_doc_pointers, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index caf9470b4c646..5fb133390aac9 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -214,7 +214,7 @@ pub(super) trait GoalKind<'tcx>: goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - fn consider_builtin_async_iterator_candidate( + fn consider_builtin_async_stream_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; @@ -577,8 +577,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_future_candidate(self, goal) } else if lang_items.iterator_trait() == Some(trait_def_id) { G::consider_builtin_iterator_candidate(self, goal) - } else if lang_items.async_iterator_trait() == Some(trait_def_id) { - G::consider_builtin_async_iterator_candidate(self, goal) + } else if lang_items.async_stream_trait() == Some(trait_def_id) { + G::consider_builtin_async_stream_candidate(self, goal) } else if lang_items.coroutine_trait() == Some(trait_def_id) { G::consider_builtin_coroutine_candidate(self, goal) } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) { diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index ccee6f8eb29b9..135b316fb73d6 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -525,7 +525,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) } - fn consider_builtin_async_iterator_candidate( + fn consider_builtin_async_stream_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index be07927568446..b26fbdee33e78 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -377,7 +377,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - fn consider_builtin_async_iterator_candidate( + fn consider_builtin_async_stream_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index dd4e69efe379e..0b4419aa64f4c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1829,7 +1829,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( lang_items.coroutine_trait(), lang_items.future_trait(), lang_items.iterator_trait(), - lang_items.async_iterator_trait(), + lang_items.async_stream_trait(), lang_items.fn_trait(), lang_items.fn_mut_trait(), lang_items.fn_once_trait(), @@ -2051,8 +2051,8 @@ fn confirm_select_candidate<'cx, 'tcx>( confirm_future_candidate(selcx, obligation, data) } else if lang_items.iterator_trait() == Some(trait_def_id) { confirm_iterator_candidate(selcx, obligation, data) - } else if lang_items.async_iterator_trait() == Some(trait_def_id) { - confirm_async_iterator_candidate(selcx, obligation, data) + } else if lang_items.async_stream_trait() == Some(trait_def_id) { + confirm_async_stream_candidate(selcx, obligation, data) } else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() { if obligation.predicate.self_ty().is_closure() { confirm_closure_candidate(selcx, obligation, data) @@ -2218,7 +2218,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>( .with_addl_obligations(obligations) } -fn confirm_async_iterator_candidate<'cx, 'tcx>( +fn confirm_async_stream_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, nested: Vec>, @@ -2236,12 +2236,12 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>( gen_sig, ); - debug!(?obligation, ?gen_sig, ?obligations, "confirm_async_iterator_candidate"); + debug!(?obligation, ?gen_sig, ?obligations, "confirm_async_stream_candidate"); let tcx = selcx.tcx(); - let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, None); + let iter_def_id = tcx.require_lang_item(LangItem::AsyncStream, None); - let (trait_ref, yield_ty) = super::util::async_iterator_trait_ref_and_outputs( + let (trait_ref, yield_ty) = super::util::async_stream_trait_ref_and_outputs( tcx, iter_def_id, obligation.predicate.self_ty(), diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 54b91ab1d4d81..d053ee44bfa80 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -112,8 +112,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_future_candidates(obligation, &mut candidates); } else if lang_items.iterator_trait() == Some(def_id) { self.assemble_iterator_candidates(obligation, &mut candidates); - } else if lang_items.async_iterator_trait() == Some(def_id) { - self.assemble_async_iterator_candidates(obligation, &mut candidates); + } else if lang_items.async_stream_trait() == Some(def_id) { + self.assemble_async_stream_candidates(obligation, &mut candidates); } self.assemble_closure_candidates(obligation, &mut candidates); @@ -257,7 +257,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn assemble_async_iterator_candidates( + fn assemble_async_stream_candidates( &mut self, obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index e20bb06d7770a..2f941ef0dd3ea 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -99,7 +99,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } AsyncIteratorCandidate => { - let vtable_iterator = self.confirm_async_iterator_candidate(obligation)?; + let vtable_iterator = self.confirm_async_stream_candidate(obligation)?; ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator) } @@ -818,7 +818,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(nested) } - fn confirm_async_iterator_candidate( + fn confirm_async_stream_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result>, SelectionError<'tcx>> { @@ -830,11 +830,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("closure candidate for non-closure {:?}", obligation); }; - debug!(?obligation, ?coroutine_def_id, ?args, "confirm_async_iterator_candidate"); + debug!(?obligation, ?coroutine_def_id, ?args, "confirm_async_stream_candidate"); let gen_sig = args.as_coroutine().sig(); - let (trait_ref, _) = super::util::async_iterator_trait_ref_and_outputs( + let (trait_ref, _) = super::util::async_stream_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(), diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 19eae93df9c87..3c3493f4342a1 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -320,14 +320,14 @@ pub fn iterator_trait_ref_and_outputs<'tcx>( (trait_ref, sig.yield_ty) } -pub fn async_iterator_trait_ref_and_outputs<'tcx>( +pub fn async_stream_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, - async_iterator_def_id: DefId, + async_stream_def_id: DefId, self_ty: Ty<'tcx>, sig: ty::GenSig<'tcx>, ) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); - let trait_ref = ty::TraitRef::new(tcx, async_iterator_def_id, [self_ty]); + let trait_ref = ty::TraitRef::new(tcx, async_stream_def_id, [self_ty]); (trait_ref, sig.yield_ty) } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 81d5304b81265..de3534f9d0782 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -271,7 +271,7 @@ fn resolve_associated_item<'tcx>( debug_assert!(tcx.defaultness(trait_item_id).has_value()); Some(Instance::new(trait_item_id, rcvr_args)) } - } else if Some(trait_ref.def_id) == lang_items.async_iterator_trait() { + } else if Some(trait_ref.def_id) == lang_items.async_stream_trait() { let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { bug!() }; diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index fdf5e134f4d4c..b8657a4ce4c8e 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -147,7 +147,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::any::Any; -use core::async_iter::AsyncIterator; use core::borrow; use core::cmp::Ordering; use core::error::Error; @@ -163,6 +162,7 @@ use core::ops::{ }; use core::pin::Pin; use core::ptr::{self, NonNull, Unique}; +use core::stream::Stream; use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] @@ -2152,8 +2152,8 @@ where } } -#[unstable(feature = "async_iterator", issue = "79024")] -impl AsyncIterator for Box { +#[unstable(feature = "async_stream", issue = "79024")] +impl Stream for Box { type Item = S::Item; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 0af3ac38ee534..7df44d317c904 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -107,7 +107,7 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(assert_matches)] -#![feature(async_iterator)] +#![feature(async_stream)] #![feature(coerce_unsized)] #![feature(const_align_of_val)] #![feature(const_box)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 07720f235989b..beb25d0f8198c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -367,8 +367,6 @@ pub mod any; pub mod array; pub mod ascii; pub mod asserting; -#[unstable(feature = "async_iterator", issue = "79024")] -pub mod async_iter; pub mod cell; pub mod char; pub mod ffi; @@ -381,6 +379,8 @@ pub mod panic; pub mod panicking; pub mod pin; pub mod result; +#[unstable(feature = "async_stream", issue = "79024")] +pub mod stream; pub mod sync; pub mod fmt; diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 6a53909a8f128..1902ee659fc16 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -1,10 +1,10 @@ -use crate::async_iter::AsyncIterator; use crate::cell::UnsafeCell; use crate::fmt; use crate::future::Future; use crate::ops::{Deref, DerefMut}; use crate::pin::Pin; use crate::ptr::{NonNull, Unique}; +use crate::stream::Stream; use crate::task::{Context, Poll}; /// A marker trait which represents "panic safe" types in Rust. @@ -298,8 +298,8 @@ impl Future for AssertUnwindSafe { } } -#[unstable(feature = "async_iterator", issue = "79024")] -impl AsyncIterator for AssertUnwindSafe { +#[unstable(feature = "async_stream", issue = "79024")] +impl Stream for AssertUnwindSafe { type Item = S::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { diff --git a/library/core/src/async_iter/from_iter.rs b/library/core/src/stream/from_iter.rs similarity index 58% rename from library/core/src/async_iter/from_iter.rs rename to library/core/src/stream/from_iter.rs index 3180187afc8c9..e435b3e788432 100644 --- a/library/core/src/async_iter/from_iter.rs +++ b/library/core/src/stream/from_iter.rs @@ -1,31 +1,31 @@ use crate::pin::Pin; -use crate::async_iter::AsyncIterator; +use crate::stream::Stream; use crate::task::{Context, Poll}; -/// An async iterator that was created from iterator. +/// A stream that was created from an iterator. /// -/// This async iterator is created by the [`from_iter`] function. +/// This stream is created by the [`from_iter`] function. /// See it documentation for more. /// /// [`from_iter`]: fn.from_iter.html -#[unstable(feature = "async_iter_from_iter", issue = "81798")] +#[unstable(feature = "async_stream_from_iter", issue = "81798")] #[derive(Clone, Debug)] pub struct FromIter { iter: I, } -#[unstable(feature = "async_iter_from_iter", issue = "81798")] +#[unstable(feature = "async_stream_from_iter", issue = "81798")] impl Unpin for FromIter {} /// Converts an iterator into an async iterator. -#[unstable(feature = "async_iter_from_iter", issue = "81798")] +#[unstable(feature = "async_stream_from_iter", issue = "81798")] pub fn from_iter(iter: I) -> FromIter { FromIter { iter: iter.into_iter() } } -#[unstable(feature = "async_iter_from_iter", issue = "81798")] -impl AsyncIterator for FromIter { +#[unstable(feature = "async_stream_from_iter", issue = "81798")] +impl Stream for FromIter { type Item = I::Item; fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { diff --git a/library/core/src/async_iter/mod.rs b/library/core/src/stream/mod.rs similarity index 96% rename from library/core/src/async_iter/mod.rs rename to library/core/src/stream/mod.rs index e1f1c9075823d..a0fd243356c12 100644 --- a/library/core/src/async_iter/mod.rs +++ b/library/core/src/stream/mod.rs @@ -68,8 +68,8 @@ //! Let's make an async iterator named `Counter` which counts from `1` to `5`: //! //! ```no_run -//! #![feature(async_iterator)] -//! # use core::async_iter::AsyncIterator; +//! #![feature(async_stream)] +//! # use core::stream::Stream; //! # use core::task::{Context, Poll}; //! # use core::pin::Pin; //! @@ -91,7 +91,7 @@ //! //! // Then, we implement `AsyncIterator` for our `Counter`: //! -//! impl AsyncIterator for Counter { +//! impl Stream for Counter { //! // we will be counting with usize //! type Item = usize; //! @@ -121,8 +121,8 @@ //! warning: unused result that must be used: async iterators do nothing unless polled //! ``` -mod async_iter; mod from_iter; +mod stream; -pub use async_iter::{AsyncIterator, IntoAsyncIterator}; pub use from_iter::{from_iter, FromIter}; +pub use stream::{IntoStream, Stream}; diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/stream/stream.rs similarity index 56% rename from library/core/src/async_iter/async_iter.rs rename to library/core/src/stream/stream.rs index db71a286b6dd0..4d48be0b8bc1b 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/stream/stream.rs @@ -2,55 +2,54 @@ use crate::ops::DerefMut; use crate::pin::Pin; use crate::task::{Context, Poll}; -/// A trait for dealing with asynchronous iterators. +/// A trait for dealing with asynchronous streams. /// -/// This is the main async iterator trait. For more about the concept of async iterators +/// This is the main stream trait. For more about the concept of streams /// generally, please see the [module-level documentation]. In particular, you -/// may want to know how to [implement `AsyncIterator`][impl]. +/// may want to know how to [implement `Stream`][impl]. /// /// [module-level documentation]: index.html -/// [impl]: index.html#implementing-async-iterator -#[unstable(feature = "async_iterator", issue = "79024")] -#[must_use = "async iterators do nothing unless polled"] -#[doc(alias = "Stream")] -#[lang = "async_iterator"] -pub trait AsyncIterator { - /// The type of items yielded by the async iterator. +/// [impl]: index.html#implementing-async-stream +#[unstable(feature = "async_stream", issue = "79024")] +#[must_use = "streams do nothing unless polled"] +#[cfg_attr(not(bootstrap), lang = "async_stream")] +pub trait Stream { + /// The type of items yielded by the stream. type Item; - /// Attempt to pull out the next value of this async iterator, registering the + /// Attempt to pull out the next value of this stream, registering the /// current task for wakeup if the value is not yet available, and returning - /// `None` if the async iterator is exhausted. + /// `None` if the stream is exhausted. /// /// # Return value /// /// There are several possible return values, each indicating a distinct - /// async iterator state: + /// stream state: /// - /// - `Poll::Pending` means that this async iterator's next value is not ready + /// - `Poll::Pending` means that this stream's next value is not ready /// yet. Implementations will ensure that the current task will be notified /// when the next value may be ready. /// - /// - `Poll::Ready(Some(val))` means that the async iterator has successfully + /// - `Poll::Ready(Some(val))` means that the stream has successfully /// produced a value, `val`, and may produce further values on subsequent /// `poll_next` calls. /// - /// - `Poll::Ready(None)` means that the async iterator has terminated, and + /// - `Poll::Ready(None)` means that the stream has terminated, and /// `poll_next` should not be invoked again. /// /// # Panics /// - /// Once an async iterator has finished (returned `Ready(None)` from `poll_next`), calling its + /// Once an stream has finished (returned `Ready(None)` from `poll_next`), calling its /// `poll_next` method again may panic, block forever, or cause other kinds of - /// problems; the `AsyncIterator` trait places no requirements on the effects of + /// problems; the `Asyncstream` trait places no requirements on the effects of /// such a call. However, as the `poll_next` method is not marked `unsafe`, /// Rust's usual rules apply: calls must never cause undefined behavior /// (memory corruption, incorrect use of `unsafe` functions, or the like), - /// regardless of the async iterator's state. - #[cfg_attr(not(bootstrap), lang = "async_iterator_poll_next")] + /// regardless of the stream's state. + #[cfg_attr(not(bootstrap), lang = "async_stream_poll_next")] fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - /// Returns the bounds on the remaining length of the async iterator. + /// Returns the bounds on the remaining length of the stream. /// /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. @@ -61,12 +60,12 @@ pub trait AsyncIterator { /// /// # Implementation notes /// - /// It is not enforced that an async iterator implementation yields the declared - /// number of elements. A buggy async iterator may yield less than the lower bound + /// It is not enforced that an stream implementation yields the declared + /// number of elements. A buggy stream may yield less than the lower bound /// or more than the upper bound of elements. /// /// `size_hint()` is primarily intended to be used for optimizations such as - /// reserving space for the elements of the async iterator, but must not be + /// reserving space for the elements of the stream, but must not be /// trusted to e.g., omit bounds checks in unsafe code. An incorrect /// implementation of `size_hint()` should not lead to memory safety /// violations. @@ -75,15 +74,15 @@ pub trait AsyncIterator { /// because otherwise it would be a violation of the trait's protocol. /// /// The default implementation returns (0, [None]) which is correct for any - /// async iterator. + /// stream. #[inline] fn size_hint(&self) -> (usize, Option) { (0, None) } } -#[unstable(feature = "async_iterator", issue = "79024")] -impl AsyncIterator for &mut S { +#[unstable(feature = "async_stream", issue = "79024")] +impl Stream for &mut S { type Item = S::Item; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { @@ -95,16 +94,16 @@ impl AsyncIterator for &mut S { } } -#[unstable(feature = "async_iterator", issue = "79024")] -impl

AsyncIterator for Pin

+#[unstable(feature = "async_stream", issue = "79024")] +impl

Stream for Pin

where P: DerefMut, - P::Target: AsyncIterator, + P::Target: Stream, { - type Item = ::Item; + type Item = ::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ::poll_next(self.as_deref_mut(), cx) + ::poll_next(self.as_deref_mut(), cx) } fn size_hint(&self) -> (usize, Option) { @@ -115,7 +114,7 @@ where #[unstable(feature = "async_gen_internals", issue = "none")] impl Poll> { /// A helper function for internal desugaring -- produces `Ready(Some(t))`, - /// which corresponds to the async iterator yielding a value. + /// which corresponds to the stream yielding a value. #[unstable(feature = "async_gen_internals", issue = "none")] #[lang = "AsyncGenReady"] pub fn async_gen_ready(t: T) -> Self { @@ -123,38 +122,38 @@ impl Poll> { } /// A helper constant for internal desugaring -- produces `Pending`, - /// which corresponds to the async iterator pending on an `.await`. + /// which corresponds to the stream pending on an `.await`. #[unstable(feature = "async_gen_internals", issue = "none")] #[lang = "AsyncGenPending"] // FIXME(gen_blocks): This probably could be deduplicated. pub const PENDING: Self = Poll::Pending; /// A helper constant for internal desugaring -- produces `Ready(None)`, - /// which corresponds to the async iterator finishing its iteration. + /// which corresponds to the stream finishing its iteration. #[unstable(feature = "async_gen_internals", issue = "none")] #[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 +/// Convert something into an stream +#[unstable(feature = "async_stream", issue = "79024")] +pub trait IntoStream { + /// The type of the item yielded by the stream type Item; - /// The type of the resulting iterator - type IntoAsyncIter: AsyncIterator; + /// The type of the resulting stream + type IntoStream: Stream; - /// Converts `self` into an async iterator - #[cfg_attr(not(bootstrap), lang = "into_async_iter_into_iter")] - fn into_async_iter(self) -> Self::IntoAsyncIter; + /// Converts `self` into an stream + #[cfg_attr(not(bootstrap), lang = "into_async_stream_into_stream")] + fn into_stream(self) -> Self::IntoStream; } -#[unstable(feature = "async_iterator", issue = "79024")] -impl IntoAsyncIterator for I { +#[unstable(feature = "async_stream", issue = "79024")] +impl IntoStream for I { type Item = I::Item; - type IntoAsyncIter = I; + type IntoStream = I; - fn into_async_iter(self) -> Self::IntoAsyncIter { + fn into_stream(self) -> Self::IntoStream { self } } diff --git a/library/core/tests/async_iter/mod.rs b/library/core/tests/async_iter/mod.rs deleted file mode 100644 index 0c30bd1dfeac9..0000000000000 --- a/library/core/tests/async_iter/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -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 5946862d3e435..e793121025603 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -4,8 +4,8 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] -#![feature(async_iter_from_iter)] -#![feature(async_iterator)] +#![feature(async_stream_from_iter)] +#![feature(async_stream)] #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_align_offset)] @@ -127,7 +127,6 @@ mod any; mod array; mod ascii; mod asserting; -mod async_iter; mod atomic; mod bool; mod cell; @@ -162,6 +161,7 @@ mod simd; mod slice; mod str; mod str_lossy; +mod stream; mod task; mod time; mod tuple; diff --git a/library/core/tests/stream/mod.rs b/library/core/tests/stream/mod.rs new file mode 100644 index 0000000000000..e59fab4066b57 --- /dev/null +++ b/library/core/tests/stream/mod.rs @@ -0,0 +1,17 @@ +use core::pin::pin; +use core::stream::{self, IntoStream, Stream}; +use core::task::Poll; + +#[test] +fn into_stream() { + let stream = stream::from_iter(0..3); + let mut stream = pin!(stream.into_stream()); + + let waker = core::task::Waker::noop(); + let mut cx = &mut core::task::Context::from_waker(&waker); + + assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(Some(0))); + assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(Some(1))); + assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(Some(2))); + assert_eq!(stream.as_mut().poll_next(&mut cx), Poll::Ready(None)); +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 95ee6a9b29c9c..23d27acf3c50f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -368,7 +368,7 @@ // Only for re-exporting: // tidy-alphabetical-start #![feature(assert_matches)] -#![feature(async_iterator)] +#![feature(async_stream)] #![feature(c_variadic)] #![feature(cfg_accessible)] #![feature(cfg_eval)] @@ -480,8 +480,6 @@ pub use alloc_crate::vec; pub use core::any; #[stable(feature = "core_array", since = "1.36.0")] pub use core::array; -#[unstable(feature = "async_iterator", issue = "79024")] -pub use core::async_iter; #[stable(feature = "rust1", since = "1.0.0")] pub use core::cell; #[stable(feature = "rust1", since = "1.0.0")] @@ -534,6 +532,8 @@ pub use core::pin; pub use core::ptr; #[stable(feature = "rust1", since = "1.0.0")] pub use core::result; +#[unstable(feature = "async_stream", issue = "79024")] +pub use core::stream; #[stable(feature = "i128", since = "1.26.0")] #[allow(deprecated, deprecated_in_future)] pub use core::u128; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 1cb6ff8627a23..d88a9d27b6293 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -1779,8 +1779,8 @@ The tracking issue for this feature is: [#110011] "##, }, Lint { - label: "async_iter_from_iter", - description: r##"# `async_iter_from_iter` + label: "async_stream_from_iter", + description: r##"# `async_stream_from_iter` The tracking issue for this feature is: [#81798] @@ -1790,8 +1790,8 @@ The tracking issue for this feature is: [#81798] "##, }, Lint { - label: "async_iterator", - description: r##"# `async_iterator` + label: "async_stream", + description: r##"# `async_stream` The tracking issue for this feature is: [#79024] 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 2fceeb15ea983..ce03e5e454d92 100644 --- a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr @@ -37,10 +37,10 @@ LL | fn T() -> Option {} | help: use fully-qualified syntax | -LL | fn T() -> Option< as IntoAsyncIterator>::Item> {} - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | fn T() -> Option< as IntoIterator>::Item> {} | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | fn T() -> Option< as IntoStream>::Item> {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/async-await/feature-async-for-loop.rs b/tests/ui/async-await/feature-async-for-loop.rs index 42247dd14b0d1..ff13908523b5c 100644 --- a/tests/ui/async-await/feature-async-for-loop.rs +++ b/tests/ui/async-await/feature-async-for-loop.rs @@ -1,11 +1,11 @@ // edition:2021 // gate-test-async_for_loop -#![feature(async_iter_from_iter, async_iterator)] +#![feature(async_stream_from_iter, async_stream)] fn f() { let _ = async { - for await _i in core::async_iter::from_iter(0..3) { + for await _i in core::stream::from_iter(0..3) { //~^ ERROR `for await` loops are experimental } }; @@ -14,7 +14,7 @@ fn f() { #[cfg(FALSE)] fn g() { let _ = async { - for await _i in core::async_iter::from_iter(0..3) { + for await _i in core::stream::from_iter(0..3) { //~^ ERROR `for await` loops are experimental } }; diff --git a/tests/ui/async-await/feature-async-for-loop.stderr b/tests/ui/async-await/feature-async-for-loop.stderr index 38f75821772c8..c8609ff8fdafe 100644 --- a/tests/ui/async-await/feature-async-for-loop.stderr +++ b/tests/ui/async-await/feature-async-for-loop.stderr @@ -1,7 +1,7 @@ error[E0658]: `for await` loops are experimental --> $DIR/feature-async-for-loop.rs:8:13 | -LL | for await _i in core::async_iter::from_iter(0..3) { +LL | for await _i in core::stream::from_iter(0..3) { | ^^^^^ | = note: see issue #118898 for more information @@ -10,7 +10,7 @@ LL | for await _i in core::async_iter::from_iter(0..3) { error[E0658]: `for await` loops are experimental --> $DIR/feature-async-for-loop.rs:17:13 | -LL | for await _i in core::async_iter::from_iter(0..3) { +LL | for await _i in core::stream::from_iter(0..3) { | ^^^^^ | = note: see issue #118898 for more information diff --git a/tests/ui/async-await/for-await-consumes-iter.rs b/tests/ui/async-await/for-await-consumes-iter.rs index 65bb9e88448ff..b2035aa5a94af 100644 --- a/tests/ui/async-await/for-await-consumes-iter.rs +++ b/tests/ui/async-await/for-await-consumes-iter.rs @@ -1,12 +1,12 @@ // edition: 2021 -#![feature(async_iterator, async_iter_from_iter, const_waker, async_for_loop, noop_waker)] +#![feature(async_stream, async_stream_from_iter, const_waker, async_for_loop, noop_waker)] use std::future::Future; // a test to make sure `for await` consumes the iterator async fn real_main() { - let iter = core::async_iter::from_iter(0..3); + let iter = core::stream::from_iter(0..3); let mut count = 0; for await i in iter { } diff --git a/tests/ui/async-await/for-await-consumes-iter.stderr b/tests/ui/async-await/for-await-consumes-iter.stderr index a3e5bbcabf5d0..4e0171e8036ae 100644 --- a/tests/ui/async-await/for-await-consumes-iter.stderr +++ b/tests/ui/async-await/for-await-consumes-iter.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `iter` --> $DIR/for-await-consumes-iter.rs:14:20 | -LL | let iter = core::async_iter::from_iter(0..3); +LL | let iter = core::stream::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 { @@ -10,8 +10,8 @@ LL | for await i in iter { LL | for await i in iter { | ^^^^ value used here after move | -note: `into_async_iter` takes ownership of the receiver `self`, which moves `iter` - --> $SRC_DIR/core/src/async_iter/async_iter.rs:LL:COL +note: `into_stream` takes ownership of the receiver `self`, which moves `iter` + --> $SRC_DIR/core/src/stream/stream.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() { diff --git a/tests/ui/async-await/for-await-passthrough.rs b/tests/ui/async-await/for-await-passthrough.rs index 7fa133aaedcd7..f55c54ea190c9 100644 --- a/tests/ui/async-await/for-await-passthrough.rs +++ b/tests/ui/async-await/for-await-passthrough.rs @@ -1,13 +1,13 @@ // run-pass // edition: 2024 // compile-flags: -Zunstable-options -#![feature(async_iterator, async_iter_from_iter, const_waker, async_for_loop, noop_waker, +#![feature(async_stream, async_stream_from_iter, const_waker, async_for_loop, noop_waker, gen_blocks)] use std::future::Future; -async gen fn async_iter() -> i32 { - let iter = core::async_iter::from_iter(0..3); +async gen fn stream() -> i32 { + let iter = core::stream::from_iter(0..3); for await i in iter { yield i + 1; } @@ -16,7 +16,7 @@ async gen fn async_iter() -> i32 { // make sure a simple for await loop works async fn real_main() { let mut count = 1; - for await i in async_iter() { + for await i in stream() { assert_eq!(i, count); count += 1; } diff --git a/tests/ui/async-await/for-await.rs b/tests/ui/async-await/for-await.rs index 6345ceb0c2798..71064ee4f61d7 100644 --- a/tests/ui/async-await/for-await.rs +++ b/tests/ui/async-await/for-await.rs @@ -1,12 +1,12 @@ // run-pass // edition: 2021 -#![feature(async_iterator, async_iter_from_iter, const_waker, async_for_loop, noop_waker)] +#![feature(async_stream, async_stream_from_iter, const_waker, async_for_loop, noop_waker)] use std::future::Future; // make sure a simple for await loop works async fn real_main() { - let iter = core::async_iter::from_iter(0..3); + let iter = core::stream::from_iter(0..3); let mut count = 0; for await i in iter { assert_eq!(i, count); diff --git a/tests/ui/coroutine/async-gen-deduce-yield.rs b/tests/ui/coroutine/async-gen-deduce-yield.rs index 9ccc8ee41f667..bbe0af5255028 100644 --- a/tests/ui/coroutine/async-gen-deduce-yield.rs +++ b/tests/ui/coroutine/async-gen-deduce-yield.rs @@ -1,11 +1,11 @@ // compile-flags: --edition 2024 -Zunstable-options // check-pass -#![feature(async_iterator, gen_blocks)] +#![feature(async_stream, gen_blocks)] -use std::async_iter::AsyncIterator; +use std::stream::Stream; -fn deduce() -> impl AsyncIterator { +fn deduce() -> impl Stream { async gen { yield Default::default(); } diff --git a/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs b/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs index aac74d3eacba8..03307e24d3a6b 100644 --- a/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs +++ b/tests/ui/coroutine/async-gen-yield-ty-is-unit.rs @@ -1,17 +1,17 @@ // compile-flags: --edition 2024 -Zunstable-options // check-pass -#![feature(async_iterator, gen_blocks, noop_waker)] +#![feature(async_stream, gen_blocks, noop_waker)] -use std::{async_iter::AsyncIterator, pin::pin, task::{Context, Waker}}; +use std::{stream::Stream, pin::pin, task::{Context, Waker}}; async gen fn gen_fn() -> &'static str { yield "hello" } pub fn main() { - let async_iterator = pin!(gen_fn()); + let stream = pin!(gen_fn()); let waker = Waker::noop(); let ctx = &mut Context::from_waker(&waker); - async_iterator.poll_next(ctx); + stream.poll_next(ctx); } diff --git a/tests/ui/coroutine/async_gen_fn_iter.rs b/tests/ui/coroutine/async_gen_fn_iter.rs index ec6464d004877..070ea306843ce 100644 --- a/tests/ui/coroutine/async_gen_fn_iter.rs +++ b/tests/ui/coroutine/async_gen_fn_iter.rs @@ -2,7 +2,7 @@ // compile-flags: -Zunstable-options // run-pass -#![feature(gen_blocks, async_iterator)] +#![feature(gen_blocks, async_stream)] #![feature(noop_waker)] // make sure that a ridiculously simple async gen fn works as an iterator. @@ -45,14 +45,14 @@ async fn async_main() { use std::pin::{Pin, pin}; use std::task::*; -use std::async_iter::AsyncIterator; +use std::stream::Stream; use std::future::Future; -trait AsyncIterExt { +trait StreamExt { fn next(&mut self) -> Next<'_, Self>; } -impl AsyncIterExt for T { +impl StreamExt for T { fn next(&mut self) -> Next<'_, Self> { Next { s: self } } @@ -62,7 +62,7 @@ struct Next<'s, S: ?Sized> { s: &'s mut S, } -impl<'s, S: AsyncIterator> Future for Next<'s, S> where S: Unpin { +impl<'s, S: Stream> Future for Next<'s, S> where S: Unpin { type Output = Option; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 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 cabaa76a8867d..0688c08057714 100644 --- a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr +++ b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr @@ -6,10 +6,10 @@ LL | impl Foo for Bar where for<'a> <&'a S>::Item: Foo {} | 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 {} | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | impl Foo for Bar where for<'a> <&'a S as IntoStream>::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 5eb10d9a30e86..415e2ba62aa7e 100644 --- a/tests/ui/typeck/issue-110052.stderr +++ b/tests/ui/typeck/issue-110052.stderr @@ -6,10 +6,10 @@ LL | for<'iter> dyn Validator<<&'iter I>::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>:, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | for<'iter> dyn Validator<<&'iter I as IntoStream>::Item>:, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error From f20ec230cd6e934fd758a21570e742309b65a36d Mon Sep 17 00:00:00 2001 From: Yosh Date: Wed, 3 Jan 2024 16:21:02 +0100 Subject: [PATCH 2/8] Introduce an AFIT-based `AsyncIterator` trait 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. --- library/alloc/src/boxed.rs | 14 +++ library/alloc/src/lib.rs | 1 + library/core/src/async_iter/async_iter.rs | 87 ++++++++++++++++ library/core/src/async_iter/from_iter.rs | 35 +++++++ library/core/src/async_iter/mod.rs | 117 ++++++++++++++++++++++ library/core/src/lib.rs | 2 + library/core/src/panic/unwind_safe.rs | 14 +++ library/core/tests/async_iter/mod.rs | 18 ++++ library/core/tests/lib.rs | 5 +- library/std/src/lib.rs | 3 + 10 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 library/core/src/async_iter/async_iter.rs create mode 100644 library/core/src/async_iter/from_iter.rs create mode 100644 library/core/src/async_iter/mod.rs create mode 100644 library/core/tests/async_iter/mod.rs diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index b8657a4ce4c8e..ba2a68371000d 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -147,6 +147,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::any::Any; +use core::async_iter::AsyncIterator; use core::borrow; use core::cmp::Ordering; use core::error::Error; @@ -2165,6 +2166,19 @@ impl Stream for Box { } } +#[unstable(feature = "async_iterator", issue = "79024")] +impl AsyncIterator for Box { + type Item = I::Item; + + async fn next(&mut self) -> Option { + (&mut **self).next().await + } + + fn size_hint(&self) -> (usize, Option) { + (**self).size_hint() + } +} + impl dyn Error { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7df44d317c904..4ebfca8c6cb30 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -108,6 +108,7 @@ #![feature(ascii_char)] #![feature(assert_matches)] #![feature(async_stream)] +#![feature(async_iterator)] #![feature(coerce_unsized)] #![feature(const_align_of_val)] #![feature(const_box)] diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs new file mode 100644 index 0000000000000..ce9191db805ec --- /dev/null +++ b/library/core/src/async_iter/async_iter.rs @@ -0,0 +1,87 @@ +/// A trait for dealing with asynchronous iterators. +/// +/// This is the main async iterator trait. For more about the concept of async iterators +/// generally, please see the [module-level documentation]. In particular, you +/// may want to know how to [implement `AsyncIterator`][impl]. +/// +/// [module-level documentation]: index.html +/// [impl]: index.html#implementing-async-iterator +#[unstable(feature = "async_iterator", issue = "79024")] +#[must_use = "async iterators do nothing unless polled"] +#[doc(alias = "Stream")] +#[allow(async_fn_in_trait)] +pub trait AsyncIterator { + /// The type of items yielded by the async iterator. + type Item; + + /// Attempt to pull out the next value of this async iterator, registering the + /// current task for wakeup if the value is not yet available, and returning + /// `None` if the async iterator is exhausted. + async fn next(&mut self) -> Option; + + /// Returns the bounds on the remaining length of the async iterator. + /// + /// Specifically, `size_hint()` returns a tuple where the first element + /// is the lower bound, and the second element is the upper bound. + /// + /// The second half of the tuple that is returned is an [Option]<[usize]>. + /// A [`None`] here means that either there is no known upper bound, or the + /// upper bound is larger than [`usize`]. + /// + /// # Implementation notes + /// + /// It is not enforced that an async iterator implementation yields the declared + /// number of elements. A buggy async iterator may yield less than the lower bound + /// or more than the upper bound of elements. + /// + /// `size_hint()` is primarily intended to be used for optimizations such as + /// reserving space for the elements of the async iterator, but must not be + /// trusted to e.g., omit bounds checks in unsafe code. An incorrect + /// implementation of `size_hint()` should not lead to memory safety + /// violations. + /// + /// That said, the implementation should provide a correct estimation, + /// because otherwise it would be a violation of the trait's protocol. + /// + /// The default implementation returns (0, [None]) which is correct for any + /// async iterator. + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, None) + } +} + +#[unstable(feature = "async_iterator", issue = "79024")] +impl AsyncIterator for &mut I { + type Item = I::Item; + + async fn next(&mut self) -> Option { + (**self).next().await + } + + fn size_hint(&self) -> (usize, Option) { + (**self).size_hint() + } +} + +/// 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/from_iter.rs b/library/core/src/async_iter/from_iter.rs new file mode 100644 index 0000000000000..4573c8e804812 --- /dev/null +++ b/library/core/src/async_iter/from_iter.rs @@ -0,0 +1,35 @@ +use crate::async_iter::AsyncIterator; + +/// An async iterator that was created from iterator. +/// +/// This async iterator is created by the [`from_iter`] function. +/// See it documentation for more. +/// +/// [`from_iter`]: fn.from_iter.html +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +#[derive(Clone, Debug)] +pub struct FromIter { + iter: I, +} + +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +impl Unpin for FromIter {} + +/// Converts an iterator into an async iterator. +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +pub fn from_iter(iter: I) -> FromIter { + FromIter { iter: iter.into_iter() } +} + +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +impl AsyncIterator for FromIter { + type Item = I::Item; + + async fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} diff --git a/library/core/src/async_iter/mod.rs b/library/core/src/async_iter/mod.rs new file mode 100644 index 0000000000000..ad51084ac315a --- /dev/null +++ b/library/core/src/async_iter/mod.rs @@ -0,0 +1,117 @@ +//! Composable asynchronous iteration. +//! +//! If you've found yourself with an asynchronous collection of some kind, +//! and needed to perform an operation on the elements of said collection, +//! you'll quickly run into 'async iterators'. Async Iterators are heavily used in +//! idiomatic asynchronous Rust code, so it's worth becoming familiar with them. +//! +//! Before explaining more, let's talk about how this module is structured: +//! +//! # Organization +//! +//! This module is largely organized by type: +//! +//! * [Traits] are the core portion: these traits define what kind of async iterators +//! exist and what you can do with them. The methods of these traits are worth +//! putting some extra study time into. +//! * Functions provide some helpful ways to create some basic async iterators. +//! * Structs are often the return types of the various methods on this +//! module's traits. You'll usually want to look at the method that creates +//! the `struct`, rather than the `struct` itself. For more detail about why, +//! see '[Implementing Async Iterator](#implementing-async-iterator)'. +//! +//! [Traits]: #traits +//! +//! That's it! Let's dig into async iterators. +//! +//! # Async Iterators +//! +//! The heart and soul of this module is the [`AsyncIterator`] trait. The core of +//! [`AsyncIterator`] looks like this: +//! +//! ``` +//! trait AsyncIterator { +//! type Item; +//! async fn next(&mut self) -> Option; +//! } +//! ``` +//! +//! The future returned by `next` will yield `Some(Item)` as long as there are +//! elements, and once they've all been exhausted, will yield `None` to indicate +//! that iteration is finished. If we're waiting on something asynchronous to +//! resolve, the future will wait until the async iterator is ready to yield again. +//! +//! Individual async iterators may choose to resume iteration, and so calling `next` +//! again may or may not eventually yield `Some(Item)` again at some point. +//! +//! [`AsyncIterator`]'s full definition includes a number of other methods as well, +//! but they are default methods, built on top of [`next`], and so you get +//! them for free. +//! +//! [`next`]: AsyncIterator::next +//! +//! # Implementing Async Iterator +//! +//! Creating an async iterator of your own involves two steps: creating a `struct` to +//! hold the async iterator's state, and then implementing [`AsyncIterator`] for that +//! `struct`. +//! +//! Let's make an async iterator named `Counter` which counts from `1` to `5`: +//! +//! ```no_run +//! #![feature(async_iterator)] +//! # use core::async_iter::AsyncIterator; +//! +//! // First, the struct: +//! +//! /// An async iterator which counts from one to five +//! struct Counter { +//! count: usize, +//! } +//! +//! // we want our count to start at one, so let's add a new() method to help. +//! // This isn't strictly necessary, but is convenient. Note that we start +//! // `count` at zero, we'll see why in `next()`'s implementation below. +//! impl Counter { +//! fn new() -> Counter { +//! Counter { count: 0 } +//! } +//! } +//! +//! // Then, we implement `AsyncIterator` for our `Counter`: +//! +//! impl AsyncIterator for Counter { +//! // we will be counting with usize +//! type Item = usize; +//! +//! // next() is the only required method +//! async fn next(&mut self) -> Option { +//! // Increment our count. This is why we started at zero. +//! self.count += 1; +//! +//! // Check to see if we've finished counting or not. +//! if self.count < 6 { +//! Some(self.count) +//! } else { +//! None +//! } +//! } +//! } +//! ``` +//! +//! # Laziness +//! +//! Async iterators are *lazy*. This means that just creating an async iterator doesn't +//! _do_ a whole lot. Nothing really happens until you call `next`. This is +//! sometimes a source of confusion when creating an async iterator solely for its side +//! effects. The compiler will warn us about this kind of behavior: +//! +//! ```text +//! warning: unused result that must be used: async iterators do nothing unless polled +//! ``` + +mod async_iter; +mod from_iter; + +pub use async_iter::{AsyncIterator, IntoAsyncIterator}; +pub use from_iter::{from_iter, FromIter}; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index beb25d0f8198c..7129b8e800ed1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -367,6 +367,8 @@ pub mod any; pub mod array; pub mod ascii; pub mod asserting; +#[unstable(feature = "async_iterator", issue = "79024")] +pub mod async_iter; pub mod cell; pub mod char; pub mod ffi; diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 1902ee659fc16..48882c254d6f8 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -1,3 +1,4 @@ +use crate::async_iter::AsyncIterator; use crate::cell::UnsafeCell; use crate::fmt; use crate::future::Future; @@ -311,3 +312,16 @@ impl Stream for AssertUnwindSafe { self.0.size_hint() } } + +#[unstable(feature = "async_iterator", issue = "79024")] +impl AsyncIterator for AssertUnwindSafe { + type Item = I::Item; + + async fn next(&mut self) -> Option { + self.0.next().await + } + + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} diff --git a/library/core/tests/async_iter/mod.rs b/library/core/tests/async_iter/mod.rs new file mode 100644 index 0000000000000..4af938c24a0c1 --- /dev/null +++ b/library/core/tests/async_iter/mod.rs @@ -0,0 +1,18 @@ +use core::async_iter::{self, AsyncIterator, IntoAsyncIterator}; +use core::future::Future; +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 = async_iter.into_async_iter(); + + let waker = core::task::Waker::noop(); + let mut cx = &mut core::task::Context::from_waker(&waker); + + 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)); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e793121025603..a196bdca9d660 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -4,8 +4,10 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] -#![feature(async_stream_from_iter)] +#![feature(async_iterator)] +#![feature(async_iter_from_iter)] #![feature(async_stream)] +#![feature(async_stream_from_iter)] #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_align_offset)] @@ -127,6 +129,7 @@ mod any; mod array; mod ascii; mod asserting; +mod async_iter; mod atomic; mod bool; mod cell; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 23d27acf3c50f..d829a10310b58 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -368,6 +368,7 @@ // Only for re-exporting: // tidy-alphabetical-start #![feature(assert_matches)] +#![feature(async_iterator)] #![feature(async_stream)] #![feature(c_variadic)] #![feature(cfg_accessible)] @@ -480,6 +481,8 @@ pub use alloc_crate::vec; pub use core::any; #[stable(feature = "core_array", since = "1.36.0")] pub use core::array; +#[unstable(feature = "async_iterator", issue = "79024")] +pub use core::async_iter; #[stable(feature = "rust1", since = "1.0.0")] pub use core::cell; #[stable(feature = "rust1", since = "1.0.0")] From cf1cab9a7120e34dd85acbf014fa3534c7b3924f Mon Sep 17 00:00:00 2001 From: Yosh Date: Wed, 3 Jan 2024 17:44:05 +0100 Subject: [PATCH 3/8] Implement feedback from review --- .../rust-analyzer/crates/ide-db/src/generated/lints.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index d88a9d27b6293..1cb6ff8627a23 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -1779,8 +1779,8 @@ The tracking issue for this feature is: [#110011] "##, }, Lint { - label: "async_stream_from_iter", - description: r##"# `async_stream_from_iter` + label: "async_iter_from_iter", + description: r##"# `async_iter_from_iter` The tracking issue for this feature is: [#81798] @@ -1790,8 +1790,8 @@ The tracking issue for this feature is: [#81798] "##, }, Lint { - label: "async_stream", - description: r##"# `async_stream` + label: "async_iterator", + description: r##"# `async_iterator` The tracking issue for this feature is: [#79024] From cbf2976d43835817f8402bce4649eb54f264d69e Mon Sep 17 00:00:00 2001 From: Yosh Date: Wed, 3 Jan 2024 18:49:30 +0100 Subject: [PATCH 4/8] Implement feedback from review --- library/alloc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4ebfca8c6cb30..646c7c1646073 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -107,8 +107,8 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(assert_matches)] -#![feature(async_stream)] #![feature(async_iterator)] +#![feature(async_stream)] #![feature(coerce_unsized)] #![feature(const_align_of_val)] #![feature(const_box)] From 325f695d0a033c4725eb12329e39dabf762158e2 Mon Sep 17 00:00:00 2001 From: Yosh Date: Wed, 3 Jan 2024 19:43:10 +0100 Subject: [PATCH 5/8] update UI tests --- tests/ui/associated-inherent-types/issue-109071.no_gate.stderr | 2 ++ tests/ui/async-await/for-await-consumes-iter.stderr | 2 +- tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr | 2 ++ tests/ui/typeck/issue-110052.stderr | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) 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 ce03e5e454d92..ce32237372018 100644 --- a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr @@ -37,6 +37,8 @@ LL | fn T() -> Option {} | help: use fully-qualified syntax | +LL | fn T() -> Option< as IntoAsyncIterator>::Item> {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | fn T() -> Option< as IntoIterator>::Item> {} | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | fn T() -> Option< as IntoStream>::Item> {} diff --git a/tests/ui/async-await/for-await-consumes-iter.stderr b/tests/ui/async-await/for-await-consumes-iter.stderr index 4e0171e8036ae..d93b5245eafa9 100644 --- a/tests/ui/async-await/for-await-consumes-iter.stderr +++ b/tests/ui/async-await/for-await-consumes-iter.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `iter` --> $DIR/for-await-consumes-iter.rs:14:20 | LL | let iter = core::stream::from_iter(0..3); - | ---- move occurs because `iter` has type `FromIter>`, which does not implement the `Copy` trait + | ---- move occurs because `iter` has type `std::stream::FromIter>`, which does not implement the `Copy` trait LL | let mut count = 0; LL | for await i in iter { | ---- `iter` moved due to this method call 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 0688c08057714..60d430efcb37e 100644 --- a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr +++ b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr @@ -6,6 +6,8 @@ LL | impl Foo for Bar where for<'a> <&'a S>::Item: Foo {} | 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 {} | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | impl Foo for Bar where for<'a> <&'a S as IntoStream>::Item: Foo {} diff --git a/tests/ui/typeck/issue-110052.stderr b/tests/ui/typeck/issue-110052.stderr index 415e2ba62aa7e..ae372d96619f3 100644 --- a/tests/ui/typeck/issue-110052.stderr +++ b/tests/ui/typeck/issue-110052.stderr @@ -6,6 +6,8 @@ LL | for<'iter> dyn Validator<<&'iter I>::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>:, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | for<'iter> dyn Validator<<&'iter I as IntoStream>::Item>:, From 0148977f9fd28722bb91ae9a1194d8e460681fb0 Mon Sep 17 00:00:00 2001 From: Yosh Date: Wed, 3 Jan 2024 19:43:26 +0100 Subject: [PATCH 6/8] Implement feedback from review --- library/core/src/async_iter/async_iter.rs | 4 ++++ library/core/src/stream/stream.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index ce9191db805ec..de3d8e0d0e194 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -1,11 +1,15 @@ /// A trait for dealing with asynchronous iterators. /// +/// This trait is an alternative to the [`Stream`] trait. Both traits are +/// currently being evaluated on nightly with the intent to stabilize only one. +/// /// This is the main async iterator trait. For more about the concept of async iterators /// generally, please see the [module-level documentation]. In particular, you /// may want to know how to [implement `AsyncIterator`][impl]. /// /// [module-level documentation]: index.html /// [impl]: index.html#implementing-async-iterator +/// [`Stream`]: crate::stream::Stream #[unstable(feature = "async_iterator", issue = "79024")] #[must_use = "async iterators do nothing unless polled"] #[doc(alias = "Stream")] diff --git a/library/core/src/stream/stream.rs b/library/core/src/stream/stream.rs index 4d48be0b8bc1b..42c2da77c530a 100644 --- a/library/core/src/stream/stream.rs +++ b/library/core/src/stream/stream.rs @@ -4,12 +4,16 @@ use crate::task::{Context, Poll}; /// A trait for dealing with asynchronous streams. /// +/// This trait is an alternative to the [`AsyncIterator`] trait. Both traits are +/// currently being evaluated on nightly with the intent to stabilize only one. +/// /// This is the main stream trait. For more about the concept of streams /// generally, please see the [module-level documentation]. In particular, you /// may want to know how to [implement `Stream`][impl]. /// /// [module-level documentation]: index.html /// [impl]: index.html#implementing-async-stream +/// [`AsyncIterator`]: crate::async_iter::AsyncIterator #[unstable(feature = "async_stream", issue = "79024")] #[must_use = "streams do nothing unless polled"] #[cfg_attr(not(bootstrap), lang = "async_stream")] From d1c60dde46dd51c06946db32a9af7159e4661592 Mon Sep 17 00:00:00 2001 From: Yosh Date: Thu, 4 Jan 2024 15:34:55 +0100 Subject: [PATCH 7/8] Fix docs --- library/core/src/stream/mod.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/stream/mod.rs b/library/core/src/stream/mod.rs index a0fd243356c12..d597d4735499b 100644 --- a/library/core/src/stream/mod.rs +++ b/library/core/src/stream/mod.rs @@ -26,23 +26,23 @@ //! //! # Async Iterators //! -//! The heart and soul of this module is the [`AsyncIterator`] trait. The core of -//! [`AsyncIterator`] looks like this: +//! The heart and soul of this module is the [`Stream`] trait. The core of +//! [`Stream`] looks like this: //! //! ``` //! # use core::task::{Context, Poll}; //! # use core::pin::Pin; -//! trait AsyncIterator { +//! trait Stream { //! type Item; //! fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; //! } //! ``` //! -//! Unlike `Iterator`, `AsyncIterator` makes a distinction between the [`poll_next`] -//! method which is used when implementing an `AsyncIterator`, and a (to-be-implemented) -//! `next` method which is used when consuming an async iterator. Consumers of `AsyncIterator` +//! Unlike `Iterator`, `Stream` makes a distinction between the [`poll_next`] +//! method which is used when implementing an `Stream`, and a (to-be-implemented) +//! `next` method which is used when consuming an async iterator. Consumers of `Stream` //! only need to consider `next`, which when called, returns a future which -//! yields `Option`. +//! yields `Option`. //! //! The future returned by `next` will yield `Some(Item)` as long as there are //! elements, and once they've all been exhausted, will yield `None` to indicate @@ -52,17 +52,17 @@ //! Individual async iterators may choose to resume iteration, and so calling `next` //! again may or may not eventually yield `Some(Item)` again at some point. //! -//! [`AsyncIterator`]'s full definition includes a number of other methods as well, +//! [`Stream`]'s full definition includes a number of other methods as well, //! but they are default methods, built on top of [`poll_next`], and so you get //! them for free. //! //! [`Poll`]: super::task::Poll -//! [`poll_next`]: AsyncIterator::poll_next +//! [`poll_next`]: Stream::poll_next //! //! # Implementing Async Iterator //! //! Creating an async iterator of your own involves two steps: creating a `struct` to -//! hold the async iterator's state, and then implementing [`AsyncIterator`] for that +//! hold the async iterator's state, and then implementing [`Stream`] for that //! `struct`. //! //! Let's make an async iterator named `Counter` which counts from `1` to `5`: @@ -89,7 +89,7 @@ //! } //! } //! -//! // Then, we implement `AsyncIterator` for our `Counter`: +//! // Then, we implement `Stream` for our `Counter`: //! //! impl Stream for Counter { //! // we will be counting with usize From a51cbeeef77b666483bca36a6b282f5932e50eee Mon Sep 17 00:00:00 2001 From: Yosh Date: Fri, 5 Jan 2024 18:47:06 +0100 Subject: [PATCH 8/8] Fix doc links --- library/core/src/stream/mod.rs | 34 +++++++++++++++---------------- library/core/src/stream/stream.rs | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library/core/src/stream/mod.rs b/library/core/src/stream/mod.rs index d597d4735499b..9c1df290df7e9 100644 --- a/library/core/src/stream/mod.rs +++ b/library/core/src/stream/mod.rs @@ -2,7 +2,7 @@ //! //! If you've found yourself with an asynchronous collection of some kind, //! and needed to perform an operation on the elements of said collection, -//! you'll quickly run into 'async iterators'. Async Iterators are heavily used in +//! you'll quickly run into 'streams'. streams are heavily used in //! idiomatic asynchronous Rust code, so it's worth becoming familiar with them. //! //! Before explaining more, let's talk about how this module is structured: @@ -11,20 +11,20 @@ //! //! This module is largely organized by type: //! -//! * [Traits] are the core portion: these traits define what kind of async iterators +//! * [Traits] are the core portion: these traits define what kind of streams //! exist and what you can do with them. The methods of these traits are worth //! putting some extra study time into. -//! * Functions provide some helpful ways to create some basic async iterators. +//! * Functions provide some helpful ways to create some basic streams. //! * Structs are often the return types of the various methods on this //! module's traits. You'll usually want to look at the method that creates //! the `struct`, rather than the `struct` itself. For more detail about why, -//! see '[Implementing Async Iterator](#implementing-async-iterator)'. +//! see '[Implementing Stream](#implementing-stream)'. //! //! [Traits]: #traits //! -//! That's it! Let's dig into async iterators. +//! That's it! Let's dig into streams. //! -//! # Async Iterators +//! # Streams //! //! The heart and soul of this module is the [`Stream`] trait. The core of //! [`Stream`] looks like this: @@ -40,16 +40,16 @@ //! //! Unlike `Iterator`, `Stream` makes a distinction between the [`poll_next`] //! method which is used when implementing an `Stream`, and a (to-be-implemented) -//! `next` method which is used when consuming an async iterator. Consumers of `Stream` +//! `next` method which is used when consuming an stream. Consumers of `Stream` //! only need to consider `next`, which when called, returns a future which //! yields `Option`. //! //! The future returned by `next` will yield `Some(Item)` as long as there are //! elements, and once they've all been exhausted, will yield `None` to indicate //! that iteration is finished. If we're waiting on something asynchronous to -//! resolve, the future will wait until the async iterator is ready to yield again. +//! resolve, the future will wait until the stream is ready to yield again. //! -//! Individual async iterators may choose to resume iteration, and so calling `next` +//! Individual streams may choose to resume iteration, and so calling `next` //! again may or may not eventually yield `Some(Item)` again at some point. //! //! [`Stream`]'s full definition includes a number of other methods as well, @@ -59,13 +59,13 @@ //! [`Poll`]: super::task::Poll //! [`poll_next`]: Stream::poll_next //! -//! # Implementing Async Iterator +//! # Implementing Stream //! -//! Creating an async iterator of your own involves two steps: creating a `struct` to -//! hold the async iterator's state, and then implementing [`Stream`] for that +//! Creating an stream of your own involves two steps: creating a `struct` to +//! hold the stream's state, and then implementing [`Stream`] for that //! `struct`. //! -//! Let's make an async iterator named `Counter` which counts from `1` to `5`: +//! Let's make an stream named `Counter` which counts from `1` to `5`: //! //! ```no_run //! #![feature(async_stream)] @@ -75,7 +75,7 @@ //! //! // First, the struct: //! -//! /// An async iterator which counts from one to five +//! /// An stream which counts from one to five //! struct Counter { //! count: usize, //! } @@ -112,13 +112,13 @@ //! //! # Laziness //! -//! Async iterators are *lazy*. This means that just creating an async iterator doesn't +//! Streams are *lazy*. This means that just creating an stream doesn't //! _do_ a whole lot. Nothing really happens until you call `poll_next`. This is -//! sometimes a source of confusion when creating an async iterator solely for its side +//! sometimes a source of confusion when creating an stream solely for its side //! effects. The compiler will warn us about this kind of behavior: //! //! ```text -//! warning: unused result that must be used: async iterators do nothing unless polled +//! warning: unused result that must be used: streams do nothing unless polled //! ``` mod from_iter; diff --git a/library/core/src/stream/stream.rs b/library/core/src/stream/stream.rs index 42c2da77c530a..e22e102015fb5 100644 --- a/library/core/src/stream/stream.rs +++ b/library/core/src/stream/stream.rs @@ -12,7 +12,7 @@ use crate::task::{Context, Poll}; /// may want to know how to [implement `Stream`][impl]. /// /// [module-level documentation]: index.html -/// [impl]: index.html#implementing-async-stream +/// [impl]: index.html#implementing-stream /// [`AsyncIterator`]: crate::async_iter::AsyncIterator #[unstable(feature = "async_stream", issue = "79024")] #[must_use = "streams do nothing unless polled"]