about summary refs log tree commit diff
path: root/src/libsyntax/parse/lexer
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-01-27 21:04:50 -0800
committerEsteban Küber <esteban@kuber.com.ar>2019-02-07 01:41:30 -0800
commit7451cd8dc0b20c012fad1886b321c3dee2052577 (patch)
tree564bb3390199f080413ec319481f3f37fa345054 /src/libsyntax/parse/lexer
parent825f355c7483746f3a17166f34dfabe3b2df1741 (diff)
downloadrust-7451cd8dc0b20c012fad1886b321c3dee2052577.tar.gz
rust-7451cd8dc0b20c012fad1886b321c3dee2052577.zip
Deduplicate mismatched delimiter errors
Delay unmatched delimiter errors until after the parser has run to
deduplicate them when parsing and attempt recovering intelligently.
Diffstat (limited to 'src/libsyntax/parse/lexer')
-rw-r--r--src/libsyntax/parse/lexer/mod.rs11
-rw-r--r--src/libsyntax/parse/lexer/tokentrees.rs30
2 files changed, 26 insertions, 15 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 2e3233c8ed8..d3fc1c03634 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -33,6 +33,15 @@ impl Default for TokenAndSpan {
     }
 }
 
+#[derive(Clone, Debug)]
+pub struct UnmatchedBrace {
+    pub expected_delim: token::DelimToken,
+    pub found_delim: token::DelimToken,
+    pub found_span: Span,
+    pub unclosed_span: Option<Span>,
+    pub candidate_span: Option<Span>,
+}
+
 pub struct StringReader<'a> {
     pub sess: &'a ParseSess,
     /// The absolute offset within the source_map of the next character to read
@@ -58,6 +67,7 @@ pub struct StringReader<'a> {
     span_src_raw: Span,
     /// Stack of open delimiters and their spans. Used for error message.
     open_braces: Vec<(token::DelimToken, Span)>,
+    crate unmatched_braces: Vec<UnmatchedBrace>,
     /// The type and spans for all braces
     ///
     /// Used only for error recovery when arriving to EOF with mismatched braces.
@@ -222,6 +232,7 @@ impl<'a> StringReader<'a> {
             span: syntax_pos::DUMMY_SP,
             span_src_raw: syntax_pos::DUMMY_SP,
             open_braces: Vec::new(),
+            unmatched_braces: Vec::new(),
             matching_delim_spans: Vec::new(),
             override_span,
             last_unclosed_found_span: None,
diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index 7699d9eab22..0db36c84cdf 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -1,5 +1,5 @@
 use crate::print::pprust::token_to_string;
-use crate::parse::lexer::StringReader;
+use crate::parse::lexer::{StringReader, UnmatchedBrace};
 use crate::parse::{token, PResult};
 use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint};
 
@@ -101,38 +101,38 @@ impl<'a> StringReader<'a> {
                     }
                     // Incorrect delimiter.
                     token::CloseDelim(other) => {
-                        let token_str = token_to_string(&self.token);
+                        let mut unclosed_delimiter = None;
+                        let mut candidate = None;
                         if self.last_unclosed_found_span != Some(self.span) {
                             // do not complain about the same unclosed delimiter multiple times
                             self.last_unclosed_found_span = Some(self.span);
-                            let msg = format!("incorrect close delimiter: `{}`", token_str);
-                            let mut err = self.sess.span_diagnostic.struct_span_err(
-                                self.span,
-                                &msg,
-                            );
-                            err.span_label(self.span, "incorrect close delimiter");
                             // 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() {
-                                err.span_label(sp, "un-closed delimiter");
+                                unclosed_delimiter = Some(sp);
                             };
                             if let Some(current_padding) = sm.span_to_margin(self.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 == &other {
-                                            err.span_label(
-                                                *brace_span,
-                                                "close delimiter possibly meant for this",
-                                            );
+                                            candidate = Some(*brace_span);
                                         }
                                     }
                                 }
                             }
-                            err.emit();
+                            let (tok, _) = self.open_braces.pop().unwrap();
+                            self.unmatched_braces.push(UnmatchedBrace {
+                                expected_delim: tok,
+                                found_delim: other,
+                                found_span: self.span,
+                                unclosed_span: unclosed_delimiter,
+                                candidate_span: candidate,
+                            });
+                        } else {
+                            self.open_braces.pop();
                         }
-                        self.open_braces.pop().unwrap();
 
                         // If the incorrect delimiter matches an earlier opening
                         // delimiter, then don't consume it (it can be used to