Skip to content
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

Try to recover from unmatched delimiters in the parser #54029

Closed

Conversation

estebank
Copy link
Contributor

@estebank estebank commented Sep 7, 2018

Follow up to #53949.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 7, 2018
mut err: DiagnosticBuilder<'a>,
) -> PResult<'a, ()> {
let mut pos = None;
let mut tokens: Vec<token::Token> = tokens.iter().map(|t| (*t).clone()).collect();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't that just tokens.to_vec()?

sess: &ParseSess,
override_span: Option<Span>,
) -> TokenStream {
source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span).0
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@rust-highfive

This comment has been minimized.

@nikomatsakis

This comment has been minimized.

@estebank

This comment has been minimized.

@bors

This comment has been minimized.

@estebank estebank force-pushed the unclosed-delim-the-next-generation branch from 7a222ae to 0036e72 Compare September 11, 2018 13:49
//~| ERROR expected expression
fs::create_dir_all(path.as_ref()).map(|()| true)
} else {
//~^ ERROR incorrect close delimiter: `}`
Ok(false);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the ideal output for this file?

I'll get back to this over the weekend to see if I can make the parser recover from missing delimiters and parse the rest correctly, so that we get the type error about fs::create_dir_all back.

@estebank
Copy link
Contributor Author

@nikomatsakis ready for a proper review.

@rust-highfive

This comment has been minimized.

@estebank estebank force-pushed the unclosed-delim-the-next-generation branch from 2962e35 to 8605d87 Compare September 11, 2018 20:19
// - - ^ expected one of `)`, <...>
// | |
// | help: ...missing `)` might belong here
// you might have meant to close this...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really the right spot? I would have suggested us to suggest adding the ) after the {}, like so {foo(bar {})}, not {foo(bar) {}}, which doesn't look to me like it would parse

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I'm intrigued on wether the comment is correct, at all...

I'd like to create a bunch of real "broken" code samples to test against, which would give me more confidence that what I'm doing in this PR is beneficial.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would help me too, since I'm starting my reviews by just looking at the test cases (I haven't really looked at the code at all yet)

LL | }
| ^ incorrect close delimiter

error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

LL | }
| ^ expected expression

error[E0401]: can't use type parameters from outer function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still, nice that we recovered here

| | help: ...the missing `)` may belong here
| if you meant to close this...

error: expected expression, found `)`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"found )" is confusing too...?

Copy link
Contributor Author

@estebank estebank Sep 12, 2018

Choose a reason for hiding this comment

The 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 ) at all here...

LL | }
| ^ incorrect close delimiter

error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `bar`
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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...

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

LL | foo(x
| - expected one of `.`, `;`, `?`, `}`, or an operator here
LL | bar()
| ^^^ unexpected token
Copy link
Contributor Author

@estebank estebank Sep 12, 2018

Choose a reason for hiding this comment

The 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

error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `bar`
  --> $DIR/parser-recovery-4.rs:17:5
   |
LL |     foo(x
   |        - -- help: you might also be missing a semicolon here: `;`
   |        | |
   |        | expected one of 8 possible tokens here
   |        | help: ...the missing `)` may belong here
   |        if you meant to close this...
LL |     bar()
   |     ^^^ unexpected token

but I'm not sure how to verify that we don't start suggesting bogus code that wouldn't work...

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

@nikomatsakis
Copy link
Contributor

@estebank are you planning to make changes here?

@estebank
Copy link
Contributor Author

@nikomatsakis yes. I have a couple of alternative approaches that I'm going to try out once I have spare time. Rough timeline, next 2 weeks at the latest.

@nikomatsakis nikomatsakis added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 25, 2018
@nikomatsakis
Copy link
Contributor

OK.

@bors
Copy link
Contributor

bors commented Oct 11, 2018

☔ The latest upstream changes (presumably #54969) made this pull request unmergeable. Please resolve the merge conflicts.

@TimNN
Copy link
Contributor

TimNN commented Oct 16, 2018

Ping from triage @estebank: What is the status of this PR?

@estebank
Copy link
Contributor Author

@TimNN I'll close to clear the backlog and reopen once I get back to it.

@estebank estebank closed this Oct 16, 2018
bors added a commit that referenced this pull request Feb 7, 2019
Deduplicate mismatched delimiter errors

Delay unmatched delimiter errors until after the parser has run to deduplicate them when parsing and attempt recovering intelligently.

Second attempt at #54029, follow up to #53949. Fix #31528.
bors added a commit that referenced this pull request Feb 8, 2019
Deduplicate mismatched delimiter errors

Delay unmatched delimiter errors until after the parser has run to deduplicate them when parsing and attempt recovering intelligently.

Second attempt at #54029, follow up to #53949. Fix #31528.
bors added a commit that referenced this pull request Feb 9, 2019
Deduplicate mismatched delimiter errors

Delay unmatched delimiter errors until after the parser has run to deduplicate them when parsing and attempt recovering intelligently.

Second attempt at #54029, follow up to #53949. Fix #31528.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants