Skip to content

Commit b44d336

Browse files
committed
Distinguish delim kind to decide whether to emit unexpected closing delimiter
To emit missing open delim note, I also moved `missing open delim` note to `mismatched closing delimiter` error, which can emit without delaying to `unexpected closing delimiter` error. And I moved `make_unclosed_delims_error` to src/lexer/diagnostics.rs for clean. And some other clean. Signed-off-by: xizheyin <[email protected]>
1 parent a4c5e80 commit b44d336

31 files changed

+196
-145
lines changed

compiler/rustc_parse/src/lexer/diagnostics.rs

+56-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
use rustc_ast::token::Delimiter;
1+
use rustc_ast::token::{self, Delimiter};
2+
use rustc_ast_pretty::pprust;
23
use rustc_errors::Diag;
4+
use rustc_session::parse::ParseSess;
35
use rustc_span::Span;
46
use rustc_span::source_map::SourceMap;
57

68
use super::UnmatchedDelim;
9+
use crate::errors::MismatchedClosingDelimiter;
710

811
#[derive(Default)]
912
pub(super) struct TokenTreeDiagInfo {
13+
/// record span of `(` for diagnostic
14+
pub open_parens: Vec<Span>,
15+
/// record span of `{` for diagnostic
16+
pub open_braces: Vec<Span>,
17+
/// record span of `[` for diagnostic
18+
pub open_brackets: Vec<Span>,
19+
1020
/// Stack of open delimiters and their spans. Used for error message.
1121
pub open_delimiters: Vec<(Delimiter, Span)>,
1222
pub unmatched_delims: Vec<UnmatchedDelim>,
@@ -22,13 +32,58 @@ pub(super) struct TokenTreeDiagInfo {
2232
pub matching_block_spans: Vec<(Span, Span)>,
2333
}
2434

35+
impl TokenTreeDiagInfo {
36+
pub(super) fn push_open_delimiter(&mut self, delim: Delimiter, span: Span) {
37+
self.open_delimiters.push((delim, span));
38+
match delim {
39+
Delimiter::Parenthesis => self.open_parens.push(span),
40+
Delimiter::Brace => self.open_braces.push(span),
41+
Delimiter::Bracket => self.open_brackets.push(span),
42+
_ => {}
43+
}
44+
}
45+
46+
pub(super) fn pop_open_delimiter(&mut self) -> Option<(Delimiter, Span)> {
47+
let (delim, span) = self.open_delimiters.pop()?;
48+
match delim {
49+
Delimiter::Parenthesis => self.open_parens.pop(),
50+
Delimiter::Brace => self.open_braces.pop(),
51+
Delimiter::Bracket => self.open_brackets.pop(),
52+
_ => unreachable!(),
53+
};
54+
Some((delim, span))
55+
}
56+
}
57+
2558
pub(super) fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool {
2659
match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) {
2760
(Some(open_padding), Some(close_padding)) => open_padding == close_padding,
2861
_ => false,
2962
}
3063
}
3164

65+
pub(crate) fn make_unclosed_delims_error(
66+
unmatched: UnmatchedDelim,
67+
psess: &ParseSess,
68+
) -> Option<Diag<'_>> {
69+
// `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
70+
// `unmatched_delims` only for error recovery in the `Parser`.
71+
let found_delim = unmatched.found_delim?;
72+
let mut spans = vec![unmatched.found_span];
73+
if let Some(sp) = unmatched.unclosed_span {
74+
spans.push(sp);
75+
};
76+
let mut err = psess.dcx().create_err(MismatchedClosingDelimiter {
77+
spans,
78+
delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(),
79+
unmatched: unmatched.found_span,
80+
opening_candidate: unmatched.candidate_span,
81+
unclosed: unmatched.unclosed_span,
82+
});
83+
report_missing_open_delim(&mut err, &[unmatched]);
84+
Some(err)
85+
}
86+
3287
// When we get a `)` or `]` for `{`, we should emit help message here
3388
// it's more friendly compared to report `unmatched error` in later phase
3489
fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool {
@@ -58,10 +113,6 @@ pub(super) fn report_suspicious_mismatch_block(
58113
sm: &SourceMap,
59114
delim: Delimiter,
60115
) {
61-
if report_missing_open_delim(err, &diag_info.unmatched_delims) {
62-
return;
63-
}
64-
65116
let mut matched_spans: Vec<(Span, bool)> = diag_info
66117
.matching_block_spans
67118
.iter()

compiler/rustc_parse/src/lexer/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::ops::Range;
22

3+
use diagnostics::make_unclosed_delims_error;
34
use rustc_ast::ast::{self, AttrStyle};
45
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
56
use rustc_ast::tokenstream::TokenStream;
@@ -17,9 +18,9 @@ use rustc_session::parse::ParseSess;
1718
use rustc_span::{BytePos, Pos, Span, Symbol};
1819
use tracing::debug;
1920

21+
use crate::errors;
2022
use crate::lexer::diagnostics::TokenTreeDiagInfo;
2123
use crate::lexer::unicode_chars::UNICODE_ARRAY;
22-
use crate::{errors, make_unclosed_delims_error};
2324

2425
mod diagnostics;
2526
mod tokentrees;

compiler/rustc_parse/src/lexer/tokentrees.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
3636
return if is_delimited {
3737
Ok((open_spacing, TokenStream::new(buf)))
3838
} else {
39+
let matches_previous_open_delim = match delim {
40+
Delimiter::Parenthesis => self.diag_info.open_parens.last().is_some(),
41+
Delimiter::Brace => self.diag_info.open_braces.last().is_some(),
42+
Delimiter::Bracket => self.diag_info.open_brackets.last().is_some(),
43+
_ => unreachable!(),
44+
};
45+
if matches_previous_open_delim {
46+
return Err(vec![]);
47+
}
3948
Err(vec![self.close_delim_err(delim)])
4049
};
4150
}
@@ -102,7 +111,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
102111
// The span for beginning of the delimited section.
103112
let pre_span = self.token.span;
104113

105-
self.diag_info.open_delimiters.push((open_delim, self.token.span));
114+
self.diag_info.push_open_delimiter(open_delim, open_delim_span);
106115

107116
// Lex the token trees within the delimiters.
108117
// We stop at any delimiter so we can try to recover if the user
@@ -117,7 +126,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
117126
// Correct delimiter.
118127
token::CloseDelim(close_delim) if close_delim == open_delim => {
119128
let (open_delimiter, open_delimiter_span) =
120-
self.diag_info.open_delimiters.pop().unwrap();
129+
self.diag_info.pop_open_delimiter().unwrap();
121130
let close_delim_span = self.token.span;
122131

123132
if tts.is_empty() && close_delim == Delimiter::Brace {

compiler/rustc_parse/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
3333

3434
#[macro_use]
3535
pub mod parser;
36-
use parser::{Parser, make_unclosed_delims_error};
36+
use parser::Parser;
3737
pub mod lexer;
3838
pub mod validate_attr;
3939

compiler/rustc_parse/src/parser/mod.rs

+1-25
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,8 @@ use token_type::TokenTypeSet;
4545
pub use token_type::{ExpKeywordPair, ExpTokenPair, TokenType};
4646
use tracing::debug;
4747

48-
use crate::errors::{
49-
self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
50-
};
48+
use crate::errors::{self, IncorrectVisibilityRestriction, NonStringAbiLiteral};
5149
use crate::exp;
52-
use crate::lexer::UnmatchedDelim;
5350

5451
#[cfg(test)]
5552
mod tests;
@@ -1780,27 +1777,6 @@ impl<'a> Parser<'a> {
17801777
}
17811778
}
17821779

1783-
pub(crate) fn make_unclosed_delims_error(
1784-
unmatched: UnmatchedDelim,
1785-
psess: &ParseSess,
1786-
) -> Option<Diag<'_>> {
1787-
// `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
1788-
// `unmatched_delims` only for error recovery in the `Parser`.
1789-
let found_delim = unmatched.found_delim?;
1790-
let mut spans = vec![unmatched.found_span];
1791-
if let Some(sp) = unmatched.unclosed_span {
1792-
spans.push(sp);
1793-
};
1794-
let err = psess.dcx().create_err(MismatchedClosingDelimiter {
1795-
spans,
1796-
delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(),
1797-
unmatched: unmatched.found_span,
1798-
opening_candidate: unmatched.candidate_span,
1799-
unclosed: unmatched.unclosed_span,
1800-
});
1801-
Some(err)
1802-
}
1803-
18041780
/// A helper struct used when building an `AttrTokenStream` from
18051781
/// a `LazyAttrTokenStream`. Both delimiter and non-delimited tokens
18061782
/// are stored as `FlatToken::Token`. A vector of `FlatToken`s

tests/ui/macros/issue-102878.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ error: mismatched closing delimiter: `)`
22
--> $DIR/issue-102878.rs:1:35
33
|
44
LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
5-
| -^ ^ mismatched closing delimiter
6-
| ||
5+
| -^ ^
6+
| || |
7+
| || mismatched closing delimiter
8+
| || missing open `(` for this delimiter
79
| |unclosed delimiter
810
| closing delimiter possibly meant for this
911

tests/ui/parser/deli-ident-issue-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ fn main() {
22
if 1 < 2 {
33
let _a = vec!]; //~ ERROR mismatched closing delimiter
44
}
5-
} //~ ERROR unexpected closing delimiter
5+
}
66

77
fn main() {}

tests/ui/parser/deli-ident-issue-2.stderr

+5-11
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,10 @@ error: mismatched closing delimiter: `]`
44
LL | if 1 < 2 {
55
| ^ unclosed delimiter
66
LL | let _a = vec!];
7-
| ^ mismatched closing delimiter
7+
| ^
8+
| |
9+
| mismatched closing delimiter
10+
| missing open `[` for this delimiter
811

9-
error: unexpected closing delimiter: `}`
10-
--> $DIR/deli-ident-issue-2.rs:5:1
11-
|
12-
LL | let _a = vec!];
13-
| - missing open `[` for this delimiter
14-
LL | }
15-
LL | }
16-
| ^ unexpected closing delimiter
17-
18-
error: aborting due to 2 previous errors
12+
error: aborting due to 1 previous error
1913

tests/ui/parser/do-not-suggest-semicolon-before-array.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ error: mismatched closing delimiter: `)`
22
--> $DIR/do-not-suggest-semicolon-before-array.rs:5:5
33
|
44
LL | [1, 3)
5-
| ^ ^ mismatched closing delimiter
6-
| |
5+
| ^ ^
6+
| | |
7+
| | mismatched closing delimiter
8+
| | missing open `(` for this delimiter
79
| unclosed delimiter
810

911
error: aborting due to 1 previous error

tests/ui/parser/issues/issue-104367.stderr

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ error: mismatched closing delimiter: `)`
22
--> $DIR/issue-104367.rs:5:15
33
|
44
LL | #![w,)
5-
| ^ ^ mismatched closing delimiter
6-
| |
5+
| ^ ^
6+
| | |
7+
| | mismatched closing delimiter
8+
| | missing open `(` for this delimiter
79
| unclosed delimiter
810

911
error: this file contains an unclosed delimiter
@@ -18,7 +20,6 @@ LL | d: [u32; {
1820
LL | #![cfg] {
1921
| - unclosed delimiter
2022
LL | #![w,)
21-
| - missing open `(` for this delimiter
2223
LL |
2324
| ^
2425

tests/ui/parser/issues/issue-105209.stderr

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ error: mismatched closing delimiter: `)`
22
--> $DIR/issue-105209.rs:2:11
33
|
44
LL | #![c={#![c[)x
5-
| ^^ mismatched closing delimiter
6-
| |
5+
| ^^
6+
| ||
7+
| |mismatched closing delimiter
8+
| |missing open `(` for this delimiter
79
| unclosed delimiter
810

911
error: this file contains an unclosed delimiter
1012
--> $DIR/issue-105209.rs:3:68
1113
|
1214
LL | #![c={#![c[)x
13-
| - - - - missing open `(` for this delimiter
14-
| | | |
15-
| | | unclosed delimiter
15+
| - - - unclosed delimiter
16+
| | |
1617
| | unclosed delimiter
1718
| unclosed delimiter
1819
LL |

tests/ui/parser/issues/issue-10636-1.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ struct Obj {
44
)
55
//~^ ERROR mismatched closing delimiter
66
//~| NOTE mismatched closing delimiter
7+
//~| NOTE missing open `(` for this delimiter
78

89
fn main() {}

tests/ui/parser/issues/issue-10636-1.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ LL | struct Obj {
55
| ^ unclosed delimiter
66
...
77
LL | )
8-
| ^ mismatched closing delimiter
8+
| ^
9+
| |
10+
| mismatched closing delimiter
11+
| missing open `(` for this delimiter
912

1013
error: aborting due to 1 previous error
1114

tests/ui/parser/issues/issue-60075.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ LL | fn qux() -> Option<usize> {
55
| ^ unclosed delimiter
66
LL | let _ = if true {
77
LL | });
8-
| ^ mismatched closing delimiter
8+
| ^
9+
| |
10+
| mismatched closing delimiter
11+
| missing open `(` for this delimiter
912

1013
error: aborting due to 1 previous error
1114

tests/ui/parser/issues/issue-62895.stderr

+8-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ LL | mod _ {
55
| ^ unclosed delimiter
66
LL | pub g() -> is
77
LL | (), w20);
8-
| ^ mismatched closing delimiter
8+
| ^
9+
| |
10+
| mismatched closing delimiter
11+
| missing open `(` for this delimiter
912

1013
error: mismatched closing delimiter: `)`
1114
--> $DIR/issue-62895.rs:4:7
@@ -14,7 +17,10 @@ LL | mod _ {
1417
| ^ unclosed delimiter
1518
...
1619
LL | (), w20);
17-
| ^ mismatched closing delimiter
20+
| ^
21+
| |
22+
| mismatched closing delimiter
23+
| missing open `(` for this delimiter
1824

1925
error: aborting due to 2 previous errors
2026

tests/ui/parser/issues/issue-62973.stderr

+10-8
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,28 @@ error: mismatched closing delimiter: `)`
22
--> $DIR/issue-62973.rs:8:27
33
|
44
LL | fn p() { match s { v, E { [) {) }
5-
| ^^ mismatched closing delimiter
6-
| |
5+
| ^^
6+
| ||
7+
| |mismatched closing delimiter
8+
| |missing open `(` for this delimiter
79
| unclosed delimiter
810

911
error: mismatched closing delimiter: `)`
1012
--> $DIR/issue-62973.rs:8:30
1113
|
1214
LL | fn p() { match s { v, E { [) {) }
13-
| ^^ mismatched closing delimiter
14-
| |
15+
| ^^
16+
| ||
17+
| |mismatched closing delimiter
18+
| |missing open `(` for this delimiter
1519
| unclosed delimiter
1620

1721
error: this file contains an unclosed delimiter
1822
--> $DIR/issue-62973.rs:10:2
1923
|
2024
LL | fn p() { match s { v, E { [) {) }
21-
| - - - - missing open `(` for this delimiter
22-
| | | |
23-
| | | missing open `(` for this delimiter
24-
| | unclosed delimiter
25+
| - - unclosed delimiter
26+
| |
2527
| unclosed delimiter
2628
LL |
2729
LL |

0 commit comments

Comments
 (0)