From a61cf673cd10ed24394c3403e03d8f7cf1f50170 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 5 Oct 2023 11:30:55 +0000 Subject: [PATCH 01/13] Reserve `gen` keyword for `gen {}` blocks and `gen fn` in 2024 edition --- compiler/rustc_ast/src/ast.rs | 6 +++++ compiler/rustc_ast/src/token.rs | 1 + compiler/rustc_parse/messages.ftl | 3 +++ compiler/rustc_parse/src/errors.rs | 8 +++++++ compiler/rustc_parse/src/parser/expr.rs | 18 ++++++++++++++ compiler/rustc_parse/src/parser/item.rs | 11 +++++++-- compiler/rustc_parse/src/parser/mod.rs | 11 +++++++++ compiler/rustc_span/src/symbol.rs | 6 +++-- tests/ui/coroutine/gen_block.e2024.stderr | 10 ++++++++ tests/ui/coroutine/gen_block.none.stderr | 29 +++++++++++++++++++++++ tests/ui/coroutine/gen_block.rs | 13 ++++++++++ tests/ui/coroutine/gen_fn.e2024.stderr | 10 ++++++++ tests/ui/coroutine/gen_fn.none.stderr | 8 +++++++ tests/ui/coroutine/gen_fn.rs | 8 +++++++ 14 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 tests/ui/coroutine/gen_block.e2024.stderr create mode 100644 tests/ui/coroutine/gen_block.none.stderr create mode 100644 tests/ui/coroutine/gen_block.rs create mode 100644 tests/ui/coroutine/gen_fn.e2024.stderr create mode 100644 tests/ui/coroutine/gen_fn.none.stderr create mode 100644 tests/ui/coroutine/gen_fn.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e94e26a63bc6f..543c528db448a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2357,6 +2357,12 @@ pub enum Async { No, } +#[derive(Copy, Clone, Encodable, Decodable, Debug)] +pub enum Gen { + Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, + No, +} + impl Async { pub fn is_async(self) -> bool { matches!(self, Async::Yes { .. }) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index dd879a14567c8..914c97a14ac0d 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -197,6 +197,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { kw::Continue, kw::False, kw::For, + kw::Gen, kw::If, kw::Let, kw::Loop, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e0778f72bfe6e..9bedd7b8a338a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -278,6 +278,9 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}` parse_function_body_equals_expr = function body cannot be `= expression;` .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` +parse_gen_block = `gen` blocks are not yet implemented + .help = only the keyword is reserved for now + parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index aeb4fd0a304aa..c0e94d15da0bf 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -520,6 +520,14 @@ pub(crate) struct CatchAfterTry { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_gen_block)] +#[help] +pub(crate) struct GenBlock { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_comma_after_base_struct)] #[note] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 5157106f4e269..e59076acf4c14 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1422,6 +1422,9 @@ impl<'a> Parser<'a> { } else if this.is_try_block() { this.expect_keyword(kw::Try)?; this.parse_try_block(lo) + } else if this.is_gen_block() { + this.expect_keyword(kw::Gen)?; + this.parse_gen_block(lo) } else if this.eat_keyword(kw::Return) { this.parse_expr_return() } else if this.eat_keyword(kw::Continue) { @@ -3040,6 +3043,14 @@ impl<'a> Parser<'a> { } } + /// Parses a `gen {...}` expression (`gen` token already eaten). + fn parse_gen_block(&mut self, _span_lo: Span) -> PResult<'a, P> { + let (_attrs, _body) = self.parse_inner_attrs_and_block()?; + + Err(errors::GenBlock { span: self.prev_token.span } + .into_diagnostic(&self.sess.span_diagnostic)) + } + fn is_do_catch_block(&self) -> bool { self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Catch]) @@ -3059,6 +3070,13 @@ impl<'a> Parser<'a> { && self.token.uninterpolated_span().at_least_rust_2018() } + fn is_gen_block(&self) -> bool { + self.token.is_keyword(kw::Gen) + && self + .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + && self.token.uninterpolated_span().at_least_rust_2024() + } + /// Parses an `async move? {...}` expression. fn parse_async_block(&mut self) -> PResult<'a, P> { let lo = self.token.span; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 982f601c0d5a2..4c76ade013932 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2297,9 +2297,9 @@ impl<'a> Parser<'a> { // `pub` is added in case users got confused with the ordering like `async pub fn`, // only if it wasn't preceded by `default` as `default pub` is invalid. let quals: &[Symbol] = if check_pub { - &[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern] + &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern] } else { - &[kw::Const, kw::Async, kw::Unsafe, kw::Extern] + &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern] }; self.check_keyword_case(kw::Fn, case) // Definitely an `fn`. // `$qual fn` or `$qual $qual`: @@ -2353,6 +2353,9 @@ impl<'a> Parser<'a> { let async_start_sp = self.token.span; let asyncness = self.parse_asyncness(case); + let _gen_start_sp = self.token.span; + let genness = self.parse_genness(case); + let unsafe_start_sp = self.token.span; let unsafety = self.parse_unsafety(case); @@ -2368,6 +2371,10 @@ impl<'a> Parser<'a> { } } + if let Gen::Yes { span, .. } = genness { + self.sess.emit_err(errors::GenBlock { span }); + } + if !self.eat_keyword_case(kw::Fn, case) { // It is possible for `expect_one_of` to recover given the contents of // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 597303cae73e2..53c6d8acff154 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -11,6 +11,7 @@ mod stmt; mod ty; use crate::lexer::UnmatchedDelim; +use ast::Gen; pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use expr::ForbiddenLetReason; @@ -1126,6 +1127,16 @@ impl<'a> Parser<'a> { } } + /// Parses genness: `gen` or nothing. + fn parse_genness(&mut self, case: Case) -> Gen { + if self.token.span.at_least_rust_2024() && self.eat_keyword_case(kw::Gen, case) { + let span = self.prev_token.uninterpolated_span(); + Gen::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID } + } else { + Gen::No + } + } + /// Parses unsafety: `unsafe` or nothing. fn parse_unsafety(&mut self, case: Case) -> Unsafe { if self.eat_keyword_case(kw::Unsafe, case) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ff61143a12ba2..8ef16ed0dbf7c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -98,6 +98,7 @@ symbols! { Builtin: "builtin", Catch: "catch", Default: "default", + Gen: "gen", MacroRules: "macro_rules", Raw: "raw", Union: "union", @@ -2188,8 +2189,9 @@ impl Symbol { self >= kw::Abstract && self <= kw::Yield } - fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { - self == kw::Try && edition() >= Edition::Edition2018 + fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool { + self == kw::Try && edition().at_least_rust_2018() + || self == kw::Gen && edition().at_least_rust_2024() } pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool { diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr new file mode 100644 index 0000000000000..099a9d13ceefd --- /dev/null +++ b/tests/ui/coroutine/gen_block.e2024.stderr @@ -0,0 +1,10 @@ +error: `gen` blocks are not yet implemented + --> $DIR/gen_block.rs:5:18 + | +LL | let x = gen {}; + | ^ + | + = help: only the keyword is reserved for now + +error: aborting due to previous error + diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr new file mode 100644 index 0000000000000..1cdd5d070ee53 --- /dev/null +++ b/tests/ui/coroutine/gen_block.none.stderr @@ -0,0 +1,29 @@ +error: expected identifier, found reserved keyword `yield` + --> $DIR/gen_block.rs:8:19 + | +LL | let y = gen { yield 42 }; + | --- ^^^^^ expected identifier, found reserved keyword + | | + | while parsing this struct + +error[E0422]: cannot find struct, variant or union type `gen` in this scope + --> $DIR/gen_block.rs:5:13 + | +LL | let x = gen {}; + | ^^^ not found in this scope + +error[E0422]: cannot find struct, variant or union type `gen` in this scope + --> $DIR/gen_block.rs:8:13 + | +LL | let y = gen { yield 42 }; + | ^^^ not found in this scope + +error[E0422]: cannot find struct, variant or union type `gen` in this scope + --> $DIR/gen_block.rs:11:5 + | +LL | gen {}; + | ^^^ not found in this scope + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0422`. diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs new file mode 100644 index 0000000000000..5c0db5b3d38d1 --- /dev/null +++ b/tests/ui/coroutine/gen_block.rs @@ -0,0 +1,13 @@ +// revisions: e2024 none +//[e2024] compile-flags: --edition 2024 -Zunstable-options + +fn main() { + let x = gen {}; + //[none]~^ ERROR: cannot find + //[e2024]~^^ ERROR: `gen` blocks are not yet implemented + let y = gen { yield 42 }; + //[none]~^ ERROR: found reserved keyword `yield` + //[none]~| ERROR: cannot find + gen {}; + //[none]~^ ERROR: cannot find +} diff --git a/tests/ui/coroutine/gen_fn.e2024.stderr b/tests/ui/coroutine/gen_fn.e2024.stderr new file mode 100644 index 0000000000000..41bd04d976912 --- /dev/null +++ b/tests/ui/coroutine/gen_fn.e2024.stderr @@ -0,0 +1,10 @@ +error: `gen` blocks are not yet implemented + --> $DIR/gen_fn.rs:4:1 + | +LL | gen fn foo() {} + | ^^^ + | + = help: only the keyword is reserved for now + +error: aborting due to previous error + diff --git a/tests/ui/coroutine/gen_fn.none.stderr b/tests/ui/coroutine/gen_fn.none.stderr new file mode 100644 index 0000000000000..5e7bd9d8bbfbf --- /dev/null +++ b/tests/ui/coroutine/gen_fn.none.stderr @@ -0,0 +1,8 @@ +error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen` + --> $DIR/gen_fn.rs:4:1 + | +LL | gen fn foo() {} + | ^^^ expected one of 9 possible tokens + +error: aborting due to previous error + diff --git a/tests/ui/coroutine/gen_fn.rs b/tests/ui/coroutine/gen_fn.rs new file mode 100644 index 0000000000000..9566660dfb566 --- /dev/null +++ b/tests/ui/coroutine/gen_fn.rs @@ -0,0 +1,8 @@ +// revisions: e2024 none +//[e2024] compile-flags: --edition 2024 -Zunstable-options + +gen fn foo() {} +//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen` +//[e2024]~^^ ERROR: `gen` blocks are not yet implemented + +fn main() {} From 14423080f1f9e9729d372f9b5da06c0ab4aef6e3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 20 Oct 2023 19:21:24 +0000 Subject: [PATCH 02/13] Add hir::GeneratorKind::Gen --- compiler/rustc_ast_lowering/src/expr.rs | 7 +++-- .../src/diagnostics/conflict_errors.rs | 5 ++++ .../src/diagnostics/region_name.rs | 14 ++++++++++ .../src/debuginfo/type_names.rs | 3 ++ compiler/rustc_hir/src/hir.rs | 12 ++++++++ compiler/rustc_hir_typeck/src/check.rs | 19 +++++++------ compiler/rustc_middle/src/mir/terminator.rs | 10 +++++++ compiler/rustc_middle/src/ty/util.rs | 2 ++ compiler/rustc_smir/src/rustc_smir/mod.rs | 28 +++++++++++++------ .../src/traits/error_reporting/suggestions.rs | 17 ++++++++++- .../error_reporting/type_err_ctxt_ext.rs | 3 ++ compiler/stable_mir/src/mir/body.rs | 1 + 12 files changed, 99 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b82f878ea87e0..ab82bbd46a6ea 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -712,7 +712,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let full_span = expr.span.to(await_kw_span); match self.coroutine_kind { Some(hir::CoroutineKind::Async(_)) => {} - Some(hir::CoroutineKind::Coroutine) | None => { + Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) | None => { self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { await_kw_span, item_span: self.current_item, @@ -936,8 +936,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } Some(movability) } - Some(hir::CoroutineKind::Async(_)) => { - panic!("non-`async` closure body turned `async` during lowering"); + Some(hir::CoroutineKind::Gen(_)) | Some(hir::CoroutineKind::Async(_)) => { + panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering"); } None => { if movability == Movability::Static { @@ -1446,6 +1446,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> { match self.coroutine_kind { Some(hir::CoroutineKind::Coroutine) => {} + Some(hir::CoroutineKind::Gen(_)) => {} Some(hir::CoroutineKind::Async(_)) => { self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span }); } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 928c25d106179..9db7dec1cf8e3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2505,6 +2505,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; let kind = match use_span.coroutine_kind() { Some(coroutine_kind) => match coroutine_kind { + CoroutineKind::Gen(kind) => match kind { + CoroutineSource::Block => "gen block", + CoroutineSource::Closure => "gen closure", + _ => bug!("gen block/closure expected, but gen function found."), + }, CoroutineKind::Async(async_kind) => match async_kind { CoroutineSource::Block => "async block", CoroutineSource::Closure => "async closure", diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index e630ac7c4faee..d38cfbc54d7ac 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -698,6 +698,20 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { " of async function" } }, + Some(hir::CoroutineKind::Gen(gen)) => match gen { + hir::CoroutineSource::Block => " of gen block", + hir::CoroutineSource::Closure => " of gen closure", + hir::CoroutineSource::Fn => { + let parent_item = + hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id); + let output = &parent_item + .fn_decl() + .expect("coroutine lowered from gen fn should be in fn") + .output; + span = output.span(); + " of gen function" + } + }, Some(hir::CoroutineKind::Coroutine) => " of coroutine", None => " of closure", }; diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 5900c764073df..1a85eb8dd7970 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -560,6 +560,9 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: & fn coroutine_kind_label(coroutine_kind: Option) -> &'static str { match coroutine_kind { + Some(CoroutineKind::Gen(CoroutineSource::Block)) => "gen_block", + Some(CoroutineKind::Gen(CoroutineSource::Closure)) => "gen_closure", + Some(CoroutineKind::Gen(CoroutineSource::Fn)) => "gen_fn", Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block", Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure", Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn", diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 259af4f565bda..22ee39634a56d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1513,6 +1513,9 @@ pub enum CoroutineKind { /// An explicit `async` block or the body of an async function. Async(CoroutineSource), + /// An explicit `gen` block or the body of a `gen` function. + Gen(CoroutineSource), + /// A coroutine literal created via a `yield` inside a closure. Coroutine, } @@ -1529,6 +1532,14 @@ impl fmt::Display for CoroutineKind { k.fmt(f) } CoroutineKind::Coroutine => f.write_str("coroutine"), + CoroutineKind::Gen(k) => { + if f.alternate() { + f.write_str("`gen` ")?; + } else { + f.write_str("gen ")? + } + k.fmt(f) + } } } } @@ -2242,6 +2253,7 @@ impl From for YieldSource { // Guess based on the kind of the current coroutine. CoroutineKind::Coroutine => Self::Yield, CoroutineKind::Async(_) => Self::Await { expr: None }, + CoroutineKind::Gen(_) => Self::Yield, } } } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index e7060dac844b9..14cd3881a068d 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -58,15 +58,16 @@ pub(super) fn check_fn<'a, 'tcx>( if let Some(kind) = body.coroutine_kind && can_be_coroutine.is_some() { - let yield_ty = if kind == hir::CoroutineKind::Coroutine { - let yield_ty = fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }); - fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); - yield_ty - } else { - Ty::new_unit(tcx) + let yield_ty = match kind { + hir::CoroutineKind::Gen(..) | hir::CoroutineKind::Coroutine => { + let yield_ty = fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + yield_ty + } + hir::CoroutineKind::Async(..) => Ty::new_unit(tcx), }; // Resume type defaults to `()` if the coroutine has no argument. diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index affa83fa34858..ef1d0c867ea18 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -148,8 +148,14 @@ impl AssertKind { RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero", ResumedAfterReturn(CoroutineKind::Coroutine) => "coroutine resumed after completion", ResumedAfterReturn(CoroutineKind::Async(_)) => "`async fn` resumed after completion", + ResumedAfterReturn(CoroutineKind::Gen(_)) => { + bug!("`gen fn` should just keep returning `None` after the first time") + } ResumedAfterPanic(CoroutineKind::Coroutine) => "coroutine resumed after panicking", ResumedAfterPanic(CoroutineKind::Async(_)) => "`async fn` resumed after panicking", + ResumedAfterPanic(CoroutineKind::Gen(_)) => { + bug!("`gen fn` should just keep returning `None` after panicking") + } BoundsCheck { .. } | MisalignedPointerDereference { .. } => { bug!("Unexpected AssertKind") } @@ -236,10 +242,14 @@ impl AssertKind { DivisionByZero(_) => middle_assert_divide_by_zero, RemainderByZero(_) => middle_assert_remainder_by_zero, ResumedAfterReturn(CoroutineKind::Async(_)) => middle_assert_async_resume_after_return, + // FIXME(gen_blocks): custom error message for `gen` blocks + ResumedAfterReturn(CoroutineKind::Gen(_)) => middle_assert_async_resume_after_return, ResumedAfterReturn(CoroutineKind::Coroutine) => { middle_assert_coroutine_resume_after_return } ResumedAfterPanic(CoroutineKind::Async(_)) => middle_assert_async_resume_after_panic, + // FIXME(gen_blocks): custom error message for `gen` blocks + ResumedAfterPanic(CoroutineKind::Gen(_)) => middle_assert_async_resume_after_panic, ResumedAfterPanic(CoroutineKind::Coroutine) => { middle_assert_coroutine_resume_after_panic } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index be48c0e8926b7..d29d1902404f0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -749,6 +749,7 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::Coroutine => match self.coroutine_kind(def_id).unwrap() { rustc_hir::CoroutineKind::Async(..) => "async closure", rustc_hir::CoroutineKind::Coroutine => "coroutine", + rustc_hir::CoroutineKind::Gen(..) => "gen closure", }, _ => def_kind.descr(def_id), } @@ -766,6 +767,7 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::Coroutine => match self.coroutine_kind(def_id).unwrap() { rustc_hir::CoroutineKind::Async(..) => "an", rustc_hir::CoroutineKind::Coroutine => "a", + rustc_hir::CoroutineKind::Gen(..) => "a", }, _ => def_kind.article(), } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 928536721c95f..219f6d284dd83 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -880,18 +880,28 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { } } +impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource { + type T = stable_mir::mir::CoroutineSource; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use rustc_hir::CoroutineSource; + match self { + CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block, + CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure, + CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn, + } + } +} + impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { type T = stable_mir::mir::CoroutineKind; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - use rustc_hir::{CoroutineKind, CoroutineSource}; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use rustc_hir::CoroutineKind; match self { - CoroutineKind::Async(async_gen) => { - let async_gen = match async_gen { - CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block, - CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure, - CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn, - }; - stable_mir::mir::CoroutineKind::Async(async_gen) + CoroutineKind::Async(source) => { + stable_mir::mir::CoroutineKind::Async(source.stable(tables)) + } + CoroutineKind::Gen(source) => { + stable_mir::mir::CoroutineKind::Gen(source.stable(tables)) } CoroutineKind::Coroutine => stable_mir::mir::CoroutineKind::Coroutine, } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index b9a08056ad162..3087b734cf274 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2425,6 +2425,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { CoroutineKind::Async(CoroutineSource::Closure) => { format!("future created by async closure is not {trait_name}") } + CoroutineKind::Gen(CoroutineSource::Fn) => self + .tcx + .parent(coroutine_did) + .as_local() + .map(|parent_did| hir.local_def_id_to_hir_id(parent_did)) + .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .map(|name| { + format!("iterator returned by `{name}` is not {trait_name}") + })?, + CoroutineKind::Gen(CoroutineSource::Block) => { + format!("iterator created by gen block is not {trait_name}") + } + CoroutineKind::Gen(CoroutineSource::Closure) => { + format!("iterator created by gen closure is not {trait_name}") + } }) }) .unwrap_or_else(|| format!("{future_or_coroutine} is not {trait_name}")); @@ -2905,7 +2920,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => { let what = match self.tcx.coroutine_kind(coroutine_def_id) { - None | Some(hir::CoroutineKind::Coroutine) => "yield", + None | Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) => "yield", Some(hir::CoroutineKind::Async(..)) => "await", }; err.note(format!( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 353a69ef6d324..030813a4ac372 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1614,6 +1614,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block", hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function", hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure", + hir::CoroutineKind::Gen(hir::CoroutineSource::Block) => "a gen block", + hir::CoroutineKind::Gen(hir::CoroutineSource::Fn) => "a gen function", + hir::CoroutineKind::Gen(hir::CoroutineSource::Closure) => "a gen closure", }) } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index c2e79eaaf3ffe..b686004b2fef5 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -137,6 +137,7 @@ pub enum UnOp { pub enum CoroutineKind { Async(CoroutineSource), Coroutine, + Gen(CoroutineSource), } #[derive(Clone, Debug)] From 621494382da59e3a899a968e7d445170dd37ba1d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 20 Oct 2023 21:26:57 +0000 Subject: [PATCH 03/13] Add gen blocks to ast and do some broken ast lowering --- compiler/rustc_ast/src/ast.rs | 32 ++++++++-- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/util/classify.rs | 2 +- compiler/rustc_ast/src/util/parser.rs | 4 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 61 ++++++++++++++++++- .../rustc_ast_pretty/src/pprust/state/expr.rs | 4 +- .../src/assert/context.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 32 +++++----- compiler/rustc_passes/src/hir_stats.rs | 4 +- compiler/rustc_resolve/src/def_collector.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- .../src/suspicious_operation_groupings.rs | 2 +- .../clippy/clippy_utils/src/ast_utils.rs | 2 +- src/tools/clippy/clippy_utils/src/sugg.rs | 2 +- src/tools/rustfmt/src/closures.rs | 2 +- src/tools/rustfmt/src/expr.rs | 8 +-- src/tools/rustfmt/src/utils.rs | 2 +- tests/ui/coroutine/gen_block.e2024.stderr | 9 ++- tests/ui/coroutine/gen_block.none.stderr | 8 +-- tests/ui/coroutine/gen_block.rs | 3 +- 21 files changed, 131 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 543c528db448a..aceee07a7341c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1232,7 +1232,7 @@ impl Expr { ExprKind::Closure(..) => ExprPrecedence::Closure, ExprKind::Block(..) => ExprPrecedence::Block, ExprKind::TryBlock(..) => ExprPrecedence::TryBlock, - ExprKind::Async(..) => ExprPrecedence::Async, + ExprKind::Gen(..) => ExprPrecedence::Gen, ExprKind::Await(..) => ExprPrecedence::Await, ExprKind::Assign(..) => ExprPrecedence::Assign, ExprKind::AssignOp(..) => ExprPrecedence::AssignOp, @@ -1401,11 +1401,9 @@ pub enum ExprKind { Closure(Box), /// A block (`'label: { ... }`). Block(P, Option