-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Try to recover from unmatched delimiters in the parser #54029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0036e72
b5b9299
46ffe9d
3942ad4
8605d87
413912a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// 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 A; | ||
|
||
impl A { | ||
fn banana(&mut self) { | ||
fn peach(this: &Self, foo: usize { | ||
//~^ ERROR expected one of | ||
//~| ERROR can't use type parameters from outer function | ||
} | ||
} | ||
//~^ ERROR incorrect close delimiter | ||
//~| ERROR expected expression | ||
} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
error: incorrect close delimiter: `}` | ||
--> $DIR/parser-recovery-3.rs:19:5 | ||
| | ||
LL | fn banana(&mut self) { | ||
| - close delimiter possibly meant for this | ||
LL | fn peach(this: &Self, foo: usize { | ||
| - un-closed delimiter | ||
... | ||
LL | } | ||
| ^ incorrect close delimiter | ||
|
||
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's kind of surprising to me that this advice comes here, in a second error after the "main" error above... why is that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The lexer first performs the basic matching braces checks and emits the appropriate error. Then the parser takes the tokenstream and tries to parse things. So the first error is about the lexer finding unbalanced delimiters, while the second one is a parse error not finding an expected close delimiter. There're two options: keeping the un-emitted DiagnosticBuilders from the lexer and emitting them once we are parsing and find an appropriate place for the close delimiter suggestion, or completely stop performing balanced delimiter checks in the lexer and rely entirely on the parser for parse errors. Both felt like too much work for little win. I'd prefer to iterate this PR until we have the recovery nailed down before revisiting the above possibilities. |
||
--> $DIR/parser-recovery-3.rs:15:42 | ||
| | ||
LL | fn peach(this: &Self, foo: usize { | ||
| - -^ expected one of 7 possible tokens here | ||
| | | | ||
| | help: ...the missing `)` may belong here | ||
| if you meant to close this... | ||
|
||
error: expected expression, found `)` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "found There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mmm... This is surprising. I'm not sure why the parser is finding a |
||
--> $DIR/parser-recovery-3.rs:19:5 | ||
| | ||
LL | } | ||
| ^ expected expression | ||
|
||
error[E0401]: can't use type parameters from outer function | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. still, nice that we recovered here |
||
--> $DIR/parser-recovery-3.rs:15:25 | ||
| | ||
LL | impl A { | ||
| ---- `Self` type implicitly declared here, by this `impl` | ||
LL | fn banana(&mut self) { | ||
LL | fn peach(this: &Self, foo: usize { | ||
| ^^^^ | ||
| | | ||
| use of type variable from outer function | ||
| use a type here instead | ||
|
||
error: aborting due to 4 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0401`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// 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. | ||
|
||
fn foo(_: usize) {} | ||
fn bar() {} | ||
|
||
fn main() { | ||
let x = 1; | ||
foo(x | ||
bar() | ||
//~^ ERROR expected one of | ||
//~| ERROR expected one of | ||
} | ||
//~^ ERROR incorrect close delimiter |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
error: incorrect close delimiter: `}` | ||
--> $DIR/parser-recovery-4.rs:20:1 | ||
| | ||
LL | fn main() { | ||
| - close delimiter possibly meant for this | ||
LL | let x = 1; | ||
LL | foo(x | ||
| - un-closed delimiter | ||
... | ||
LL | } | ||
| ^ incorrect close delimiter | ||
|
||
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `bar` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. something feels..inelegant to me here. Like, I would like to be suppressing these "fallout" errors, and just picking up parsing from some other point..? Hmm, I'm not sure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is an option, to just bail on parsing the entire block from that point on, as we do in other parts of the parser. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem with out right bailing until the next closing brace is that we then don't get the nice recovery shown above. Maybe that's a reasonable trade-off... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. which is the nice recovery you are referring to? I tend to think that giving "false errors" is kind of the most confusing thing we can do and we should bias in favor of too few errors and not too many, but opinions vary. |
||
--> $DIR/parser-recovery-4.rs:17:5 | ||
| | ||
LL | foo(x | ||
| - - | ||
| | | | ||
| | expected one of 8 possible tokens here | ||
| | help: ...the missing `)` may belong here | ||
| if you meant to close this... | ||
LL | bar() | ||
| ^^^ unexpected token | ||
|
||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `bar` | ||
--> $DIR/parser-recovery-4.rs:17:5 | ||
| | ||
LL | foo(x | ||
| - expected one of `.`, `;`, `?`, `}`, or an operator here | ||
LL | bar() | ||
| ^^^ unexpected token | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the ideal end state, this error would not get emitted, instead having the prior one be
but I'm not sure how to verify that we don't start suggesting bogus code that wouldn't work... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I understand. But I do think that this example you just gave is kind of cluttered -- I feel like it'd be better to break it apart into multiple sections or something. |
||
|
||
error: aborting due to 3 previous errors | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,43 @@ | ||
error: incorrect close delimiter: `}` | ||
--> $DIR/token-error-correct-3.rs:30:9 | ||
--> $DIR/token-error-correct-3.rs:27:9 | ||
| | ||
LL | if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory` | ||
LL | if !is_directory(path.as_ref()) { | ||
| - close delimiter possibly meant for this | ||
LL | callback(path.as_ref(); //~ ERROR expected one of | ||
LL | callback(path.as_ref(); | ||
| - un-closed delimiter | ||
... | ||
LL | } else { //~ ERROR: incorrect close delimiter: `}` | ||
LL | } else { | ||
| ^ incorrect close delimiter | ||
|
||
error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` | ||
--> $DIR/token-error-correct-3.rs:24:35 | ||
| | ||
LL | callback(path.as_ref(); //~ ERROR expected one of | ||
| ^ expected one of `)`, `,`, `.`, `?`, or an operator here | ||
LL | callback(path.as_ref(); | ||
| - ^ | ||
| | | | ||
| | expected one of `)`, `,`, `.`, `?`, or an operator here | ||
| | help: ...the missing `)` may belong here | ||
| if you meant to close this... | ||
|
||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` | ||
--> $DIR/token-error-correct-3.rs:30:9 | ||
--> $DIR/token-error-correct-3.rs:27:9 | ||
| | ||
LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types | ||
LL | fs::create_dir_all(path.as_ref()).map(|()| true) | ||
| - expected one of `.`, `;`, `?`, `}`, or an operator here | ||
... | ||
LL | } else { //~ ERROR: incorrect close delimiter: `}` | ||
LL | } else { | ||
| ^ unexpected token | ||
|
||
error[E0425]: cannot find function `is_directory` in this scope | ||
--> $DIR/token-error-correct-3.rs:23:13 | ||
| | ||
LL | if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory` | ||
| ^^^^^^^^^^^^ not found in this scope | ||
|
||
error[E0308]: mismatched types | ||
--> $DIR/token-error-correct-3.rs:25:13 | ||
--> $DIR/token-error-correct-3.rs:26:13 | ||
| | ||
LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types | ||
LL | fs::create_dir_all(path.as_ref()).map(|()| true) | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` | ||
| | | ||
| expected (), found enum `std::result::Result` | ||
| | ||
= note: expected type `()` | ||
found type `std::result::Result<bool, std::io::Error>` | ||
|
||
error: aborting due to 5 previous errors | ||
error: aborting due to 4 previous errors | ||
|
||
Some errors occurred: E0308, E0425. | ||
For more information about an error, try `rustc --explain E0308`. | ||
For more information about this error, try `rustc --explain E0308`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,52 @@ | ||
error: incorrect close delimiter: `}` | ||
--> $DIR/token-error-correct.rs:16:1 | ||
--> $DIR/token-error-correct.rs:19:1 | ||
| | ||
LL | fn main() { | ||
| - close delimiter possibly meant for this | ||
LL | foo(bar(; | ||
| - un-closed delimiter | ||
LL | //~^ ERROR: expected expression, found `;` | ||
... | ||
LL | } | ||
| ^ incorrect close delimiter | ||
|
||
error: expected expression, found `;` | ||
--> $DIR/token-error-correct.rs:14:13 | ||
| | ||
LL | foo(bar(; | ||
| ^ expected expression | ||
| - ^ | ||
| | | | ||
| | expected expression | ||
| | help: ...the missing `)` may belong here | ||
| if you meant to close this... | ||
|
||
error: aborting due to 2 previous errors | ||
error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` | ||
--> $DIR/token-error-correct.rs:14:13 | ||
| | ||
LL | foo(bar(; | ||
| -^ | ||
| || | ||
| |expected one of `)`, `,`, `.`, `?`, or an operator here | ||
| |help: ...the missing `)` may belong here | ||
| if you meant to close this... | ||
|
||
error: expected expression, found `)` | ||
--> $DIR/token-error-correct.rs:19:1 | ||
| | ||
LL | } | ||
| ^ expected expression | ||
|
||
error[E0425]: cannot find function `foo` in this scope | ||
--> $DIR/token-error-correct.rs:14:5 | ||
| | ||
LL | foo(bar(; | ||
| ^^^ not found in this scope | ||
|
||
error[E0425]: cannot find function `bar` in this scope | ||
--> $DIR/token-error-correct.rs:14:9 | ||
| | ||
LL | foo(bar(; | ||
| ^^^ not found in this scope | ||
|
||
error: aborting due to 6 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0425`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this mean that for rustc invocations that don't read the source from a file but from stdin we don't get these suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. On the one hand, those will not have any worse output. On the other, this was a bit explorative and want to nail it down before trying to get to to work in all cases.