Skip to content

Commit 191bb83

Browse files
author
Sasha Pourcelot
committed
Put some notes in a separate note block
1 parent 3a334a0 commit 191bb83

File tree

3 files changed

+56
-14
lines changed

3 files changed

+56
-14
lines changed

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,9 +1736,6 @@ impl<'a> Parser<'a> {
17361736
self.sess.gated_spans.gate(sym::async_closure, span);
17371737
}
17381738

1739-
// Disable recovery for closure body
1740-
self.last_closure_body = Some(decl_hi);
1741-
17421739
if self.token.kind == TokenKind::Semi && self.token_cursor.frame.delim == DelimToken::Paren
17431740
{
17441741
// It is likely that the closure body is a block but where the
@@ -1747,11 +1744,18 @@ impl<'a> Parser<'a> {
17471744
body = self.mk_expr_err(body.span);
17481745
}
17491746

1750-
Ok(self.mk_expr(
1747+
let body_span = body.span;
1748+
1749+
let clo = self.mk_expr(
17511750
lo.to(body.span),
17521751
ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
17531752
attrs,
1754-
))
1753+
);
1754+
1755+
// Disable recovery for closure body
1756+
self.last_closure_body = Some((clo.span, decl_hi, body_span));
1757+
1758+
Ok(clo)
17551759
}
17561760

17571761
/// Parses an optional `move` prefix to a closure-like construct.

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError
3535
use rustc_session::parse::ParseSess;
3636
use rustc_span::source_map::{Span, DUMMY_SP};
3737
use rustc_span::symbol::{kw, sym, Ident, Symbol};
38+
use rustc_span::MultiSpan;
3839
use tracing::debug;
3940

4041
use std::ops::Range;
@@ -145,7 +146,11 @@ pub struct Parser<'a> {
145146

146147
/// This allows us to recover when the user forget to add braces around
147148
/// multiple statements in the closure body.
148-
pub last_closure_body: Option<Span /* The closing `|` of the closure declarator. */>,
149+
pub last_closure_body: Option<(
150+
Span, /* The whole body. */
151+
Span, /* The closing `|` of the closure declarator. */
152+
Span, /* What we parsed as closure body. */
153+
)>,
149154
}
150155

151156
/// Indicates a range of tokens that should be replaced by
@@ -779,15 +784,19 @@ impl<'a> Parser<'a> {
779784
let token_str = pprust::token_kind_to_string(t);
780785

781786
match self.last_closure_body.take() {
782-
Some(right_pipe_span) if self.token.kind == TokenKind::Semi => {
787+
Some((closure_span, right_pipe_span, expr_span))
788+
if self.token.kind == TokenKind::Semi =>
789+
{
783790
// Finding a semicolon instead of a comma
784791
// after a closure body indicates that the
785792
// closure body may be a block but the user
786793
// forgot to put braces around its
787794
// statements.
788795

789796
self.recover_missing_braces_around_closure_body(
797+
closure_span,
790798
right_pipe_span,
799+
expr_span,
791800
expect_err,
792801
)?;
793802

@@ -868,16 +877,13 @@ impl<'a> Parser<'a> {
868877

869878
fn recover_missing_braces_around_closure_body(
870879
&mut self,
880+
closure_span: Span,
871881
right_pipe_span: Span,
882+
expr_span: Span,
872883
mut expect_err: DiagnosticBuilder<'_>,
873884
) -> PResult<'a, ()> {
874885
let initial_semicolon = self.token.span;
875886

876-
expect_err.span_help(
877-
initial_semicolon,
878-
"This `;` turns the expression into a statement, which must be placed in a block",
879-
);
880-
881887
while self.eat(&TokenKind::Semi) {
882888
let _ = self.parse_stmt(ForceCollect::Yes)?;
883889
}
@@ -889,6 +895,25 @@ impl<'a> Parser<'a> {
889895
let preceding_pipe_span = right_pipe_span;
890896
let following_token_span = self.token.span;
891897

898+
let mut first_note = MultiSpan::from(vec![initial_semicolon]);
899+
first_note.push_span_label(
900+
initial_semicolon,
901+
"this `;` turns the preceding expression into a statement".to_string(),
902+
);
903+
first_note.push_span_label(
904+
expr_span,
905+
"this expression is a statement because of the trailing semicolon".to_string(),
906+
);
907+
expect_err.span_note(first_note, "statement found outside of a block");
908+
909+
let mut second_note = MultiSpan::from(vec![closure_span]);
910+
second_note.push_span_label(closure_span, "this is the parsed closure...".to_string());
911+
second_note.push_span_label(
912+
following_token_span,
913+
"...but likely you meant the closure to end here".to_string(),
914+
);
915+
expect_err.span_note(second_note, "the closure body may be incorrectly delimited");
916+
892917
expect_err.set_span(vec![preceding_pipe_span, following_token_span]);
893918

894919
let opening_suggestion_str = " {".to_string();

src/test/ui/expr/malformed_closure/missing_braces_around_block.stderr

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,24 @@ LL | (1..num).reduce(|a, b|
77
LL | ).unwrap();
88
| ^
99
|
10-
help: This `;` turns the expression into a statement, which must be placed in a block
10+
note: statement found outside of a block
1111
--> $DIR/missing_braces_around_block.rs:16:26
1212
|
1313
LL | println!("{}", a);
14-
| ^
14+
| -----------------^ this `;` turns the preceding expression into a statement
15+
| |
16+
| this expression is a statement because of the trailing semicolon
17+
note: the closure body may be incorrectly delimited
18+
--> $DIR/missing_braces_around_block.rs:14:21
19+
|
20+
LL | (1..num).reduce(|a, b|
21+
| _____________________^
22+
LL | |
23+
LL | | println!("{}", a);
24+
| |_________________________^ this is the parsed closure...
25+
LL | a * b
26+
LL | ).unwrap();
27+
| - ...but likely you meant the closure to end here
1528
help: try adding braces
1629
|
1730
LL ~ (1..num).reduce(|a, b| {

0 commit comments

Comments
 (0)