diff options
| author | bors <bors@rust-lang.org> | 2018-09-09 01:36:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-09-09 01:36:58 +0000 |
| commit | 004bc5a33cd44cd0896cae917a75488579126da5 (patch) | |
| tree | d0da7000dd54a3a1bc3e9d24e902fbb99912d38f /src/libsyntax | |
| parent | 0198a1ea45e29af00d92423aa6d2ac876410c3f9 (diff) | |
| parent | 3192d3dc0c4417a6e360018b341c07d32f3f3d7f (diff) | |
| download | rust-004bc5a33cd44cd0896cae917a75488579126da5.tar.gz rust-004bc5a33cd44cd0896cae917a75488579126da5.zip | |
Auto merge of #53949 - estebank:unclosed-delim, r=nikomatsakis
Improve messages for un-closed delimiter errors
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/parse/lexer/mod.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/parse/lexer/tokentrees.rs | 47 | ||||
| -rw-r--r-- | src/libsyntax/source_map.rs | 32 |
3 files changed, 69 insertions, 15 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 96584a580f1..b7e8a880e7e 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -66,6 +66,10 @@ pub struct StringReader<'a> { /// The raw source span which *does not* take `override_span` into account span_src_raw: Span, open_braces: Vec<(token::DelimToken, Span)>, + /// The type and spans for all braces that have different indentation. + /// + /// Used only for error recovery when arriving to EOF with mismatched braces. + suspicious_open_spans: Vec<(token::DelimToken, Span, Span)>, crate override_span: Option<Span>, last_unclosed_found_span: Option<Span>, } @@ -216,6 +220,7 @@ impl<'a> StringReader<'a> { span: syntax_pos::DUMMY_SP, span_src_raw: syntax_pos::DUMMY_SP, open_braces: Vec::new(), + suspicious_open_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 e2fd7faf903..e6ad3b9203e 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -49,9 +49,26 @@ impl<'a> StringReader<'a> { let msg = "this file contains an un-closed delimiter"; let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg); for &(_, sp) in &self.open_braces { - err.span_help(sp, "did you mean to close this delimiter?"); + err.span_label(sp, "un-closed delimiter"); } + if let Some((delim, _)) = self.open_braces.last() { + if let Some((d, open_sp, close_sp)) = self.suspicious_open_spans.iter() + .filter(|(d, _, _)| delim == d) + .next() // these are in reverse order as they get inserted on close, but + { // we want the last open/first close + if d == delim { + 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) }, token::OpenDelim(delim) => { @@ -70,11 +87,20 @@ impl<'a> StringReader<'a> { // Expand to cover the entire delimited token tree let span = pre_span.with_hi(self.span.hi()); + let sm = self.sess.source_map(); match self.token { // Correct delimiter. token::CloseDelim(d) if d == delim => { - self.open_braces.pop().unwrap(); - + let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); + if let Some(current_padding) = sm.span_to_margin(self.span) { + if let Some(padding) = sm.span_to_margin(open_brace_span) { + if current_padding != padding { + self.suspicious_open_spans.push( + (open_brace, open_brace_span, self.span), + ); + } + } + } // Parse the close delimiter. self.real_token(); } @@ -94,8 +120,21 @@ impl<'a> StringReader<'a> { // 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, "unclosed delimiter"); + err.span_label(sp, "un-closed delimiter"); }; + 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", + ); + } + } + } + } err.emit(); } self.open_braces.pop().unwrap(); diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index 95839f94b9e..7ee58350621 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -251,17 +251,18 @@ impl SourceMap { /// crate. The source code of such an "imported source_file" is not available, /// but we still know enough to generate accurate debuginfo location /// information for things inlined from other crates. - pub fn new_imported_source_file(&self, - filename: FileName, - name_was_remapped: bool, - crate_of_origin: u32, - src_hash: u128, - name_hash: u128, - source_len: usize, - mut file_local_lines: Vec<BytePos>, - mut file_local_multibyte_chars: Vec<MultiByteChar>, - mut file_local_non_narrow_chars: Vec<NonNarrowChar>) - -> Lrc<SourceFile> { + pub fn new_imported_source_file( + &self, + filename: FileName, + name_was_remapped: bool, + crate_of_origin: u32, + src_hash: u128, + name_hash: u128, + source_len: usize, + mut file_local_lines: Vec<BytePos>, + mut file_local_multibyte_chars: Vec<MultiByteChar>, + mut file_local_non_narrow_chars: Vec<NonNarrowChar>, + ) -> Lrc<SourceFile> { let start_pos = self.next_start_pos(); let end_pos = Pos::from_usize(start_pos + source_len); @@ -578,6 +579,15 @@ impl SourceMap { .to_string()) } + pub fn span_to_margin(&self, sp: Span) -> Option<usize> { + match self.span_to_prev_source(sp) { + Err(_) => None, + Ok(source) => source.split('\n').last().map(|last_line| { + last_line.len() - last_line.trim_left().len() + }) + } + } + /// Return the source snippet as `String` before the given `Span` pub fn span_to_prev_source(&self, sp: Span) -> Result<String, SpanSnippetError> { self.span_to_source(sp, |src, start_index, _| src[..start_index].to_string()) |
