Skip to content

Commit

Permalink
Fix Error Messages for break Inside Coroutines
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
veera-sivarajan committed May 5, 2024
1 parent 833bbcc commit 5f66961
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 10 deletions.
48 changes: 44 additions & 4 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
88 changes: 88 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
47 changes: 41 additions & 6 deletions compiler/rustc_passes/src/loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 });
Expand Down

0 comments on commit 5f66961

Please sign in to comment.