From e8a6ccc7ce9e6a549e1bdd34a12c833fd29f75f9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 11 Apr 2024 12:48:32 +0000 Subject: [PATCH] Add explicit syntax for coroutines instead of relying on closures having `yield` expressions --- compiler/rustc_ast_lowering/src/expr.rs | 19 +++++++++++++---- compiler/rustc_parse/src/parser/expr.rs | 21 ++++++++++--------- tests/ui/coroutine/addassign-yield.rs | 10 +++++---- tests/ui/coroutine/borrow-in-tail-expr.rs | 6 ++++-- .../ui/coroutine/derived-drop-parent-expr.rs | 10 +++++---- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 389cf4e313216..3bbd4514a343c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -201,18 +201,18 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span, fn_arg_span, }) => match coroutine_kind { - Some(coroutine_kind) => self.lower_expr_coroutine_closure( + Some(kind @ CoroutineKind::Async { .. }) => self.lower_expr_coroutine_closure( binder, *capture_clause, e.id, hir_id, - *coroutine_kind, + *kind, fn_decl, body, *fn_decl_span, *fn_arg_span, ), - None => self.lower_expr_closure( + _ => self.lower_expr_closure( binder, *capture_clause, e.id, @@ -222,6 +222,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, *fn_decl_span, *fn_arg_span, + *coroutine_kind, ), }, ExprKind::Gen(capture_clause, block, genblock_kind) => { @@ -963,12 +964,22 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Expr, fn_decl_span: Span, fn_arg_span: Span, + coroutine_kind: Option, ) -> hir::ExprKind<'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { - let mut coroutine_kind = None; + let mut coroutine_kind = coroutine_kind.map(|k| match k { + CoroutineKind::Async { span, .. } => { + span_bug!(span, "should have used lower_expr_coroutine_closure") + } + CoroutineKind::Gen { .. } => hir::CoroutineKind::Coroutine(Movability::Movable), + CoroutineKind::AsyncGen { span, .. } => { + span_bug!(span, "async gen closures are not supported yet") + } + }); let body_id = this.lower_fn_body(decl, |this| { + this.coroutine_kind = coroutine_kind; let e = this.lower_expr_mut(body); coroutine_kind = this.coroutine_kind; e diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 012285e4644d6..588e723c2f981 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1522,17 +1522,18 @@ impl<'a> Parser<'a> { Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore)) } else if this.token.uninterpolated_span().at_least_rust_2018() { // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly. - if this.token.uninterpolated_span().at_least_rust_2024() - // check for `gen {}` and `gen move {}` - // or `async gen {}` and `async gen move {}` - && (this.is_gen_block(kw::Gen, 0) - || (this.check_keyword(kw::Async) && this.is_gen_block(kw::Gen, 1))) - { - // FIXME: (async) gen closures aren't yet parsed. - this.parse_gen_block() - } else if this.check_keyword(kw::Async) { + if this.check_keyword(kw::Async) { // FIXME(gen_blocks): Parse `gen async` and suggest swap - if this.is_gen_block(kw::Async, 0) { + if this.is_gen_block(kw::Async, 0) || this.is_gen_block(kw::Gen, 1) { + // Check for `async {` and `async move {`, + this.parse_gen_block() + } else { + this.parse_expr_closure() + } + } else if this.check_keyword(kw::Gen) + && this.token.uninterpolated_span().at_least_rust_2024() + { + if this.is_gen_block(kw::Gen, 0) { // Check for `async {` and `async move {`, this.parse_gen_block() } else { diff --git a/tests/ui/coroutine/addassign-yield.rs b/tests/ui/coroutine/addassign-yield.rs index 8718e73512f71..cc3df7a1bf4c9 100644 --- a/tests/ui/coroutine/addassign-yield.rs +++ b/tests/ui/coroutine/addassign-yield.rs @@ -1,25 +1,27 @@ //@ run-pass +//@ edition: 2024 +//@ compile-flags: -Zunstable-options // Regression test for broken MIR error (#61442) // Due to the two possible evaluation orders for // a '+=' expression (depending on whether or not the 'AddAssign' trait // is being used), we were failing to account for all types that might // possibly be live across a yield point. -#![feature(coroutines)] +#![feature(coroutines, gen_blocks)] fn foo() { - let _x = static || { + let _x = static gen || { let mut s = String::new(); s += { yield; "" }; }; - let _y = static || { + let _y = static gen || { let x = &mut 0; *{ yield; x } += match String::new() { _ => 0 }; }; // Please don't ever actually write something like this - let _z = static || { + let _z = static gen || { let x = &mut 0; *{ let inner = &mut 1; diff --git a/tests/ui/coroutine/borrow-in-tail-expr.rs b/tests/ui/coroutine/borrow-in-tail-expr.rs index 2f0aa62019e83..002afc30f16e9 100644 --- a/tests/ui/coroutine/borrow-in-tail-expr.rs +++ b/tests/ui/coroutine/borrow-in-tail-expr.rs @@ -1,9 +1,11 @@ //@ run-pass +//@ edition: 2024 +//@ compile-flags: -Zunstable-options -#![feature(coroutines)] +#![feature(coroutines, gen_blocks)] fn main() { - let _a = || { + let _a = gen || { yield; let a = String::new(); a.len() diff --git a/tests/ui/coroutine/derived-drop-parent-expr.rs b/tests/ui/coroutine/derived-drop-parent-expr.rs index f70a732c90f08..19bde87bd73df 100644 --- a/tests/ui/coroutine/derived-drop-parent-expr.rs +++ b/tests/ui/coroutine/derived-drop-parent-expr.rs @@ -1,7 +1,9 @@ //@ build-pass +//@ edition: 2024 +//@ compile-flags: -Zunstable-options //! Like drop-tracking-parent-expression, but also tests that this doesn't ICE when building MIR -#![feature(coroutines)] +#![feature(coroutines, gen_blocks)] fn assert_send(_thing: T) {} @@ -9,8 +11,8 @@ fn assert_send(_thing: T) {} pub struct Client { pub nickname: String } fn main() { - let g = move || match drop(Client { ..Client::default() }) { - _status => yield, - }; + let g = gen || match drop(Client { ..Client::default() }) { + _status => yield, + }; assert_send(g); }