Skip to content

Distinguish delim kind to decide whether to emit unexpected closing delimiter #138554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions compiler/rustc_parse/src/lexer/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ pub(super) fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Sp

// When we get a `)` or `]` for `{`, we should emit help message here
// it's more friendly compared to report `unmatched error` in later phase
fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool {
fn report_missing_open_delim(
err: &mut Diag<'_>,
unmatched_delims: &mut Vec<UnmatchedDelim>,
) -> bool {
let mut reported_missing_open = false;
for unmatch_brace in unmatched_delims.iter() {
unmatched_delims.retain(|unmatch_brace| {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When missing open xxx for this delimiter is reported in the unexpected closing delimiter: xxx error, I remove the corresponding unmatched_delims so that make_unclosed_delims_error doesn't get double report.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, thank you for all your changes and your patience to improve this output!

Do we have any test left where the lexer diagnostic is still emitted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if let Some(delim) = unmatch_brace.found_delim
&& matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket)
{
Expand All @@ -50,18 +53,21 @@ fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDe
format!("missing open `{missed_open}` for this delimiter"),
);
reported_missing_open = true;
false
} else {
true
}
}
});
reported_missing_open
}

pub(super) fn report_suspicious_mismatch_block(
err: &mut Diag<'_>,
diag_info: &TokenTreeDiagInfo,
diag_info: &mut TokenTreeDiagInfo,
sm: &SourceMap,
delim: Delimiter,
) {
if report_missing_open_delim(err, &diag_info.unmatched_delims) {
if report_missing_open_delim(err, &mut diag_info.unmatched_delims) {
return;
}

Expand Down
29 changes: 21 additions & 8 deletions compiler/rustc_parse/src/lexer/tokentrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
);
}

if let Some((delim, _)) = self.diag_info.open_delimiters.last() {
if let Some((delim, _)) = self.diag_info.open_delimiters.last().cloned() {
report_suspicious_mismatch_block(
&mut err,
&self.diag_info,
&mut self.diag_info,
self.psess.source_map(),
*delim,
delim,
)
}
err
Expand Down Expand Up @@ -154,15 +154,12 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
candidate = Some(*delimiter_span);
}
}
let (_, _) = self.diag_info.open_delimiters.pop().unwrap();
self.diag_info.unmatched_delims.push(UnmatchedDelim {
found_delim: Some(close_delim),
found_span: self.token.span,
unclosed_span: unclosed_delimiter,
candidate_span: candidate,
});
} else {
self.diag_info.open_delimiters.pop();
}

// If the incorrect delimiter matches an earlier opening
Expand Down Expand Up @@ -238,13 +235,29 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
this_spacing
}

fn close_delim_err(&mut self, delim: Delimiter) -> Diag<'psess> {
fn close_delim_err(&mut self, close_delim: Delimiter) -> Diag<'psess> {
// An unexpected closing delimiter (i.e., there is no matching opening delimiter).
let token_str = token_to_string(&self.token);
let msg = format!("unexpected closing delimiter: `{token_str}`");
let mut err = self.dcx().struct_span_err(self.token.span, msg);

report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim);
if let Some((open_delim, open_delim_span)) = self.diag_info.open_delimiters.last().cloned()
{
if open_delim == close_delim {
err.span_label(
open_delim_span,
format!("the mismatchd closing `{}` may be matched here", token_str),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message has a typo, and I'd like to tweak the wording here a bit, I just don't have a good idea for what the ideal text would be in context.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something "the mismatched closing {token_str} may be meant for this opening delimiter"?

);
self.diag_info.open_delimiters.pop();
}
}

report_suspicious_mismatch_block(
&mut err,
&mut self.diag_info,
self.psess.source_map(),
close_delim,
);
err.span_label(self.token.span, "unexpected closing delimiter");
err
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/parser/deli-ident-issue-2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn main() {
if 1 < 2 {
let _a = vec!]; //~ ERROR mismatched closing delimiter
let _a = vec!];
}
} //~ ERROR unexpected closing delimiter

Expand Down
13 changes: 4 additions & 9 deletions tests/ui/parser/deli-ident-issue-2.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
error: mismatched closing delimiter: `]`
--> $DIR/deli-ident-issue-2.rs:2:14
|
LL | if 1 < 2 {
| ^ unclosed delimiter
LL | let _a = vec!];
| ^ mismatched closing delimiter

error: unexpected closing delimiter: `}`
--> $DIR/deli-ident-issue-2.rs:5:1
|
LL | fn main() {
| - the mismatchd closing `}` may be matched here
LL | if 1 < 2 {
LL | let _a = vec!];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we should still have a label pointing at this opening {, stating that the closing ] matches it.

| - missing open `[` for this delimiter
LL | }
LL | }
| ^ unexpected closing delimiter

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

2 changes: 1 addition & 1 deletion tests/ui/parser/issues/issue-104367.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
struct S {
d: [u32; {
#![cfg] {
#![w,) //~ ERROR mismatched closing delimiter
#![w,)
//~ ERROR this file contains an unclosed delimiter
14 changes: 4 additions & 10 deletions tests/ui/parser/issues/issue-104367.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
error: mismatched closing delimiter: `)`
--> $DIR/issue-104367.rs:5:15
|
LL | #![w,)
| ^ ^ mismatched closing delimiter
| |
| unclosed delimiter

error: this file contains an unclosed delimiter
--> $DIR/issue-104367.rs:6:71
|
Expand All @@ -18,9 +10,11 @@ LL | d: [u32; {
LL | #![cfg] {
| - unclosed delimiter
LL | #![w,)
| - missing open `(` for this delimiter
| - - missing open `(` for this delimiter
| |
| unclosed delimiter
LL |
| ^

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

2 changes: 1 addition & 1 deletion tests/ui/parser/issues/issue-105209.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
//@ compile-flags: -Zunpretty=ast-tree
#![c={#![c[)x //~ ERROR mismatched closing delimiter
#![c={#![c[)x
//~ ERROR this file contains an unclosed delimiter
Comment on lines +2 to 3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should make the .stderr output a bit easier to read:

Suggested change
#![c={#![c[)x
//~ ERROR this file contains an unclosed delimiter
//~v ERROR this file contains an unclosed delimiter
#![c={#![c[)x
15 changes: 4 additions & 11 deletions tests/ui/parser/issues/issue-105209.stderr
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
error: mismatched closing delimiter: `)`
--> $DIR/issue-105209.rs:2:11
|
LL | #![c={#![c[)x
| ^^ mismatched closing delimiter
| |
| unclosed delimiter

error: this file contains an unclosed delimiter
--> $DIR/issue-105209.rs:3:68
|
LL | #![c={#![c[)x
| - - - - missing open `(` for this delimiter
| | | |
| - - - -- missing open `(` for this delimiter
| | | | |
| | | | unclosed delimiter
| | | unclosed delimiter
| | unclosed delimiter
| unclosed delimiter
LL |
| ^

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

6 changes: 3 additions & 3 deletions tests/ui/parser/issues/issue-62895.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ LL | (), w20);
| ^ mismatched closing delimiter

error: mismatched closing delimiter: `)`
--> $DIR/issue-62895.rs:4:7
--> $DIR/issue-62895.rs:5:22
|
LL | mod _ {
| ^ unclosed delimiter
LL | pub fn g() -> isizee {
| ^ unclosed delimiter
...
LL | (), w20);
| ^ mismatched closing delimiter
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/parser/issues/issue-62973.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

fn main() {}

//~vvv ERROR mismatched closing delimiter: `)`
//~vv ERROR mismatched closing delimiter: `)`
//~vvv ERROR this file contains an unclosed delimiter
fn p() { match s { v, E { [) {) }

Expand Down
28 changes: 7 additions & 21 deletions tests/ui/parser/issues/issue-62973.stderr
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
error: mismatched closing delimiter: `)`
--> $DIR/issue-62973.rs:8:27
|
LL | fn p() { match s { v, E { [) {) }
| ^^ mismatched closing delimiter
| |
| unclosed delimiter

error: mismatched closing delimiter: `)`
--> $DIR/issue-62973.rs:8:30
|
LL | fn p() { match s { v, E { [) {) }
| ^^ mismatched closing delimiter
| |
| unclosed delimiter

error: this file contains an unclosed delimiter
--> $DIR/issue-62973.rs:10:2
--> $DIR/issue-62973.rs:8:2
|
LL | fn p() { match s { v, E { [) {) }
| - - - - missing open `(` for this delimiter
| | | |
| | | missing open `(` for this delimiter
| - - - -- - missing open `(` for this delimiter
| | | | ||
| | | | |missing open `(` for this delimiter
| | | | unclosed delimiter
| | | unclosed delimiter
| | unclosed delimiter
| unclosed delimiter
LL |
LL |
| ^

error: aborting due to 3 previous errors
error: aborting due to 1 previous error

1 change: 0 additions & 1 deletion tests/ui/parser/issues/issue-63116.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// fixed by #66361
//~vv ERROR mismatched closing delimiter: `]`
//~v ERROR this file contains an unclosed delimiter
impl W <s(f;Y(;]
19 changes: 6 additions & 13 deletions tests/ui/parser/issues/issue-63116.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
error: mismatched closing delimiter: `]`
--> $DIR/issue-63116.rs:4:14
|
LL | impl W <s(f;Y(;]
| ^ ^ mismatched closing delimiter
| |
| unclosed delimiter

error: this file contains an unclosed delimiter
--> $DIR/issue-63116.rs:4:18
--> $DIR/issue-63116.rs:3:18
|
LL | impl W <s(f;Y(;]
| - -^
| | |
| | missing open `[` for this delimiter
| - - -^
| | | |
| | | missing open `[` for this delimiter
| | unclosed delimiter
| unclosed delimiter

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@ mod a {

enum Bug {
V = [PhantomData; { [ () ].len() ].len() as isize,
//~^ ERROR mismatched closing delimiter: `]`
}
}

mod b {
enum Bug {
V = [Vec::new; { [].len() ].len() as isize,
//~^ ERROR mismatched closing delimiter: `]`
}
}

mod c {
enum Bug {
V = [Vec::new; { [0].len() ].len() as isize,
//~^ ERROR mismatched closing delimiter: `]`
}

fn main() {} //~ ERROR this file contains an unclosed delimiter
Original file line number Diff line number Diff line change
@@ -1,47 +1,27 @@
error: mismatched closing delimiter: `]`
--> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:5:27
|
LL | V = [PhantomData; { [ () ].len() ].len() as isize,
| - ^ ^ mismatched closing delimiter
| | |
| | unclosed delimiter
| closing delimiter possibly meant for this

error: mismatched closing delimiter: `]`
--> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:12:24
|
LL | V = [Vec::new; { [].len() ].len() as isize,
| - ^ ^ mismatched closing delimiter
| | |
| | unclosed delimiter
| closing delimiter possibly meant for this

error: mismatched closing delimiter: `]`
--> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:19:24
|
LL | V = [Vec::new; { [0].len() ].len() as isize,
| - ^ ^ mismatched closing delimiter
| | |
| | unclosed delimiter
| closing delimiter possibly meant for this

error: this file contains an unclosed delimiter
--> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:23:65
--> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:20:65
|
LL | mod a {
| - unclosed delimiter
...
LL | V = [PhantomData; { [ () ].len() ].len() as isize,
| - missing open `[` for this delimiter
...
LL | mod b {
| - unclosed delimiter
LL | enum Bug {
LL | V = [Vec::new; { [].len() ].len() as isize,
| - missing open `[` for this delimiter
...
LL | mod c {
| - unclosed delimiter
LL | enum Bug {
| - unclosed delimiter
LL | V = [Vec::new; { [0].len() ].len() as isize,
| - missing open `[` for this delimiter
...
LL | fn main() {}
| ^

error: aborting due to 4 previous errors
error: aborting due to 1 previous error

2 changes: 1 addition & 1 deletion tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// FIXME: this case need more work to fix
// currently the TokenTree matching ')' with '{', which is not user friendly for diagnostics
async fn obstest() -> Result<> {
let obs_connect = || -> Result<(), MyError) { //~ ERROR mismatched closing delimiter
let obs_connect = || -> Result<(), MyError) {
async {
}
}
Expand Down
Loading
Loading