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
24 changed files with 408 additions and 106 deletions
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_session::parse::ParseSess;
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::{edition::Edition, BytePos, Pos, Span};
|
use rustc_span::{edition::Edition, BytePos, Pos, Span};
|
||||||
|
|
||||||
|
mod diagnostics;
|
||||||
mod tokentrees;
|
mod tokentrees;
|
||||||
mod unescape_error_reporting;
|
mod unescape_error_reporting;
|
||||||
mod unicode_chars;
|
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 super::{StringReader, UnmatchedBrace};
|
||||||
use rustc_ast::token::{self, Delimiter, Token};
|
use rustc_ast::token::{self, Delimiter, Token};
|
||||||
use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
|
use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
|
||||||
use rustc_ast_pretty::pprust::token_to_string;
|
use rustc_ast_pretty::pprust::token_to_string;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
|
||||||
use rustc_errors::{PErr, PResult};
|
use rustc_errors::{PErr, PResult};
|
||||||
use rustc_span::Span;
|
|
||||||
|
|
||||||
pub(super) struct TokenTreesReader<'a> {
|
pub(super) struct TokenTreesReader<'a> {
|
||||||
string_reader: StringReader<'a>,
|
string_reader: StringReader<'a>,
|
||||||
/// The "next" token, which has been obtained from the `StringReader` but
|
/// The "next" token, which has been obtained from the `StringReader` but
|
||||||
/// not yet handled by the `TokenTreesReader`.
|
/// not yet handled by the `TokenTreesReader`.
|
||||||
token: Token,
|
token: Token,
|
||||||
/// Stack of open delimiters and their spans. Used for error message.
|
diag_info: TokenTreeDiagInfo,
|
||||||
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)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TokenTreesReader<'a> {
|
impl<'a> TokenTreesReader<'a> {
|
||||||
|
@ -33,15 +22,10 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
let mut tt_reader = TokenTreesReader {
|
let mut tt_reader = TokenTreesReader {
|
||||||
string_reader,
|
string_reader,
|
||||||
token: Token::dummy(),
|
token: Token::dummy(),
|
||||||
open_braces: Vec::new(),
|
diag_info: TokenTreeDiagInfo::default(),
|
||||||
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(),
|
|
||||||
};
|
};
|
||||||
let res = tt_reader.parse_token_trees(/* is_delimited */ false);
|
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.
|
// Parse a stream of tokens into a list of `TokenTree`s.
|
||||||
|
@ -92,9 +76,9 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
fn eof_err(&mut self) -> PErr<'a> {
|
fn eof_err(&mut self) -> PErr<'a> {
|
||||||
let msg = "this file contains an unclosed delimiter";
|
let msg = "this file contains an unclosed delimiter";
|
||||||
let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
|
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");
|
err.span_label(sp, "unclosed delimiter");
|
||||||
self.unmatched_braces.push(UnmatchedBrace {
|
self.diag_info.unmatched_braces.push(UnmatchedBrace {
|
||||||
expected_delim: Delimiter::Brace,
|
expected_delim: Delimiter::Brace,
|
||||||
found_delim: None,
|
found_delim: None,
|
||||||
found_span: self.token.span,
|
found_span: self.token.span,
|
||||||
|
@ -103,23 +87,13 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((delim, _)) = self.open_braces.last() {
|
if let Some((delim, _)) = self.diag_info.open_braces.last() {
|
||||||
if let Some((_, open_sp, close_sp)) =
|
report_suspicious_mismatch_block(
|
||||||
self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
|
&mut err,
|
||||||
let sm = self.string_reader.sess.source_map();
|
&self.diag_info,
|
||||||
if let Some(close_padding) = sm.span_to_margin(*close_sp) {
|
&self.string_reader.sess.source_map(),
|
||||||
if let Some(open_padding) = sm.span_to_margin(*open_sp) {
|
*delim,
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
@ -128,7 +102,7 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
// The span for beginning of the delimited section
|
// The span for beginning of the delimited section
|
||||||
let pre_span = self.token.span;
|
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.
|
// Parse the token trees within the delimiters.
|
||||||
// We stop at any delimiter so we can try to recover if the user
|
// We stop at any delimiter so we can try to recover if the user
|
||||||
|
@ -137,35 +111,29 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
|
|
||||||
// Expand to cover the entire delimited token tree
|
// Expand to cover the entire delimited token tree
|
||||||
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
|
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
|
||||||
|
let sm = self.string_reader.sess.source_map();
|
||||||
|
|
||||||
match self.token.kind {
|
match self.token.kind {
|
||||||
// Correct delimiter.
|
// Correct delimiter.
|
||||||
token::CloseDelim(close_delim) if close_delim == open_delim => {
|
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;
|
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 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) {
|
if !sm.is_multiline(empty_block_span) {
|
||||||
// Only track if the block is in the form of `{}`, otherwise it is
|
// Only track if the block is in the form of `{}`, otherwise it is
|
||||||
// likely that it was written on purpose.
|
// 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) {
|
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.
|
// Move past the closing delimiter.
|
||||||
self.token = self.string_reader.next_token().0;
|
self.token = self.string_reader.next_token().0;
|
||||||
}
|
}
|
||||||
|
@ -174,28 +142,25 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
let mut unclosed_delimiter = None;
|
let mut unclosed_delimiter = None;
|
||||||
let mut candidate = 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
|
// 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
|
// This is a conservative error: only report the last unclosed
|
||||||
// delimiter. The previous unclosed delimiters could actually be
|
// delimiter. The previous unclosed delimiters could actually be
|
||||||
// closed! The parser just hasn't gotten to them yet.
|
// 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);
|
unclosed_delimiter = Some(sp);
|
||||||
};
|
};
|
||||||
let sm = self.string_reader.sess.source_map();
|
for (brace, brace_span) in &self.diag_info.open_braces {
|
||||||
if let Some(current_padding) = sm.span_to_margin(self.token.span) {
|
if same_identation_level(&sm, self.token.span, *brace_span)
|
||||||
for (brace, brace_span) in &self.open_braces {
|
&& brace == &close_delim
|
||||||
if let Some(padding) = sm.span_to_margin(*brace_span) {
|
{
|
||||||
// high likelihood of these two corresponding
|
// high likelihood of these two corresponding
|
||||||
if current_padding == padding && brace == &close_delim {
|
candidate = Some(*brace_span);
|
||||||
candidate = Some(*brace_span);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (tok, _) = self.open_braces.pop().unwrap();
|
let (tok, _) = self.diag_info.open_braces.pop().unwrap();
|
||||||
self.unmatched_braces.push(UnmatchedBrace {
|
self.diag_info.unmatched_braces.push(UnmatchedBrace {
|
||||||
expected_delim: tok,
|
expected_delim: tok,
|
||||||
found_delim: Some(close_delim),
|
found_delim: Some(close_delim),
|
||||||
found_span: self.token.span,
|
found_span: self.token.span,
|
||||||
|
@ -203,7 +168,7 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
candidate_span: candidate,
|
candidate_span: candidate,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.open_braces.pop();
|
self.diag_info.open_braces.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the incorrect delimiter matches an earlier opening
|
// If the incorrect delimiter matches an earlier opening
|
||||||
|
@ -213,7 +178,7 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
// fn foo() {
|
// fn foo() {
|
||||||
// bar(baz(
|
// bar(baz(
|
||||||
// } // Incorrect delimiter but matches the earlier `{`
|
// } // 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;
|
self.token = self.string_reader.next_token().0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,22 +201,12 @@ impl<'a> TokenTreesReader<'a> {
|
||||||
let mut err =
|
let mut err =
|
||||||
self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
|
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
|
report_suspicious_mismatch_block(
|
||||||
if let Some(parent) = self.matching_block_spans.last() {
|
&mut err,
|
||||||
if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
|
&self.diag_info,
|
||||||
// Check if the (empty block) is in the last properly closed block
|
&self.string_reader.sess.source_map(),
|
||||||
if (parent.0.to(parent.1)).contains(span) {
|
delim,
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err.span_label(self.token.span, "unexpected closing delimiter");
|
err.span_label(self.token.span, "unexpected closing delimiter");
|
||||||
err
|
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
|
--> $DIR/issue-81827.rs:11:27
|
||||||
|
|
|
|
||||||
LL | fn r()->i{0|{#[cfg(r(0{]0
|
LL | fn r()->i{0|{#[cfg(r(0{]0
|
||||||
| - - ^
|
| - - - ^
|
||||||
| | |
|
| | | |
|
||||||
|
| | | missing open `[` for this delimiter
|
||||||
| | unclosed delimiter
|
| | unclosed delimiter
|
||||||
| unclosed delimiter
|
| unclosed delimiter
|
||||||
|
|
||||||
|
@ -11,8 +12,9 @@ error: this file contains an unclosed delimiter
|
||||||
--> $DIR/issue-81827.rs:11:27
|
--> $DIR/issue-81827.rs:11:27
|
||||||
|
|
|
|
||||||
LL | fn r()->i{0|{#[cfg(r(0{]0
|
LL | fn r()->i{0|{#[cfg(r(0{]0
|
||||||
| - - ^
|
| - - - ^
|
||||||
| | |
|
| | | |
|
||||||
|
| | | missing open `[` for this delimiter
|
||||||
| | unclosed delimiter
|
| | unclosed delimiter
|
||||||
| unclosed delimiter
|
| unclosed delimiter
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@ error: this file contains an unclosed delimiter
|
||||||
--> $DIR/issue-62973.rs:8:2
|
--> $DIR/issue-62973.rs:8:2
|
||||||
|
|
|
|
||||||
LL | fn p() { match s { v, E { [) {) }
|
LL | fn p() { match s { v, E { [) {) }
|
||||||
| - - unclosed delimiter
|
| - - - - missing open `(` for this delimiter
|
||||||
| |
|
| | | |
|
||||||
|
| | | missing open `(` for this delimiter
|
||||||
|
| | unclosed delimiter
|
||||||
| unclosed delimiter
|
| unclosed delimiter
|
||||||
LL |
|
LL |
|
||||||
LL |
|
LL |
|
||||||
|
@ -13,8 +15,10 @@ error: this file contains an unclosed delimiter
|
||||||
--> $DIR/issue-62973.rs:8:2
|
--> $DIR/issue-62973.rs:8:2
|
||||||
|
|
|
|
||||||
LL | fn p() { match s { v, E { [) {) }
|
LL | fn p() { match s { v, E { [) {) }
|
||||||
| - - unclosed delimiter
|
| - - - - missing open `(` for this delimiter
|
||||||
| |
|
| | | |
|
||||||
|
| | | missing open `(` for this delimiter
|
||||||
|
| | unclosed delimiter
|
||||||
| unclosed delimiter
|
| unclosed delimiter
|
||||||
LL |
|
LL |
|
||||||
LL |
|
LL |
|
||||||
|
|
|
@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter
|
||||||
--> $DIR/issue-63116.rs:3:18
|
--> $DIR/issue-63116.rs:3:18
|
||||||
|
|
|
|
||||||
LL | impl W <s(f;Y(;]
|
LL | impl W <s(f;Y(;]
|
||||||
| - ^
|
| - - ^
|
||||||
| |
|
| | |
|
||||||
|
| | missing open `[` for this delimiter
|
||||||
| unclosed delimiter
|
| unclosed delimiter
|
||||||
|
|
||||||
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;`
|
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
|
--> $DIR/issue-70583-block-is-empty-1.rs:20:1
|
||||||
|
|
|
|
||||||
LL | fn struct_generic(x: Vec<i32>) {
|
LL | fn struct_generic(x: Vec<i32>) {
|
||||||
| - this opening brace...
|
| - this delimiter might not be properly closed...
|
||||||
...
|
...
|
||||||
LL | }
|
LL | }
|
||||||
| - ...matches this closing brace
|
| - ...as it matches this but it has different indentation
|
||||||
LL | }
|
LL | }
|
||||||
| ^ unexpected closing delimiter
|
| ^ unexpected closing delimiter
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
error: unexpected closing delimiter: `}`
|
error: unexpected closing delimiter: `}`
|
||||||
--> $DIR/issue-70583-block-is-empty-2.rs:14:1
|
--> $DIR/issue-70583-block-is-empty-2.rs:14:1
|
||||||
|
|
|
|
||||||
|
LL | match self {
|
||||||
|
| - this delimiter might not be properly closed...
|
||||||
LL | ErrorHandled::Reported => {}}
|
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 | }
|
LL | }
|
||||||
| ^ unexpected closing delimiter
|
| ^ unexpected closing delimiter
|
||||||
|
|
|
@ -2,10 +2,10 @@ error: unexpected closing delimiter: `}`
|
||||||
--> $DIR/macro-mismatched-delim-paren-brace.rs:5:1
|
--> $DIR/macro-mismatched-delim-paren-brace.rs:5:1
|
||||||
|
|
|
|
||||||
LL | fn main() {
|
LL | fn main() {
|
||||||
| - this opening brace...
|
| - this delimiter might not be properly closed...
|
||||||
...
|
...
|
||||||
LL | }
|
LL | }
|
||||||
| - ...matches this closing brace
|
| - ...as it matches this but it has different indentation
|
||||||
LL | }
|
LL | }
|
||||||
| ^ unexpected closing delimiter
|
| ^ unexpected closing delimiter
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter
|
||||||
--> $DIR/issue-91334.rs:10:23
|
--> $DIR/issue-91334.rs:10:23
|
||||||
|
|
|
|
||||||
LL | fn f(){||yield(((){),
|
LL | fn f(){||yield(((){),
|
||||||
| - - ^
|
| - - - ^
|
||||||
| | |
|
| | | |
|
||||||
|
| | | missing open `(` for this delimiter
|
||||||
| | unclosed delimiter
|
| | unclosed delimiter
|
||||||
| unclosed delimiter
|
| unclosed delimiter
|
||||||
|
|
||||||
|
@ -11,8 +12,9 @@ error: this file contains an unclosed delimiter
|
||||||
--> $DIR/issue-91334.rs:10:23
|
--> $DIR/issue-91334.rs:10:23
|
||||||
|
|
|
|
||||||
LL | fn f(){||yield(((){),
|
LL | fn f(){||yield(((){),
|
||||||
| - - ^
|
| - - - ^
|
||||||
| | |
|
| | | |
|
||||||
|
| | | missing open `(` for this delimiter
|
||||||
| | unclosed delimiter
|
| | unclosed delimiter
|
||||||
| unclosed delimiter
|
| unclosed delimiter
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue