Skip to content

Commit

Permalink
Error on using yield without also using gen on the closure
Browse files Browse the repository at this point in the history
And suggest adding the `gen` to the closure or function
  • Loading branch information
oli-obk committed Apr 11, 2024
1 parent e8a6ccc commit b692d5b
Show file tree
Hide file tree
Showing 19 changed files with 138 additions and 21 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_ast_lowering/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,6 @@ ast_lowering_underscore_expr_lhs_assign =
.label = `_` not allowed here
ast_lowering_use_angle_brackets = use angle brackets instead
ast_lowering_yield_in_closure =
`yield` can only be used in `gen` closures, functions, or blocks
.suggestion = use `gen` to make this item a coroutine
9 changes: 9 additions & 0 deletions compiler/rustc_ast_lowering/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,12 @@ pub(crate) struct AsyncBoundOnlyForFnTraits {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_lowering_yield_in_closure)]
pub(crate) struct YieldInClosure {
#[primary_span]
pub span: Span,
#[suggestion(code = "gen ", applicability = "maybe-incorrect", style = "verbose")]
pub suggestion: Option<Span>,
}
6 changes: 6 additions & 0 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use super::errors::{
};
use super::ResolverAstLoweringExt;
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
use crate::errors::YieldInClosure;
use crate::{FnDeclKind, ImplTraitPosition};
use rustc_ast::ptr::P as AstP;
use rustc_ast::*;
Expand Down Expand Up @@ -1578,7 +1579,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
.emit();
}
if self.tcx.sess.edition().at_least_rust_2024() {
let suggestion = self.current_item.map(|s| s.shrink_to_lo());
self.dcx().emit_err(YieldInClosure { span, suggestion });
}
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));

false
}
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
body,
..
}) => {
self.with_new_scopes(ident.span, |this| {
self.with_new_scopes(*fn_sig_span, |this| {
// Note: we don't need to change the return type from `T` to
// `impl Future<Output = T>` here because lower_body
// only cares about the input argument patterns in the function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/async-outside-of-await-issue-121096.rs:7:7
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
...
LL | }.await
| ^^^^^ only allowed inside `async` functions and blocks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,39 +141,39 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:68:19
|
LL | fn foo13() -> Result<(), ()> {
| ----- this is not `async`
| ---------------------------- this is not `async`
LL | let _ = bar().await();
| ^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:73:19
|
LL | fn foo14() -> Result<(), ()> {
| ----- this is not `async`
| ---------------------------- this is not `async`
LL | let _ = bar().await()?;
| ^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:78:19
|
LL | fn foo15() -> Result<(), ()> {
| ----- this is not `async`
| ---------------------------- this is not `async`
LL | let _ = bar().await;
| ^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:82:19
|
LL | fn foo16() -> Result<(), ()> {
| ----- this is not `async`
| ---------------------------- this is not `async`
LL | let _ = bar().await?;
| ^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:87:23
|
LL | fn foo() -> Result<(), ()> {
| --- this is not `async`
| -------------------------- this is not `async`
LL | let _ = bar().await?;
| ^^^^^ only allowed inside `async` functions and blocks

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/issues/issue-51751.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-51751.rs:9:27
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
LL | let result = inc(10000);
LL | let finished = result.await;
| ^^^^^ only allowed inside `async` functions and blocks
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/async-await/issues/issue-62009-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-1.rs:6:23
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
LL | async { let (); }.await;
| ^^^^^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-1.rs:10:7
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
...
LL | }.await;
| ^^^^^ only allowed inside `async` functions and blocks
Expand All @@ -19,7 +19,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-1.rs:12:16
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
...
LL | (|_| 2333).await;
| ^^^^^ only allowed inside `async` functions and blocks
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/issues/issue-62009-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-2.rs:8:23
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
LL | (async || 2333)().await;
| ^^^^^ only allowed inside `async` functions and blocks

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/non-async-enclosing-span.rs:9:28
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
LL | let x = move || {};
LL | let y = do_the_thing().await;
| ^^^^^ only allowed inside `async` functions and blocks
Expand Down
13 changes: 12 additions & 1 deletion tests/ui/coroutine/gen_block.e2024.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,24 @@ LL | let _ = || yield true;
= help: add `#![feature(coroutines)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: `yield` can only be used in `gen` closures, functions, or blocks
--> $DIR/gen_block.rs:15:16
|
LL | let _ = || yield true;
| ^^^^^^^^^^
|
help: use `gen` to make this item a coroutine
|
LL | let _ = gen || yield true;
| +++

error[E0282]: type annotations needed
--> $DIR/gen_block.rs:6:13
|
LL | let x = gen {};
| ^^^^^^ cannot infer type

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0282, E0658.
For more information about an error, try `rustc --explain E0282`.
1 change: 1 addition & 0 deletions tests/ui/coroutine/gen_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ fn main() {

let _ = || yield true; //[none]~ ERROR yield syntax is experimental
//~^ ERROR yield syntax is experimental
//[e2024]~^^ ERROR `yield` can only be used in `gen` closures, functions, or blocks
}
16 changes: 16 additions & 0 deletions tests/ui/coroutine/missing_gen_in_2024.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
//@ run-rustfix

#![feature(coroutines, gen_blocks)]

fn main() {
let _ = gen || yield;
//~^ ERROR `yield` can only be used in `gen` closures, functions, or blocks
}

gen fn _foo() {
yield;
//~^ ERROR `yield` can only be used in `gen` closures, functions, or blocks
//~| ERROR yield expression outside of coroutine literal
}
16 changes: 16 additions & 0 deletions tests/ui/coroutine/missing_gen_in_2024.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
//@ run-rustfix

#![feature(coroutines, gen_blocks)]

fn main() {
let _ = || yield;
//~^ ERROR `yield` can only be used in `gen` closures, functions, or blocks
}

fn _foo() {
yield;
//~^ ERROR `yield` can only be used in `gen` closures, functions, or blocks
//~| ERROR yield expression outside of coroutine literal
}
31 changes: 31 additions & 0 deletions tests/ui/coroutine/missing_gen_in_2024.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error: `yield` can only be used in `gen` closures, functions, or blocks
--> $DIR/missing_gen_in_2024.rs:8:16
|
LL | let _ = || yield;
| ^^^^^
|
help: use `gen` to make this item a coroutine
|
LL | let _ = gen || yield;
| +++

error: `yield` can only be used in `gen` closures, functions, or blocks
--> $DIR/missing_gen_in_2024.rs:13:5
|
LL | yield;
| ^^^^^
|
help: use `gen` to make this item a coroutine
|
LL | gen fn _foo() {
| +++

error[E0627]: yield expression outside of coroutine literal
--> $DIR/missing_gen_in_2024.rs:13:5
|
LL | yield;
| ^^^^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0627`.
26 changes: 24 additions & 2 deletions tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,19 @@ LL | yield true;
= help: add `#![feature(coroutines)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: `yield` can only be used in `gen` closures, functions, or blocks
--> $DIR/feature-gate-coroutines.rs:5:5
|
LL | yield true;
| ^^^^^^^^^^
|
help: use `gen` to make this item a coroutine
|
LL | gen fn main() {
| +++

error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:9:16
--> $DIR/feature-gate-coroutines.rs:10:16
|
LL | let _ = || yield true;
| ^^^^^^^^^^
Expand All @@ -18,13 +29,24 @@ LL | let _ = || yield true;
= help: add `#![feature(coroutines)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: `yield` can only be used in `gen` closures, functions, or blocks
--> $DIR/feature-gate-coroutines.rs:10:16
|
LL | let _ = || yield true;
| ^^^^^^^^^^
|
help: use `gen` to make this item a coroutine
|
LL | let _ = gen || yield true;
| +++

error[E0627]: yield expression outside of coroutine literal
--> $DIR/feature-gate-coroutines.rs:5:5
|
LL | yield true;
| ^^^^^^^^^^

error: aborting due to 3 previous errors
error: aborting due to 5 previous errors

Some errors have detailed explanations: E0627, E0658.
For more information about an error, try `rustc --explain E0627`.
8 changes: 4 additions & 4 deletions tests/ui/feature-gates/feature-gate-coroutines.none.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | yield true;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:9:16
--> $DIR/feature-gate-coroutines.rs:10:16
|
LL | let _ = || yield true;
| ^^^^^^^^^^
Expand All @@ -19,7 +19,7 @@ LL | let _ = || yield true;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:16:5
--> $DIR/feature-gate-coroutines.rs:18:5
|
LL | yield;
| ^^^^^
Expand All @@ -29,7 +29,7 @@ LL | yield;
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:17:5
--> $DIR/feature-gate-coroutines.rs:19:5
|
LL | yield 0;
| ^^^^^^^
Expand All @@ -50,7 +50,7 @@ LL | yield true;
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:9:16
--> $DIR/feature-gate-coroutines.rs:10:16
|
LL | let _ = || yield true;
| ^^^^^^^^^^
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/feature-gates/feature-gate-coroutines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ fn main() {
yield true; //~ ERROR yield syntax is experimental
//~^ ERROR yield expression outside of coroutine literal
//[none]~^^ ERROR yield syntax is experimental
//[e2024]~^^^ ERROR `yield` can only be used in `gen` closures, functions, or blocks

let _ = || yield true; //~ ERROR yield syntax is experimental
//[none]~^ ERROR yield syntax is experimental
//[e2024]~^^ ERROR `yield` can only be used in `gen` closures, functions, or blocks
}

#[cfg(FALSE)]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/sanitizer/cfi-coroutine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::async_iter::AsyncIterator;

#[test]
fn general_coroutine() {
let mut coro = |x: i32| {
let mut coro = gen |x: i32| {
yield x;
"done"
};
Expand Down

0 comments on commit b692d5b

Please sign in to comment.