Rollup merge of #104012 - chenyukang:yukang/fix-103882-deli-indentation, r=petrochenkov
Improve unexpected close and mismatch delimiter hint in TokenTreesReader Fixes #103882 Fixes #68987 Fixes #69259 The inner indentation mismatching will be covered by outer block, the new added function `report_error_prone_delim_block` will find out the error prone candidates for reporting.
This commit is contained in:
commit
e3048c7838
119
compiler/rustc_parse/src/lexer/diagnostics.rs
Normal file
119
compiler/rustc_parse/src/lexer/diagnostics.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use super::UnmatchedBrace;
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TokenTreeDiagInfo {
|
||||
/// Stack of open delimiters and their spans. Used for error message.
|
||||
pub open_braces: Vec<(Delimiter, Span)>,
|
||||
pub unmatched_braces: Vec<UnmatchedBrace>,
|
||||
|
||||
/// Used only for error recovery when arriving to EOF with mismatched braces.
|
||||
pub last_unclosed_found_span: Option<Span>,
|
||||
|
||||
/// Collect empty block spans that might have been auto-inserted by editors.
|
||||
pub empty_block_spans: Vec<Span>,
|
||||
|
||||
/// Collect the spans of braces (Open, Close). Used only
|
||||
/// for detecting if blocks are empty and only braces.
|
||||
pub matching_block_spans: Vec<(Span, Span)>,
|
||||
}
|
||||
|
||||
pub fn same_identation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool {
|
||||
match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) {
|
||||
(Some(open_padding), Some(close_padding)) => open_padding == close_padding,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// When we get a `)` or `]` for `{`, we should emit help message here
|
||||
// it's more friendly compared to report `unmatched error` in later phase
|
||||
pub fn report_missing_open_delim(
|
||||
err: &mut Diagnostic,
|
||||
unmatched_braces: &[UnmatchedBrace],
|
||||
) -> bool {
|
||||
let mut reported_missing_open = false;
|
||||
for unmatch_brace in unmatched_braces.iter() {
|
||||
if let Some(delim) = unmatch_brace.found_delim
|
||||
&& matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket)
|
||||
{
|
||||
let missed_open = match delim {
|
||||
Delimiter::Parenthesis => "(",
|
||||
Delimiter::Bracket => "[",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
err.span_label(
|
||||
unmatch_brace.found_span.shrink_to_lo(),
|
||||
format!("missing open `{}` for this delimiter", missed_open),
|
||||
);
|
||||
reported_missing_open = true;
|
||||
}
|
||||
}
|
||||
reported_missing_open
|
||||
}
|
||||
|
||||
pub fn report_suspicious_mismatch_block(
|
||||
err: &mut Diagnostic,
|
||||
diag_info: &TokenTreeDiagInfo,
|
||||
sm: &SourceMap,
|
||||
delim: Delimiter,
|
||||
) {
|
||||
if report_missing_open_delim(err, &diag_info.unmatched_braces) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut matched_spans: Vec<(Span, bool)> = diag_info
|
||||
.matching_block_spans
|
||||
.iter()
|
||||
.map(|&(open, close)| (open.with_hi(close.lo()), same_identation_level(sm, open, close)))
|
||||
.collect();
|
||||
|
||||
// sort by `lo`, so the large block spans in the front
|
||||
matched_spans.sort_by(|a, b| a.0.lo().cmp(&b.0.lo()));
|
||||
|
||||
// We use larger block whose identation is well to cover those inner mismatched blocks
|
||||
// O(N^2) here, but we are on error reporting path, so it is fine
|
||||
for i in 0..matched_spans.len() {
|
||||
let (block_span, same_ident) = matched_spans[i];
|
||||
if same_ident {
|
||||
for j in i + 1..matched_spans.len() {
|
||||
let (inner_block, inner_same_ident) = matched_spans[j];
|
||||
if block_span.contains(inner_block) && !inner_same_ident {
|
||||
matched_spans[j] = (inner_block, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the inner-most span candidate for final report
|
||||
let candidate_span =
|
||||
matched_spans.into_iter().rev().find(|&(_, same_ident)| !same_ident).map(|(span, _)| span);
|
||||
|
||||
if let Some(block_span) = candidate_span {
|
||||
err.span_label(block_span.shrink_to_lo(), "this delimiter might not be properly closed...");
|
||||
err.span_label(
|
||||
block_span.shrink_to_hi(),
|
||||
"...as it matches this but it has different indentation",
|
||||
);
|
||||
|
||||
// If there is a empty block in the mismatched span, note it
|
||||
if delim == Delimiter::Brace {
|
||||
for span in diag_info.empty_block_spans.iter() {
|
||||
if block_span.contains(*span) {
|
||||
err.span_label(*span, "block is empty, you might have not meant to close it");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If there is no suspicious span, give the last properly closed block may help
|
||||
if let Some(parent) = diag_info.matching_block_spans.last()
|
||||
&& diag_info.open_braces.last().is_none()
|
||||
&& diag_info.empty_block_spans.iter().all(|&sp| sp != parent.0.to(parent.1)) {
|
||||
err.span_label(parent.0, "this opening brace...");
|
||||
err.span_label(parent.1, "...matches this closing brace");
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{edition::Edition, BytePos, Pos, Span};
|
||||
|
||||
mod diagnostics;
|
||||
mod tokentrees;
|
||||
mod unescape_error_reporting;
|
||||
mod unicode_chars;
|
||||
|
@ -1,29 +1,18 @@
|
||||
use super::diagnostics::report_suspicious_mismatch_block;
|
||||
use super::diagnostics::same_identation_level;
|
||||
use super::diagnostics::TokenTreeDiagInfo;
|
||||
use super::{StringReader, UnmatchedBrace};
|
||||
use rustc_ast::token::{self, Delimiter, Token};
|
||||
use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast_pretty::pprust::token_to_string;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{PErr, PResult};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub(super) struct TokenTreesReader<'a> {
|
||||
string_reader: StringReader<'a>,
|
||||
/// The "next" token, which has been obtained from the `StringReader` but
|
||||
/// not yet handled by the `TokenTreesReader`.
|
||||
token: Token,
|
||||
/// Stack of open delimiters and their spans. Used for error message.
|
||||
open_braces: Vec<(Delimiter, Span)>,
|
||||
unmatched_braces: Vec<UnmatchedBrace>,
|
||||
/// The type and spans for all braces
|
||||
///
|
||||
/// Used only for error recovery when arriving to EOF with mismatched braces.
|
||||
matching_delim_spans: Vec<(Delimiter, Span, Span)>,
|
||||
last_unclosed_found_span: Option<Span>,
|
||||
/// Collect empty block spans that might have been auto-inserted by editors.
|
||||
last_delim_empty_block_spans: FxHashMap<Delimiter, Span>,
|
||||
/// Collect the spans of braces (Open, Close). Used only
|
||||
/// for detecting if blocks are empty and only braces.
|
||||
matching_block_spans: Vec<(Span, Span)>,
|
||||
diag_info: TokenTreeDiagInfo,
|
||||
}
|
||||
|
||||
impl<'a> TokenTreesReader<'a> {
|
||||
@ -33,15 +22,10 @@ pub(super) fn parse_all_token_trees(
|
||||
let mut tt_reader = TokenTreesReader {
|
||||
string_reader,
|
||||
token: Token::dummy(),
|
||||
open_braces: Vec::new(),
|
||||
unmatched_braces: Vec::new(),
|
||||
matching_delim_spans: Vec::new(),
|
||||
last_unclosed_found_span: None,
|
||||
last_delim_empty_block_spans: FxHashMap::default(),
|
||||
matching_block_spans: Vec::new(),
|
||||
diag_info: TokenTreeDiagInfo::default(),
|
||||
};
|
||||
let res = tt_reader.parse_token_trees(/* is_delimited */ false);
|
||||
(res, tt_reader.unmatched_braces)
|
||||
(res, tt_reader.diag_info.unmatched_braces)
|
||||
}
|
||||
|
||||
// Parse a stream of tokens into a list of `TokenTree`s.
|
||||
@ -92,9 +76,9 @@ fn parse_token_trees(&mut self, is_delimited: bool) -> PResult<'a, TokenStream>
|
||||
fn eof_err(&mut self) -> PErr<'a> {
|
||||
let msg = "this file contains an unclosed delimiter";
|
||||
let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
|
||||
for &(_, sp) in &self.open_braces {
|
||||
for &(_, sp) in &self.diag_info.open_braces {
|
||||
err.span_label(sp, "unclosed delimiter");
|
||||
self.unmatched_braces.push(UnmatchedBrace {
|
||||
self.diag_info.unmatched_braces.push(UnmatchedBrace {
|
||||
expected_delim: Delimiter::Brace,
|
||||
found_delim: None,
|
||||
found_span: self.token.span,
|
||||
@ -103,23 +87,13 @@ fn eof_err(&mut self) -> PErr<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
if let Some((delim, _)) = self.open_braces.last() {
|
||||
if let Some((_, open_sp, close_sp)) =
|
||||
self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
|
||||
let sm = self.string_reader.sess.source_map();
|
||||
if let Some(close_padding) = sm.span_to_margin(*close_sp) {
|
||||
if let Some(open_padding) = sm.span_to_margin(*open_sp) {
|
||||
return delim == d && close_padding != open_padding;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
// these are in reverse order as they get inserted on close, but
|
||||
{
|
||||
// we want the last open/first close
|
||||
err.span_label(*open_sp, "this delimiter might not be properly closed...");
|
||||
err.span_label(*close_sp, "...as it matches this but it has different indentation");
|
||||
}
|
||||
if let Some((delim, _)) = self.diag_info.open_braces.last() {
|
||||
report_suspicious_mismatch_block(
|
||||
&mut err,
|
||||
&self.diag_info,
|
||||
&self.string_reader.sess.source_map(),
|
||||
*delim,
|
||||
)
|
||||
}
|
||||
err
|
||||
}
|
||||
@ -128,7 +102,7 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
|
||||
// The span for beginning of the delimited section
|
||||
let pre_span = self.token.span;
|
||||
|
||||
self.open_braces.push((open_delim, self.token.span));
|
||||
self.diag_info.open_braces.push((open_delim, self.token.span));
|
||||
|
||||
// Parse the token trees within the delimiters.
|
||||
// We stop at any delimiter so we can try to recover if the user
|
||||
@ -137,35 +111,29 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
|
||||
|
||||
// Expand to cover the entire delimited token tree
|
||||
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
|
||||
let sm = self.string_reader.sess.source_map();
|
||||
|
||||
match self.token.kind {
|
||||
// Correct delimiter.
|
||||
token::CloseDelim(close_delim) if close_delim == open_delim => {
|
||||
let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
|
||||
let (open_brace, open_brace_span) = self.diag_info.open_braces.pop().unwrap();
|
||||
let close_brace_span = self.token.span;
|
||||
|
||||
if tts.is_empty() {
|
||||
if tts.is_empty() && close_delim == Delimiter::Brace {
|
||||
let empty_block_span = open_brace_span.to(close_brace_span);
|
||||
let sm = self.string_reader.sess.source_map();
|
||||
if !sm.is_multiline(empty_block_span) {
|
||||
// Only track if the block is in the form of `{}`, otherwise it is
|
||||
// likely that it was written on purpose.
|
||||
self.last_delim_empty_block_spans.insert(open_delim, empty_block_span);
|
||||
self.diag_info.empty_block_spans.push(empty_block_span);
|
||||
}
|
||||
}
|
||||
|
||||
//only add braces
|
||||
// only add braces
|
||||
if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) {
|
||||
self.matching_block_spans.push((open_brace_span, close_brace_span));
|
||||
// Add all the matching spans, we will sort by span later
|
||||
self.diag_info.matching_block_spans.push((open_brace_span, close_brace_span));
|
||||
}
|
||||
|
||||
if self.open_braces.is_empty() {
|
||||
// Clear up these spans to avoid suggesting them as we've found
|
||||
// properly matched delimiters so far for an entire block.
|
||||
self.matching_delim_spans.clear();
|
||||
} else {
|
||||
self.matching_delim_spans.push((open_brace, open_brace_span, close_brace_span));
|
||||
}
|
||||
// Move past the closing delimiter.
|
||||
self.token = self.string_reader.next_token().0;
|
||||
}
|
||||
@ -174,28 +142,25 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
|
||||
let mut unclosed_delimiter = None;
|
||||
let mut candidate = None;
|
||||
|
||||
if self.last_unclosed_found_span != Some(self.token.span) {
|
||||
if self.diag_info.last_unclosed_found_span != Some(self.token.span) {
|
||||
// do not complain about the same unclosed delimiter multiple times
|
||||
self.last_unclosed_found_span = Some(self.token.span);
|
||||
self.diag_info.last_unclosed_found_span = Some(self.token.span);
|
||||
// This is a conservative error: only report the last unclosed
|
||||
// delimiter. The previous unclosed delimiters could actually be
|
||||
// closed! The parser just hasn't gotten to them yet.
|
||||
if let Some(&(_, sp)) = self.open_braces.last() {
|
||||
if let Some(&(_, sp)) = self.diag_info.open_braces.last() {
|
||||
unclosed_delimiter = Some(sp);
|
||||
};
|
||||
let sm = self.string_reader.sess.source_map();
|
||||
if let Some(current_padding) = sm.span_to_margin(self.token.span) {
|
||||
for (brace, brace_span) in &self.open_braces {
|
||||
if let Some(padding) = sm.span_to_margin(*brace_span) {
|
||||
// high likelihood of these two corresponding
|
||||
if current_padding == padding && brace == &close_delim {
|
||||
candidate = Some(*brace_span);
|
||||
}
|
||||
}
|
||||
for (brace, brace_span) in &self.diag_info.open_braces {
|
||||
if same_identation_level(&sm, self.token.span, *brace_span)
|
||||
&& brace == &close_delim
|
||||
{
|
||||
// high likelihood of these two corresponding
|
||||
candidate = Some(*brace_span);
|
||||
}
|
||||
}
|
||||
let (tok, _) = self.open_braces.pop().unwrap();
|
||||
self.unmatched_braces.push(UnmatchedBrace {
|
||||
let (tok, _) = self.diag_info.open_braces.pop().unwrap();
|
||||
self.diag_info.unmatched_braces.push(UnmatchedBrace {
|
||||
expected_delim: tok,
|
||||
found_delim: Some(close_delim),
|
||||
found_span: self.token.span,
|
||||
@ -203,7 +168,7 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
|
||||
candidate_span: candidate,
|
||||
});
|
||||
} else {
|
||||
self.open_braces.pop();
|
||||
self.diag_info.open_braces.pop();
|
||||
}
|
||||
|
||||
// If the incorrect delimiter matches an earlier opening
|
||||
@ -213,7 +178,7 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
|
||||
// fn foo() {
|
||||
// bar(baz(
|
||||
// } // Incorrect delimiter but matches the earlier `{`
|
||||
if !self.open_braces.iter().any(|&(b, _)| b == close_delim) {
|
||||
if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) {
|
||||
self.token = self.string_reader.next_token().0;
|
||||
}
|
||||
}
|
||||
@ -236,22 +201,12 @@ fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'a> {
|
||||
let mut err =
|
||||
self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
|
||||
|
||||
// Braces are added at the end, so the last element is the biggest block
|
||||
if let Some(parent) = self.matching_block_spans.last() {
|
||||
if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
|
||||
// Check if the (empty block) is in the last properly closed block
|
||||
if (parent.0.to(parent.1)).contains(span) {
|
||||
err.span_label(span, "block is empty, you might have not meant to close it");
|
||||
} else {
|
||||
err.span_label(parent.0, "this opening brace...");
|
||||
err.span_label(parent.1, "...matches this closing brace");
|
||||
}
|
||||
} else {
|
||||
err.span_label(parent.0, "this opening brace...");
|
||||
err.span_label(parent.1, "...matches this closing brace");
|
||||
}
|
||||
}
|
||||
|
||||
report_suspicious_mismatch_block(
|
||||
&mut err,
|
||||
&self.diag_info,
|
||||
&self.string_reader.sess.source_map(),
|
||||
delim,
|
||||
);
|
||||
err.span_label(self.token.span, "unexpected closing delimiter");
|
||||
err
|
||||
}
|
||||
|
24
tests/ui/parser/deli-ident-issue-1.rs
Normal file
24
tests/ui/parser/deli-ident-issue-1.rs
Normal file
@ -0,0 +1,24 @@
|
||||
#![feature(let_chains)]
|
||||
trait Demo {}
|
||||
|
||||
impl dyn Demo {
|
||||
pub fn report(&self) -> u32 {
|
||||
let sum = |a: u32,
|
||||
b: u32,
|
||||
c: u32| {
|
||||
a + b + c
|
||||
};
|
||||
sum(1, 2, 3)
|
||||
}
|
||||
|
||||
fn check(&self, val: Option<u32>, num: Option<u32>) {
|
||||
if let Some(b) = val
|
||||
&& let Some(c) = num {
|
||||
&& b == c {
|
||||
//~^ ERROR expected struct
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { } //~ ERROR this file contains an unclosed delimiter
|
37
tests/ui/parser/deli-ident-issue-1.stderr
Normal file
37
tests/ui/parser/deli-ident-issue-1.stderr
Normal file
@ -0,0 +1,37 @@
|
||||
error: this file contains an unclosed delimiter
|
||||
--> $DIR/deli-ident-issue-1.rs:24:66
|
||||
|
|
||||
LL | impl dyn Demo {
|
||||
| - unclosed delimiter
|
||||
...
|
||||
LL | && let Some(c) = num {
|
||||
| - this delimiter might not be properly closed...
|
||||
...
|
||||
LL | }
|
||||
| - ...as it matches this but it has different indentation
|
||||
...
|
||||
LL | fn main() { }
|
||||
| ^
|
||||
|
||||
error[E0574]: expected struct, variant or union type, found local variable `c`
|
||||
--> $DIR/deli-ident-issue-1.rs:17:17
|
||||
|
|
||||
LL | && b == c {
|
||||
| ^ not a struct, variant or union type
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deli-ident-issue-1.rs:17:9
|
||||
|
|
||||
LL | fn check(&self, val: Option<u32>, num: Option<u32>) {
|
||||
| - expected `()` because of default return type
|
||||
...
|
||||
LL | / && b == c {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_________^ expected `()`, found `bool`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0574.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
7
tests/ui/parser/deli-ident-issue-2.rs
Normal file
7
tests/ui/parser/deli-ident-issue-2.rs
Normal file
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
if 1 < 2 {
|
||||
let _a = vec!]; //~ ERROR mismatched closing delimiter
|
||||
}
|
||||
} //~ ERROR unexpected closing delimiter
|
||||
|
||||
fn main() {}
|
19
tests/ui/parser/deli-ident-issue-2.stderr
Normal file
19
tests/ui/parser/deli-ident-issue-2.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error: unexpected closing delimiter: `}`
|
||||
--> $DIR/deli-ident-issue-2.rs:5:1
|
||||
|
|
||||
LL | let _a = vec!];
|
||||
| - missing open `[` for this delimiter
|
||||
LL | }
|
||||
LL | }
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
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: aborting due to 2 previous errors
|
||||
|
12
tests/ui/parser/issue-68987-unmatch-issue-1.rs
Normal file
12
tests/ui/parser/issue-68987-unmatch-issue-1.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// This file has unexpected closing delimiter,
|
||||
|
||||
fn func(o: Option<u32>) {
|
||||
match o {
|
||||
Some(_x) => {} // Extra '}'
|
||||
let _ = if true {};
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
} //~ ERROR unexpected closing delimiter
|
||||
|
||||
fn main() {}
|
16
tests/ui/parser/issue-68987-unmatch-issue-1.stderr
Normal file
16
tests/ui/parser/issue-68987-unmatch-issue-1.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error: unexpected closing delimiter: `}`
|
||||
--> $DIR/issue-68987-unmatch-issue-1.rs:10:1
|
||||
|
|
||||
LL | match o {
|
||||
| - this delimiter might not be properly closed...
|
||||
LL | Some(_x) => {} // Extra '}'
|
||||
| -- block is empty, you might have not meant to close it
|
||||
LL | let _ = if true {};
|
||||
LL | }
|
||||
| - ...as it matches this but it has different indentation
|
||||
...
|
||||
LL | }
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
error: aborting due to previous error
|
||||
|
14
tests/ui/parser/issue-68987-unmatch-issue-2.rs
Normal file
14
tests/ui/parser/issue-68987-unmatch-issue-2.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// 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
|
||||
async {
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(version, scene_list) = obs_connect() {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
} //~ ERROR unexpected closing delimiter
|
19
tests/ui/parser/issue-68987-unmatch-issue-2.stderr
Normal file
19
tests/ui/parser/issue-68987-unmatch-issue-2.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error: unexpected closing delimiter: `}`
|
||||
--> $DIR/issue-68987-unmatch-issue-2.rs:14:1
|
||||
|
|
||||
LL | let obs_connect = || -> Result<(), MyError) {
|
||||
| - missing open `(` for this delimiter
|
||||
...
|
||||
LL | }
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
error: mismatched closing delimiter: `)`
|
||||
--> $DIR/issue-68987-unmatch-issue-2.rs:3:32
|
||||
|
|
||||
LL | async fn obstest() -> Result<> {
|
||||
| ^ unclosed delimiter
|
||||
LL | let obs_connect = || -> Result<(), MyError) {
|
||||
| ^ mismatched closing delimiter
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
8
tests/ui/parser/issue-68987-unmatch-issue-3.rs
Normal file
8
tests/ui/parser/issue-68987-unmatch-issue-3.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// the `{` is closed with `)`, there is a missing `(`
|
||||
fn f(i: u32, j: u32) {
|
||||
let res = String::new();
|
||||
let mut cnt = i;
|
||||
while cnt < j {
|
||||
write!&mut res, " "); //~ ERROR mismatched closing delimiter
|
||||
}
|
||||
} //~ ERROR unexpected closing delimiter
|
19
tests/ui/parser/issue-68987-unmatch-issue-3.stderr
Normal file
19
tests/ui/parser/issue-68987-unmatch-issue-3.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error: unexpected closing delimiter: `}`
|
||||
--> $DIR/issue-68987-unmatch-issue-3.rs:8:1
|
||||
|
|
||||
LL | write!&mut res, " ");
|
||||
| - missing open `(` for this delimiter
|
||||
LL | }
|
||||
LL | }
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
error: mismatched closing delimiter: `)`
|
||||
--> $DIR/issue-68987-unmatch-issue-3.rs:5:19
|
||||
|
|
||||
LL | while cnt < j {
|
||||
| ^ unclosed delimiter
|
||||
LL | write!&mut res, " ");
|
||||
| ^ mismatched closing delimiter
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
12
tests/ui/parser/issue-68987-unmatch-issue.rs
Normal file
12
tests/ui/parser/issue-68987-unmatch-issue.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// This file has unexpected closing delimiter,
|
||||
|
||||
fn func(o: Option<u32>) {
|
||||
match o {
|
||||
Some(_x) => // Missing '{'
|
||||
let _ = if true {};
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
} //~ ERROR unexpected closing delimiter
|
||||
|
||||
fn main() {}
|
16
tests/ui/parser/issue-68987-unmatch-issue.stderr
Normal file
16
tests/ui/parser/issue-68987-unmatch-issue.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error: unexpected closing delimiter: `}`
|
||||
--> $DIR/issue-68987-unmatch-issue.rs:10:1
|
||||
|
|
||||
LL | match o {
|
||||
| - this delimiter might not be properly closed...
|
||||
LL | Some(_x) => // Missing '{'
|
||||
LL | let _ = if true {};
|
||||
| -- block is empty, you might have not meant to close it
|
||||
LL | }
|
||||
| - ...as it matches this but it has different indentation
|
||||
...
|
||||
LL | }
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-81827.rs:11:27
|
||||
|
|
||||
LL | fn r()->i{0|{#[cfg(r(0{]0
|
||||
| - - ^
|
||||
| | |
|
||||
| - - - ^
|
||||
| | | |
|
||||
| | | missing open `[` for this delimiter
|
||||
| | unclosed delimiter
|
||||
| unclosed delimiter
|
||||
|
||||
@ -11,8 +12,9 @@ error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-81827.rs:11:27
|
||||
|
|
||||
LL | fn r()->i{0|{#[cfg(r(0{]0
|
||||
| - - ^
|
||||
| | |
|
||||
| - - - ^
|
||||
| | | |
|
||||
| | | missing open `[` for this delimiter
|
||||
| | unclosed delimiter
|
||||
| unclosed delimiter
|
||||
|
||||
|
@ -2,8 +2,10 @@ error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-62973.rs:8:2
|
||||
|
|
||||
LL | fn p() { match s { v, E { [) {) }
|
||||
| - - unclosed delimiter
|
||||
| |
|
||||
| - - - - missing open `(` for this delimiter
|
||||
| | | |
|
||||
| | | missing open `(` for this delimiter
|
||||
| | unclosed delimiter
|
||||
| unclosed delimiter
|
||||
LL |
|
||||
LL |
|
||||
@ -13,8 +15,10 @@ error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-62973.rs:8:2
|
||||
|
|
||||
LL | fn p() { match s { v, E { [) {) }
|
||||
| - - unclosed delimiter
|
||||
| |
|
||||
| - - - - missing open `(` for this delimiter
|
||||
| | | |
|
||||
| | | missing open `(` for this delimiter
|
||||
| | unclosed delimiter
|
||||
| unclosed delimiter
|
||||
LL |
|
||||
LL |
|
||||
|
@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-63116.rs:3:18
|
||||
|
|
||||
LL | impl W <s(f;Y(;]
|
||||
| - ^
|
||||
| |
|
||||
| - - ^
|
||||
| | |
|
||||
| | missing open `[` for this delimiter
|
||||
| unclosed delimiter
|
||||
|
||||
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;`
|
||||
|
3
tests/ui/parser/issues/issue-69259.rs
Normal file
3
tests/ui/parser/issues/issue-69259.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {}
|
||||
|
||||
fn f) {} //~ ERROR unexpected closing delimiter
|
8
tests/ui/parser/issues/issue-69259.stderr
Normal file
8
tests/ui/parser/issues/issue-69259.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: unexpected closing delimiter: `)`
|
||||
--> $DIR/issue-69259.rs:3:5
|
||||
|
|
||||
LL | fn f) {}
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -2,10 +2,10 @@ error: unexpected closing delimiter: `}`
|
||||
--> $DIR/issue-70583-block-is-empty-1.rs:20:1
|
||||
|
|
||||
LL | fn struct_generic(x: Vec<i32>) {
|
||||
| - this opening brace...
|
||||
| - this delimiter might not be properly closed...
|
||||
...
|
||||
LL | }
|
||||
| - ...matches this closing brace
|
||||
| - ...as it matches this but it has different indentation
|
||||
LL | }
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
error: unexpected closing delimiter: `}`
|
||||
--> $DIR/issue-70583-block-is-empty-2.rs:14:1
|
||||
|
|
||||
LL | match self {
|
||||
| - this delimiter might not be properly closed...
|
||||
LL | ErrorHandled::Reported => {}}
|
||||
| -- block is empty, you might have not meant to close it
|
||||
| --- ...as it matches this but it has different indentation
|
||||
| |
|
||||
| block is empty, you might have not meant to close it
|
||||
...
|
||||
LL | }
|
||||
| ^ unexpected closing delimiter
|
||||
|
@ -2,10 +2,10 @@ error: unexpected closing delimiter: `}`
|
||||
--> $DIR/macro-mismatched-delim-paren-brace.rs:5:1
|
||||
|
|
||||
LL | fn main() {
|
||||
| - this opening brace...
|
||||
| - this delimiter might not be properly closed...
|
||||
...
|
||||
LL | }
|
||||
| - ...matches this closing brace
|
||||
| - ...as it matches this but it has different indentation
|
||||
LL | }
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
|
@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-91334.rs:10:23
|
||||
|
|
||||
LL | fn f(){||yield(((){),
|
||||
| - - ^
|
||||
| | |
|
||||
| - - - ^
|
||||
| | | |
|
||||
| | | missing open `(` for this delimiter
|
||||
| | unclosed delimiter
|
||||
| unclosed delimiter
|
||||
|
||||
@ -11,8 +12,9 @@ error: this file contains an unclosed delimiter
|
||||
--> $DIR/issue-91334.rs:10:23
|
||||
|
|
||||
LL | fn f(){||yield(((){),
|
||||
| - - ^
|
||||
| | |
|
||||
| - - - ^
|
||||
| | | |
|
||||
| | | missing open `(` for this delimiter
|
||||
| | unclosed delimiter
|
||||
| unclosed delimiter
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user