From 5f66961316b3769b3b59c33774065ef3a04cb6b7 Mon Sep 17 00:00:00 2001 From: Veera Date: Sun, 5 May 2024 18:14:23 -0400 Subject: [PATCH] Fix Error Messages for `break` Inside Coroutines Previously, `break` inside `gen` blocks and functions were incorrectly identified to be enclosed by a closure. This PR fixes it by displaying an appropriate error message for async blocks, async closures, async functions, gen blocks, gen closures, gen functions, async gen blocks, async gen closures and async gen functions. Note: gen closure and async gen closure are not supported by the compiler yet but I have added an error message here assuming that they might be implemented in the future. Also, fixes grammar in a few places by replacing `inside of a $coroutine` with `inside a $coroutine`. --- compiler/rustc_passes/messages.ftl | 48 ++++++++++++++-- compiler/rustc_passes/src/errors.rs | 88 +++++++++++++++++++++++++++++ compiler/rustc_passes/src/loops.rs | 47 +++++++++++++-- 3 files changed, 173 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 9d58d301e2bc2..6b4f3d0c5a2d5 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -53,15 +53,55 @@ passes_both_ffi_const_and_pure = `#[ffi_const]` function cannot be `#[ffi_pure]` passes_break_inside_async_block = - `{$name}` inside of an `async` block - .label = cannot `{$name}` inside of an `async` block + `{$name}` inside an `async` block + .label = cannot `{$name}` inside an `async` block .async_block_label = enclosing `async` block +passes_break_inside_async_closure = + `{$name}` inside an `async` closure + .label = cannot `{$name}` inside an `async` closure + .async_closure_label = enclosing `async` closure + +passes_break_inside_async_function = + `{$name}` inside an `async` function + .label = cannot `{$name}` inside an `async` function + .async_function_label = enclosing `async` function + +passes_break_inside_async_gen_block = + `{$name}` inside an `async gen` block + .label = cannot `{$name}` inside an `async gen` block + .async_gen_block_label = enclosing `async gen` block + +passes_break_inside_async_gen_closure = + `{$name}` inside an `async gen` closure + .label = cannot `{$name}` inside an `async gen` closure + .async_gen_closure_label = enclosing `async gen` closure + +passes_break_inside_async_gen_function = + `{$name}` inside an `async gen` function + .label = cannot `{$name}` inside an `async gen` function + .async_gen_function_label = enclosing `async gen` function + passes_break_inside_closure = - `{$name}` inside of a closure - .label = cannot `{$name}` inside of a closure + `{$name}` inside a closure + .label = cannot `{$name}` inside a closure .closure_label = enclosing closure +passes_break_inside_gen_block = + `{$name}` inside a `gen` block + .label = cannot `{$name}` inside a `gen` block + .gen_block_label = enclosing `gen` block + +passes_break_inside_gen_closure = + `{$name}` inside a `gen` closure + .label = cannot `{$name}` inside a `gen` closure + .gen_closure_label = enclosing `gen` closure + +passes_break_inside_gen_function = + `{$name}` inside a `gen` function + .label = cannot `{$name}` inside a `gen` function + .gen_function_label = enclosing `gen` function + passes_break_non_loop = `break` with value from a `{$kind}` loop .label = can only break with a value inside `loop` or breakable block diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 65cad82cc8c2b..7ec7ada6eca2a 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1096,6 +1096,94 @@ pub struct BreakInsideAsyncBlock<'a> { pub name: &'a str, } +#[derive(Diagnostic)] +#[diag(passes_break_inside_async_closure, code = E0267)] +pub struct BreakInsideAsyncClosure<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_async_closure_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_async_function, code = E0267)] +pub struct BreakInsideAsyncFn<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_async_function_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_gen_block, code = E0267)] +pub struct BreakInsideGenBlock<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_gen_block_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_gen_function, code = E0267)] +pub struct BreakInsideGenFn<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_gen_function_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_gen_closure, code = E0267)] +pub struct BreakInsideGenClosure<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_gen_closure_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_async_gen_block, code = E0267)] +pub struct BreakInsideAsyncGenBlock<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_async_gen_block_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_async_gen_function, code = E0267)] +pub struct BreakInsideAsyncGenFn<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_async_gen_function_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes_break_inside_async_gen_closure, code = E0267)] +pub struct BreakInsideAsyncGenClosure<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_async_gen_closure_label)] + pub closure_span: Span, + pub name: &'a str, +} + #[derive(Diagnostic)] #[diag(passes_outside_loop, code = E0268)] pub struct OutsideLoop<'a> { diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 4b5c4dfe991b7..c6aac7db8815b 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -13,7 +13,9 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::{BytePos, Span}; use crate::errors::{ - BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, + BreakInsideAsyncBlock, BreakInsideAsyncClosure, BreakInsideAsyncFn, BreakInsideAsyncGenBlock, + BreakInsideAsyncGenClosure, BreakInsideAsyncGenFn, BreakInsideClosure, BreakInsideGenBlock, + BreakInsideGenClosure, BreakInsideGenFn, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, }; @@ -23,7 +25,9 @@ enum Context { Fn, Loop(hir::LoopSource), Closure(Span), - AsyncClosure(Span), + Async(Span, hir::CoroutineSource), + Gen(Span, hir::CoroutineSource), + AsyncGen(Span, hir::CoroutineSource), UnlabeledBlock(Span), LabeledBlock, Constant, @@ -89,12 +93,19 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, fn_decl_span, kind, .. }) => { - // FIXME(coroutines): This doesn't handle coroutines correctly let cx = match kind { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - )) => AsyncClosure(fn_decl_span), + kind, + )) => Async(fn_decl_span, kind), + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + kind, + )) => Gen(fn_decl_span, kind), + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + kind, + )) => AsyncGen(fn_decl_span, kind), _ => Closure(fn_decl_span), }; self.visit_fn_decl(fn_decl); @@ -227,9 +238,33 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { Closure(closure_span) => { self.sess.dcx().emit_err(BreakInsideClosure { span, closure_span, name }); } - AsyncClosure(closure_span) => { + Async(closure_span, hir::CoroutineSource::Block) => { self.sess.dcx().emit_err(BreakInsideAsyncBlock { span, closure_span, name }); } + Async(closure_span, hir::CoroutineSource::Closure) => { + self.sess.dcx().emit_err(BreakInsideAsyncClosure { span, closure_span, name }); + } + Async(closure_span, hir::CoroutineSource::Fn) => { + self.sess.dcx().emit_err(BreakInsideAsyncFn { span, closure_span, name }); + } + Gen(closure_span, hir::CoroutineSource::Block) => { + self.sess.dcx().emit_err(BreakInsideGenBlock { span, closure_span, name }); + } + Gen(closure_span, hir::CoroutineSource::Fn) => { + self.sess.dcx().emit_err(BreakInsideGenFn { span, closure_span, name }); + } + Gen(closure_span, hir::CoroutineSource::Closure) => { + self.sess.dcx().emit_err(BreakInsideGenClosure { span, closure_span, name }); + } + AsyncGen(closure_span, hir::CoroutineSource::Block) => { + self.sess.dcx().emit_err(BreakInsideAsyncGenBlock { span, closure_span, name }); + } + AsyncGen(closure_span, hir::CoroutineSource::Fn) => { + self.sess.dcx().emit_err(BreakInsideAsyncGenFn { span, closure_span, name }); + } + AsyncGen(closure_span, hir::CoroutineSource::Closure) => { + self.sess.dcx().emit_err(BreakInsideAsyncGenClosure { span, closure_span, name }); + } UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => { let suggestion = Some(OutsideLoopSuggestion { block_span, break_span }); self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion });