Skip to content

Commit

Permalink
Rollup merge of rust-lang#53949 - estebank:unclosed-delim, r=nikomats…
Browse files Browse the repository at this point in the history
…akis

Improve messages for un-closed delimiter errors
  • Loading branch information
Mark-Simulacrum committed Sep 8, 2018
2 parents 4d187ae + 3192d3d commit 1e5e014
Show file tree
Hide file tree
Showing 16 changed files with 171 additions and 40 deletions.
5 changes: 5 additions & 0 deletions src/libsyntax/parse/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
}
Expand Down Expand Up @@ -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,
}
Expand Down
47 changes: 43 additions & 4 deletions src/libsyntax/parse/lexer/tokentrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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();
}
Expand All @@ -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();
Expand Down
32 changes: 21 additions & 11 deletions src/libsyntax/source_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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())
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/issue-10636-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

// compile-flags: -Z parse-only

struct Obj { //~ NOTE: unclosed delimiter
struct Obj {
//~^ NOTE: un-closed delimiter
member: usize
)
//~^ ERROR incorrect close delimiter
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/issue-10636-1.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
error: incorrect close delimiter: `)`
--> $DIR/issue-10636-1.rs:15:1
--> $DIR/issue-10636-1.rs:16:1
|
LL | struct Obj { //~ NOTE: unclosed delimiter
| - unclosed delimiter
LL | member: usize
LL | struct Obj {
| - un-closed delimiter
...
LL | )
| ^ incorrect close delimiter

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@

// compile-flags: -Z parse-only

fn foo() { //~ HELP did you mean to close this delimiter?
fn foo() { //~ NOTE un-closed delimiter
match Some(x) {
//~^ NOTE this delimiter might not be properly closed...
Some(y) => { panic!(); }
None => { panic!(); }
}
//~^ NOTE ...as it matches this but it has different indentation

fn bar() {
let mut i = 0;
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/issue-2354.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: this file contains an un-closed delimiter
--> $DIR/issue-2354.rs:26:66
|
LL | fn foo() { //~ NOTE un-closed delimiter
| - un-closed delimiter
LL | match Some(x) {
| - this delimiter might not be properly closed...
...
LL | }
| - ...as it matches this but it has different indentation
...
LL | fn main() {} //~ ERROR this file contains an un-closed delimiter
| ^

error: aborting due to previous error

9 changes: 5 additions & 4 deletions src/test/ui/parser-recovery-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@

trait Foo {
fn bar() {
let x = foo(); //~ ERROR cannot find function `foo` in this scope

let x = foo();
//~^ ERROR cannot find function `foo` in this scope
}

fn main() {
let x = y.; //~ ERROR unexpected token
//~^ ERROR cannot find value `y` in this scope
let x = y.;
//~^ ERROR unexpected token
//~| ERROR cannot find value `y` in this scope
} //~ ERROR this file contains an un-closed delimiter
22 changes: 12 additions & 10 deletions src/test/ui/parser-recovery-1.stderr
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
error: this file contains an un-closed delimiter
--> $DIR/parser-recovery-1.rs:24:55
--> $DIR/parser-recovery-1.rs:25:55
|
LL | trait Foo {
| - un-closed delimiter
LL | fn bar() {
| - this delimiter might not be properly closed...
...
LL | }
| - ...as it matches this but it has different indentation
...
LL | } //~ ERROR this file contains an un-closed delimiter
| ^
|
help: did you mean to close this delimiter?
--> $DIR/parser-recovery-1.rs:15:11
|
LL | trait Foo {
| ^

error: unexpected token: `;`
--> $DIR/parser-recovery-1.rs:22:15
|
LL | let x = y.; //~ ERROR unexpected token
LL | let x = y.;
| ^

error[E0425]: cannot find function `foo` in this scope
--> $DIR/parser-recovery-1.rs:17:17
|
LL | let x = foo(); //~ ERROR cannot find function `foo` in this scope
LL | let x = foo();
| ^^^ not found in this scope

error[E0425]: cannot find value `y` in this scope
--> $DIR/parser-recovery-1.rs:22:13
|
LL | let x = y.; //~ ERROR unexpected token
LL | let x = y.;
| ^ not found in this scope

error[E0601]: `main` function not found in crate `parser_recovery_1`
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/parser-recovery-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: incorrect close delimiter: `)`
--> $DIR/parser-recovery-2.rs:18:5
|
LL | fn bar() {
| - unclosed delimiter
| - un-closed delimiter
LL | let x = foo(); //~ ERROR cannot find function `foo` in this scope
LL | ) //~ ERROR incorrect close delimiter: `)`
| ^ incorrect close delimiter
Expand Down
32 changes: 32 additions & 0 deletions src/test/ui/parser/unclosed-braces.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct S {
x: [usize; 3],
}

fn foo() {
{
{
println!("hi");
}
}
}

fn main() {
//~^ NOTE un-closed delimiter
{
{
//~^ NOTE this delimiter might not be properly closed...
foo();
}
//~^ NOTE ...as it matches this but it has different indentation
}
//~ ERROR this file contains an un-closed delimiter
17 changes: 17 additions & 0 deletions src/test/ui/parser/unclosed-braces.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error: this file contains an un-closed delimiter
--> $DIR/unclosed-braces.rs:32:53
|
LL | fn main() {
| - un-closed delimiter
...
LL | {
| - this delimiter might not be properly closed...
...
LL | }
| - ...as it matches this but it has different indentation
...
LL | //~ ERROR this file contains an un-closed delimiter
| ^

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/resolve/token-error-correct-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: incorrect close delimiter: `)`
--> $DIR/token-error-correct-2.rs:16:5
|
LL | if foo {
| - unclosed delimiter
| - un-closed delimiter
LL | //~^ ERROR: cannot find value `foo`
LL | ) //~ ERROR: incorrect close delimiter: `)`
| ^ incorrect close delimiter
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/resolve/token-error-correct-3.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
error: incorrect close delimiter: `}`
--> $DIR/token-error-correct-3.rs:30:9
|
LL | if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory`
| - close delimiter possibly meant for this
LL | callback(path.as_ref(); //~ ERROR expected one of
| - unclosed delimiter
| - un-closed delimiter
...
LL | } else { //~ ERROR: incorrect close delimiter: `}`
| ^ incorrect close delimiter
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/resolve/token-error-correct.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
error: incorrect close delimiter: `}`
--> $DIR/token-error-correct.rs:16:1
|
LL | fn main() {
| - close delimiter possibly meant for this
LL | foo(bar(;
| - unclosed delimiter
| - un-closed delimiter
LL | //~^ ERROR: expected expression, found `;`
LL | }
| ^ incorrect close delimiter
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/token/issue-10636-2.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
error: incorrect close delimiter: `}`
--> $DIR/issue-10636-2.rs:18:1
|
LL | pub fn trace_option(option: Option<isize>) {
| - close delimiter possibly meant for this
LL | option.map(|some| 42;
| - unclosed delimiter
| - un-closed delimiter
...
LL | } //~ ERROR: incorrect close delimiter
| ^ incorrect close delimiter
Expand Down

0 comments on commit 1e5e014

Please sign in to comment.