Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libcore: Add iter::from_generator which is like iter::from_fn, but for coroutines instead of functions #96298

Merged
merged 1 commit into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions compiler/rustc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
#![feature(control_flow_enum)]
#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(generator_trait)]
#![feature(generators)]
#![feature(let_else)]
#![feature(hash_raw_entry)]
#![feature(hasher_prefixfree_extras)]
Expand Down Expand Up @@ -114,9 +112,6 @@ pub mod unhash;
pub use ena::undo_log;
pub use ena::unify;

use std::ops::{Generator, GeneratorState};
use std::pin::Pin;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
Expand All @@ -135,26 +130,6 @@ impl<F: Fn()> Drop for OnDrop<F> {
}
}

struct IterFromGenerator<G>(G);

impl<G: Generator<Return = ()> + Unpin> Iterator for IterFromGenerator<G> {
type Item = G::Yield;

fn next(&mut self) -> Option<Self::Item> {
match Pin::new(&mut self.0).resume(()) {
GeneratorState::Yielded(n) => Some(n),
GeneratorState::Complete(_) => None,
}
}
}

/// An adapter for turning a generator closure into an iterator, similar to `iter::from_fn`.
pub fn iter_from_generator<G: Generator<Return = ()> + Unpin>(
generator: G,
) -> impl Iterator<Item = G::Yield> {
IterFromGenerator(generator)
}

// See comments in src/librustc_middle/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#![feature(drain_filter)]
#![feature(generators)]
#![feature(generic_associated_types)]
#![feature(iter_from_generator)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(nll)]
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::rmeta::*;

use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::iter_from_generator;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
use rustc_hir as hir;
Expand Down Expand Up @@ -39,6 +38,7 @@ use rustc_span::{
use rustc_target::abi::VariantIdx;
use std::borrow::Borrow;
use std::hash::Hash;
use std::iter;
use std::num::NonZeroUsize;
use tracing::{debug, trace};

Expand Down Expand Up @@ -1134,7 +1134,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Encode this here because we don't do it in encode_def_ids.
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else {
record_array!(self.tables.children[def_id] <- iter_from_generator(|| {
record_array!(self.tables.children[def_id] <- iter::from_generator(|| {
for item_id in md.item_ids {
match tcx.hir().item(*item_id).kind {
// Foreign items are planted into their parent modules
Expand Down
6 changes: 6 additions & 0 deletions library/core/src/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,12 @@ pub use self::traits::Iterator;
)]
pub use self::range::Step;

#[unstable(
feature = "iter_from_generator",
issue = "43122",
reason = "generators are unstable"
)]
pub use self::sources::from_generator;
#[stable(feature = "iter_empty", since = "1.2.0")]
pub use self::sources::{empty, Empty};
#[stable(feature = "iter_from_fn", since = "1.34.0")]
Expand Down
8 changes: 8 additions & 0 deletions library/core/src/iter/sources.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod empty;
mod from_fn;
mod from_generator;
mod once;
mod once_with;
mod repeat;
Expand All @@ -21,6 +22,13 @@ pub use self::repeat_with::{repeat_with, RepeatWith};
#[stable(feature = "iter_from_fn", since = "1.34.0")]
pub use self::from_fn::{from_fn, FromFn};

#[unstable(
feature = "iter_from_generator",
issue = "43122",
reason = "generators are unstable"
)]
pub use self::from_generator::from_generator;

#[stable(feature = "iter_successors", since = "1.34.0")]
pub use self::successors::{successors, Successors};

Expand Down
43 changes: 43 additions & 0 deletions library/core/src/iter/sources/from_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::ops::{Generator, GeneratorState};
use crate::pin::Pin;

/// Creates a new iterator where each iteration calls the provided generator.
///
/// Similar to [`iter::from_fn`].
///
/// [`iter::from_fn`]: crate::iter::from_fn
///
/// # Examples
///
/// ```
/// #![feature(generators)]
/// #![feature(iter_from_generator)]
///
/// let it = std::iter::from_generator(|| {
/// yield 1;
/// yield 2;
/// yield 3;
/// });
/// let v: Vec<_> = it.collect();
/// assert_eq!(v, [1, 2, 3]);
/// ```
#[inline]
#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
pub fn from_generator<G: Generator<Return = ()> + Unpin>(
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be reasonable to also add a version that accepts a Pin<&mut G>, since that way immovable generators can be used as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm intrigued if there's a way to support both from the same function (is a Pin<&mut Generator<Return = ()>>: Generator<Return = ()> + Unpin?)

Either way, I think we can add that on a follow up PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not quite sure what you mean. Right now there isn't an easy way to accept both direct mutable references and pinned ones, but that would be a lovely thing.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm just wondering what changes we could make so that Pin<&mut Generator<Return = ()>> can satisfy Generator<Return = ()> + Unpin, making this function work for both versions.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh! Now I understand, I think. That's actually a good question...

Copy link
Contributor

Choose a reason for hiding this comment

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

Pretty sure that's already the case for Future (yup) so it shouldn't be hard to do it for Generator.

Copy link
Contributor

Choose a reason for hiding this comment

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

generator: G,
) -> impl Iterator<Item = G::Yield> {
FromGenerator(generator)
}

struct FromGenerator<G>(G);

impl<G: Generator<Return = ()> + Unpin> Iterator for FromGenerator<G> {
type Item = G::Yield;

fn next(&mut self) -> Option<Self::Item> {
match Pin::new(&mut self.0).resume(()) {
GeneratorState::Yielded(n) => Some(n),
GeneratorState::Complete(()) => None,
}
}
}
4 changes: 2 additions & 2 deletions src/test/ui/async-await/issue-68112.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ LL | require_send(send_fut);
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
= note: required because it appears within the type `impl Future<Output = ()>`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:11:25
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/partial-drop-partial-reinit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LL | async fn foo() {
= note: required because it appears within the type `(NotSend,)`
= note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}`
= note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
= note: required because it appears within the type `impl Future<Output = ()>`
= note: required because it appears within the type `impl Future<Output = ()>`
note: required by a bound in `gimme_send`
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/chalkify/bugs/async.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ LL | | x
LL | | }
| |_^ the trait `Generator<ResumeTy>` is not implemented for `[static generator@$DIR/async.rs:7:29: 9:2]`
|
note: required by a bound in `from_generator`
note: required by a bound in `std::future::from_generator`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `from_generator`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `std::future::from_generator`

error[E0280]: the requirement `<[static generator@$DIR/async.rs:7:29: 9:2] as Generator<ResumeTy>>::Yield == ()` is not satisfied
--> $DIR/async.rs:7:29
Expand All @@ -22,11 +22,11 @@ LL | | x
LL | | }
| |_^
|
note: required by a bound in `from_generator`
note: required by a bound in `std::future::from_generator`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^ required by this bound in `from_generator`
| ^^^^^^^^^^ required by this bound in `std::future::from_generator`

error[E0280]: the requirement `<impl Future<Output = u32> as Future>::Output == u32` is not satisfied
--> $DIR/async.rs:7:29
Expand Down