Error on using yield without also using #[coroutine] on the closure
And suggest adding the `#[coroutine]` to the closure
This commit is contained in:
parent
a589632dad
commit
aef0f4024a
279 changed files with 1290 additions and 886 deletions
|
|
@ -26,13 +26,13 @@ tweaks to the overall design.
|
|||
A syntactical example of a coroutine is:
|
||||
|
||||
```rust
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::ops::{Coroutine, CoroutineState};
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
let mut coroutine = || {
|
||||
let mut coroutine = #[coroutine] || {
|
||||
yield 1;
|
||||
return "foo"
|
||||
};
|
||||
|
|
@ -48,7 +48,8 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
Coroutines are closure-like literals which can contain a `yield` statement. The
|
||||
Coroutines are closure-like literals which are annotated with `#[coroutine]`
|
||||
and can contain a `yield` statement. The
|
||||
`yield` statement takes an optional expression of a value to yield out of the
|
||||
coroutine. All coroutine literals implement the `Coroutine` trait in the
|
||||
`std::ops` module. The `Coroutine` trait has one main method, `resume`, which
|
||||
|
|
@ -58,13 +59,13 @@ An example of the control flow of coroutines is that the following example
|
|||
prints all numbers in order:
|
||||
|
||||
```rust
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::ops::Coroutine;
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
let mut coroutine = || {
|
||||
let mut coroutine = #[coroutine] || {
|
||||
println!("2");
|
||||
yield;
|
||||
println!("4");
|
||||
|
|
@ -78,9 +79,9 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
At this time the main intended use case of coroutines is an implementation
|
||||
primitive for async/await syntax, but coroutines will likely be extended to
|
||||
ergonomic implementations of iterators and other primitives in the future.
|
||||
At this time the main use case of coroutines is an implementation
|
||||
primitive for `async`/`await` and `gen` syntax, but coroutines
|
||||
will likely be extended to other primitives in the future.
|
||||
Feedback on the design and usage is always appreciated!
|
||||
|
||||
### The `Coroutine` trait
|
||||
|
|
@ -163,14 +164,14 @@ which point all state is saved off in the coroutine and a value is returned.
|
|||
Let's take a look at an example to see what's going on here:
|
||||
|
||||
```rust
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::ops::Coroutine;
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
let ret = "foo";
|
||||
let mut coroutine = move || {
|
||||
let mut coroutine = #[coroutine] move || {
|
||||
yield 1;
|
||||
return ret
|
||||
};
|
||||
|
|
@ -183,7 +184,7 @@ fn main() {
|
|||
This coroutine literal will compile down to something similar to:
|
||||
|
||||
```rust
|
||||
#![feature(arbitrary_self_types, coroutines, coroutine_trait)]
|
||||
#![feature(arbitrary_self_types, coroutine_trait)]
|
||||
|
||||
use std::ops::{Coroutine, CoroutineState};
|
||||
use std::pin::Pin;
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ each one organized by a "feature flag." That is, when using an unstable
|
|||
feature of Rust, you must use a flag, like this:
|
||||
|
||||
```rust
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::ops::{Coroutine, CoroutineState};
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
let mut coroutine = || {
|
||||
let mut coroutine = #[coroutine] || {
|
||||
yield 1;
|
||||
return "foo"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
// Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562
|
||||
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
fn main() {
|
||||
let _ = || {
|
||||
let _ = #[coroutine] || {
|
||||
yield;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![feature(coroutines)]
|
||||
#![warn(clippy::large_futures)]
|
||||
#![allow(clippy::never_loop)]
|
||||
#![allow(clippy::future_not_send)]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#![feature(coroutines)]
|
||||
#![warn(clippy::large_futures)]
|
||||
#![allow(clippy::never_loop)]
|
||||
#![allow(clippy::future_not_send)]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: large future with a size of 16385 bytes
|
||||
--> tests/ui/large_futures.rs:11:9
|
||||
--> tests/ui/large_futures.rs:10:9
|
||||
|
|
||||
LL | big_fut([0u8; 1024 * 16]).await;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))`
|
||||
|
|
@ -8,37 +8,37 @@ LL | big_fut([0u8; 1024 * 16]).await;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::large_futures)]`
|
||||
|
||||
error: large future with a size of 16386 bytes
|
||||
--> tests/ui/large_futures.rs:15:5
|
||||
--> tests/ui/large_futures.rs:14:5
|
||||
|
|
||||
LL | f.await
|
||||
| ^ help: consider `Box::pin` on it: `Box::pin(f)`
|
||||
|
||||
error: large future with a size of 16387 bytes
|
||||
--> tests/ui/large_futures.rs:20:9
|
||||
--> tests/ui/large_futures.rs:19:9
|
||||
|
|
||||
LL | wait().await;
|
||||
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
|
||||
|
||||
error: large future with a size of 16387 bytes
|
||||
--> tests/ui/large_futures.rs:25:13
|
||||
--> tests/ui/large_futures.rs:24:13
|
||||
|
|
||||
LL | wait().await;
|
||||
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
|
||||
|
||||
error: large future with a size of 65540 bytes
|
||||
--> tests/ui/large_futures.rs:33:5
|
||||
--> tests/ui/large_futures.rs:32:5
|
||||
|
|
||||
LL | foo().await;
|
||||
| ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())`
|
||||
|
||||
error: large future with a size of 49159 bytes
|
||||
--> tests/ui/large_futures.rs:35:5
|
||||
--> tests/ui/large_futures.rs:34:5
|
||||
|
|
||||
LL | calls_fut(fut).await;
|
||||
| ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))`
|
||||
|
||||
error: large future with a size of 65540 bytes
|
||||
--> tests/ui/large_futures.rs:48:5
|
||||
--> tests/ui/large_futures.rs:47:5
|
||||
|
|
||||
LL | / async {
|
||||
LL | |
|
||||
|
|
@ -59,7 +59,7 @@ LL + })
|
|||
|
|
||||
|
||||
error: large future with a size of 65540 bytes
|
||||
--> tests/ui/large_futures.rs:60:13
|
||||
--> tests/ui/large_futures.rs:59:13
|
||||
|
|
||||
LL | / async {
|
||||
LL | | let x = [0i32; 1024 * 16];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//@aux-build:proc_macros.rs
|
||||
#![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
|
||||
#![warn(clippy::redundant_locals)]
|
||||
#![feature(async_closure, coroutines)]
|
||||
#![feature(async_closure, coroutines, stmt_expr_attributes)]
|
||||
|
||||
extern crate proc_macros;
|
||||
use proc_macros::{external, with_span};
|
||||
|
|
@ -191,11 +191,11 @@ fn issue12225() {
|
|||
let v4 = v4;
|
||||
dbg!(&v4);
|
||||
});
|
||||
assert_static(static || {
|
||||
assert_static(#[coroutine] static || {
|
||||
let v5 = v5;
|
||||
yield;
|
||||
});
|
||||
assert_static(|| {
|
||||
assert_static(#[coroutine] || {
|
||||
let v6 = v6;
|
||||
yield;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::{
|
||||
ops::{Coroutine, CoroutineState},
|
||||
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
};
|
||||
|
||||
fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
|
||||
static move || {
|
||||
#[coroutine] static move || {
|
||||
let mut num = 0;
|
||||
let num = &mut num;
|
||||
*num += 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//@revisions: stack tree
|
||||
//@[tree]compile-flags: -Zmiri-tree-borrows
|
||||
#![feature(coroutines, coroutine_trait, never_type)]
|
||||
#![feature(coroutines, coroutine_trait, never_type, stmt_expr_attributes)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::mem::ManuallyDrop;
|
||||
|
|
@ -43,9 +43,9 @@ fn basic() {
|
|||
panic!()
|
||||
}
|
||||
|
||||
finish(1, false, || yield 1);
|
||||
finish(1, false, #[coroutine] || yield 1);
|
||||
|
||||
finish(3, false, || {
|
||||
finish(3, false, #[coroutine] || {
|
||||
let mut x = 0;
|
||||
yield 1;
|
||||
x += 1;
|
||||
|
|
@ -55,27 +55,27 @@ fn basic() {
|
|||
assert_eq!(x, 2);
|
||||
});
|
||||
|
||||
finish(7 * 8 / 2, false, || {
|
||||
finish(7 * 8 / 2, false, #[coroutine] || {
|
||||
for i in 0..8 {
|
||||
yield i;
|
||||
}
|
||||
});
|
||||
|
||||
finish(1, false, || {
|
||||
finish(1, false, #[coroutine] || {
|
||||
if true {
|
||||
yield 1;
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
finish(1, false, || {
|
||||
finish(1, false, #[coroutine] || {
|
||||
if false {
|
||||
} else {
|
||||
yield 1;
|
||||
}
|
||||
});
|
||||
|
||||
finish(2, false, || {
|
||||
finish(2, false, #[coroutine] || {
|
||||
if {
|
||||
yield 1;
|
||||
false
|
||||
|
|
@ -88,7 +88,7 @@ fn basic() {
|
|||
|
||||
// also test self-referential coroutines
|
||||
assert_eq!(
|
||||
finish(5, true, static || {
|
||||
finish(5, true, #[coroutine] static || {
|
||||
let mut x = 5;
|
||||
let y = &mut x;
|
||||
*y = 5;
|
||||
|
|
@ -99,7 +99,7 @@ fn basic() {
|
|||
10
|
||||
);
|
||||
assert_eq!(
|
||||
finish(5, true, || {
|
||||
finish(5, true, #[coroutine] || {
|
||||
let mut x = Box::new(5);
|
||||
let y = &mut *x;
|
||||
*y = 5;
|
||||
|
|
@ -111,7 +111,7 @@ fn basic() {
|
|||
);
|
||||
|
||||
let b = true;
|
||||
finish(1, false, || {
|
||||
finish(1, false, #[coroutine] || {
|
||||
yield 1;
|
||||
if b {
|
||||
return;
|
||||
|
|
@ -123,7 +123,7 @@ fn basic() {
|
|||
drop(x);
|
||||
});
|
||||
|
||||
finish(3, false, || {
|
||||
finish(3, false, #[coroutine] || {
|
||||
yield 1;
|
||||
#[allow(unreachable_code)]
|
||||
let _x: (String, !) = (String::new(), {
|
||||
|
|
@ -172,7 +172,7 @@ fn smoke_resume_arg() {
|
|||
}
|
||||
|
||||
drain(
|
||||
&mut |mut b| {
|
||||
&mut #[coroutine] |mut b| {
|
||||
while b != 0 {
|
||||
b = yield (b + 1);
|
||||
}
|
||||
|
|
@ -181,21 +181,21 @@ fn smoke_resume_arg() {
|
|||
vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))],
|
||||
);
|
||||
|
||||
expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))]));
|
||||
expect_drops(2, || drain(&mut #[coroutine] |a| yield a, vec![(DropMe, Yielded(DropMe))]));
|
||||
|
||||
expect_drops(6, || {
|
||||
drain(
|
||||
&mut |a| yield yield a,
|
||||
&mut #[coroutine] |a| yield yield a,
|
||||
vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))],
|
||||
)
|
||||
});
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))]));
|
||||
expect_drops(2, || drain(&mut #[coroutine] |a| yield return a, vec![(DropMe, Complete(DropMe))]));
|
||||
|
||||
expect_drops(2, || {
|
||||
drain(
|
||||
&mut |a: DropMe| {
|
||||
&mut #[coroutine] |a: DropMe| {
|
||||
if false { yield () } else { a }
|
||||
},
|
||||
vec![(DropMe, Complete(DropMe))],
|
||||
|
|
@ -205,7 +205,7 @@ fn smoke_resume_arg() {
|
|||
expect_drops(4, || {
|
||||
drain(
|
||||
#[allow(unused_assignments, unused_variables)]
|
||||
&mut |mut a: DropMe| {
|
||||
&mut #[coroutine] |mut a: DropMe| {
|
||||
a = yield;
|
||||
a = yield;
|
||||
a = yield;
|
||||
|
|
@ -228,7 +228,7 @@ fn uninit_fields() {
|
|||
}
|
||||
|
||||
fn run<T>(x: bool, y: bool) {
|
||||
let mut c = || {
|
||||
let mut c = #[coroutine] || {
|
||||
if x {
|
||||
let _a: T;
|
||||
if y {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/148:
|
||||
// this fails when Stacked Borrows is strictly applied even to `!Unpin` types.
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::{
|
||||
ops::{Coroutine, CoroutineState},
|
||||
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
};
|
||||
|
||||
fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
|
||||
static move || {
|
||||
#[coroutine] static move || {
|
||||
let mut num = 0;
|
||||
let num = &mut num;
|
||||
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ fn test_coroutine() {
|
|||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
let coroutine = #[track_caller] |arg: String| {
|
||||
let coroutine = #[track_caller] #[coroutine] |arg: String| {
|
||||
yield ("first", arg.clone(), Location::caller());
|
||||
yield ("second", arg.clone(), Location::caller());
|
||||
};
|
||||
|
|
@ -255,7 +255,7 @@ fn test_coroutine() {
|
|||
assert_eq!(mono_loc.column(), 42);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let non_tracked_coroutine = || { yield Location::caller(); };
|
||||
let non_tracked_coroutine = #[coroutine] || { yield Location::caller(); };
|
||||
let non_tracked_line = line!() - 1; // This is the line of the coroutine, not its caller
|
||||
let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) {
|
||||
CoroutineState::Yielded(val) => val,
|
||||
|
|
@ -263,7 +263,7 @@ fn test_coroutine() {
|
|||
};
|
||||
assert_eq!(non_tracked_loc.file(), file!());
|
||||
assert_eq!(non_tracked_loc.line(), non_tracked_line);
|
||||
assert_eq!(non_tracked_loc.column(), 44);
|
||||
assert_eq!(non_tracked_loc.column(), 57);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -3869,7 +3869,7 @@ use std::ops::{Coroutine, CoroutineState};
|
|||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
let mut coroutine = || {
|
||||
let mut coroutine = #[coroutine] || {
|
||||
yield 1;
|
||||
return "foo"
|
||||
};
|
||||
|
|
@ -3901,7 +3901,7 @@ use std::ops::Coroutine;
|
|||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
let mut coroutine = || {
|
||||
let mut coroutine = #[coroutine] || {
|
||||
println!("2");
|
||||
yield;
|
||||
println!("4");
|
||||
|
|
@ -4007,7 +4007,7 @@ use std::pin::Pin;
|
|||
|
||||
fn main() {
|
||||
let ret = "foo";
|
||||
let mut coroutine = move || {
|
||||
let mut coroutine = #[coroutine] move || {
|
||||
yield 1;
|
||||
return ret
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#![feature(coroutines)]
|
||||
|
||||
unsafe fn foo() {
|
||||
let mut ga = static || {
|
||||
let mut ga = #[coroutine]
|
||||
static || {
|
||||
yield 1;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#![feature(coroutines)]
|
||||
|
||||
unsafe fn foo() {
|
||||
let mut ga = static || {
|
||||
let mut ga = #[coroutine]
|
||||
static || {
|
||||
yield 1;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue