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

Do not emit type errors on recovered blocks #46732

Merged
merged 2 commits into from
Dec 22, 2017

Conversation

estebank
Copy link
Contributor

When a parse error occurs on a block, the parser will recover and create
a block with the statements collected until that point. Now a flag
stating that a recovery has been performed in this block is propagated
so that the type checker knows that the type of the block (which will be
identified as ()) shouldn't be checked against the expectation to
reduce the amount of irrelevant diagnostic errors shown to the user.

Fix #44579.

@rust-highfive
Copy link
Collaborator

r? @petrochenkov

(rust_highfive has picked a reviewer for you, use r? to override)

@estebank estebank added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 14, 2017
@estebank estebank force-pushed the silence-recovered-blocks branch from ce52a2d to d2d3f94 Compare December 14, 2017 21:12
@petrochenkov
Copy link
Contributor

The case reported in #44579 is 100% reasonable recovery.
The "mismatched types" error is exactly what would be reported if the pub struct Pub items wasn't ill-formed, so I'd close this as not-a-defect.

(Also, the "unmatched visibility" wording was really weird and unhelpful (unmatched with what?), it's really nice that it's changed to "missing struct" on nightly.)

@petrochenkov
Copy link
Contributor

Output on nightly, the first error is much more visible now:

error: missing `struct` for struct definition
  --> src/main.rs:11:8
   |
11 |     pub Foo { text }    // NB: Syntax error here
   |        ^
help: add `struct` here to parse `Foo` as a public struct
   |
11 |     pub struct Foo { text }    // NB: Syntax error here
   |         ^^^^^^

error[E0308]: mismatched types
  --> src/main.rs:7:23
   |
7  |   pub fn parse() -> Foo {
   |  _______________________^
8  | |     let args: Vec<String> = env::args().collect();
9  | |     let text = args[1].clone();
10 | |     
11 | |     pub Foo { text }    // NB: Syntax error here
12 | | }
   | |_^ expected struct `Foo`, found ()
   |
   = note: expected type `Foo`
              found type `()`

@estebank
Copy link
Contributor Author

@petrochenkov the first error is more prominent now in this case, but any syntax error will cause the type error to happen. Consider the following case instead:

pub struct Foo {
    text: String
}

pub fn parse() -> Foo {
    fn
    Foo { text: "".to_string() }
}
error: expected one of `(` or `<`, found `{`
 --> src/main.rs:7:9
  |
7 |     Foo { text: "".to_string() }
  |         ^ expected one of `(` or `<` here

error[E0308]: mismatched types
 --> src/main.rs:5:23
  |
5 |   pub fn parse() -> Foo {
  |  _______________________^
6 | |     fn
7 | |     Foo { text: "".to_string() }
8 | | }
  | |_^ expected struct `Foo`, found ()
  |
  = note: expected type `Foo`
             found type `()`

error: aborting due to 2 previous errors

The second error won't happen once the syntax error is fixed, but the compiler can't know that, and it is still the most vertically prominent error in the output. I feel that masking the type error when we know the block had a parse error (that we made an effort to continue after) is a better default.

@estebank estebank force-pushed the silence-recovered-blocks branch 2 times, most recently from c6ceea9 to d99aef8 Compare December 14, 2017 23:40
@bors
Copy link
Contributor

bors commented Dec 15, 2017

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

@estebank estebank force-pushed the silence-recovered-blocks branch 2 times, most recently from 0d5a2f8 to 736e9b8 Compare December 15, 2017 07:55
@petrochenkov
Copy link
Contributor

If some piece of code look so similar to a legal statement that we recover it as a legal statement (e.g. an item statement in case of pub struct Foo), then it should not poison the outer block in which it's defined, only possibly its inner block.

pub fn parse() -> Foo { <not_poisoned>
    let args: Vec<String> = env::args().collect();
    let text = args[1].clone();
    
    pub Foo { <poisoned> text </poisoned> }
</not_poisoned> }

In the example with fn it looks like we don't recover fn Foo { text: "".to_string() } as a function item statement, it's interpreted as just some random token soup. In this case it should indeed poison the block in which it's defined.

pub fn parse() -> Foo { <poisoned>
    fn
    Foo { text: "".to_string() }
</poisoned> }

I need to make some experiments.

@estebank estebank force-pushed the silence-recovered-blocks branch 4 times, most recently from d5c526f to 0d5b144 Compare December 16, 2017 01:16
}))
}

/// Parse a statement, including the trailing semicolon.
pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
let mut stmt = match self.parse_stmt_(macro_legacy_warnings) {
let mut stmt = match self.parse_stmt_without_recovery(macro_legacy_warnings)? {
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to be a change independent from adding the recovered flag to blocks?
From what I see in the test diffs I'd keep this recovery in place.

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 recovery happens in the callee already, and using parse_stmt_ swallows errors that we do want to see in parse_block_tail.


pub Foo { text }
}
//~^^ ERROR missing `struct` for struct definition
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add the example with fn (#46732 (comment)) as a test too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added

@petrochenkov
Copy link
Contributor

r=me with comments addressed

I still want to look at the statement recovery more carefully, but not right now (probably replace the recovered flag with ExprKind::Err and statements based on it). Into backlog it goes...

@kennytm kennytm 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 Dec 16, 2017
@estebank estebank force-pushed the silence-recovered-blocks branch 2 times, most recently from 9e392e2 to 351f06a Compare December 18, 2017 05:59
@estebank
Copy link
Contributor Author

@bors r=petrochencov

@bors
Copy link
Contributor

bors commented Dec 18, 2017

📌 Commit 351f06a has been approved by petrochencov

@bors
Copy link
Contributor

bors commented Dec 18, 2017

⌛ Testing commit 351f06a with merge 184693d...

bors added a commit that referenced this pull request Dec 18, 2017
Do not emit type errors on recovered blocks

When a parse error occurs on a block, the parser will recover and create
a block with the statements collected until that point. Now a flag
stating that a recovery has been performed in this block is propagated
so that the type checker knows that the type of the block (which will be
identified as `()`) shouldn't be checked against the expectation to
reduce the amount of irrelevant diagnostic errors shown to the user.

Fix #44579.
@bors
Copy link
Contributor

bors commented Dec 18, 2017

💔 Test failed - status-appveyor

@petrochenkov
Copy link
Contributor

How do we deal with cross-repo commits?

rustfmt and rls are marked as "Broken" in https://github.com/rust-lang/rust/blob/master/src/tools/toolstate.toml, a pull request to rustfmt can be sent asyncroniously.

@estebank
Copy link
Contributor Author

Already marked as broken, looks like the failure was due to sscache.

@bors r=petrochenkov

@bors
Copy link
Contributor

bors commented Dec 18, 2017

📌 Commit 351f06a has been approved by petrochenkov

@bors
Copy link
Contributor

bors commented Dec 19, 2017

⌛ Testing commit 351f06a with merge a6c1141a37b6b16e467ca070daf55948e9068045...

@bors
Copy link
Contributor

bors commented Dec 19, 2017

💔 Test failed - status-travis

@kennytm
Copy link
Member

kennytm commented Dec 19, 2017

RLS and rustfmt are still broken.

When a parse error occurs on a block, the parser will recover and create
a block with the statements collected until that point. Now a flag
stating that a recovery has been performed in this block is propagated
so that the type checker knows that the type of the block (which will be
identified as `()`) shouldn't be checked against the expectation to
reduce the amount of irrelevant diagnostic errors shown to the user.
@estebank estebank force-pushed the silence-recovered-blocks branch from 351f06a to d90d5d1 Compare December 21, 2017 23:09
@estebank
Copy link
Contributor Author

@bors try

@bors
Copy link
Contributor

bors commented Dec 21, 2017

⌛ Trying commit d90d5d1 with merge 91fe28d...

bors added a commit that referenced this pull request Dec 21, 2017
Do not emit type errors on recovered blocks

When a parse error occurs on a block, the parser will recover and create
a block with the statements collected until that point. Now a flag
stating that a recovery has been performed in this block is propagated
so that the type checker knows that the type of the block (which will be
identified as `()`) shouldn't be checked against the expectation to
reduce the amount of irrelevant diagnostic errors shown to the user.

Fix #44579.
@bors
Copy link
Contributor

bors commented Dec 22, 2017

☀️ Test successful - status-travis
State: approved= try=True

@estebank
Copy link
Contributor Author

@bors r=petrochenkov

@bors
Copy link
Contributor

bors commented Dec 22, 2017

📌 Commit d90d5d1 has been approved by petrochenkov

bors added a commit that referenced this pull request Dec 22, 2017
Do not emit type errors on recovered blocks

When a parse error occurs on a block, the parser will recover and create
a block with the statements collected until that point. Now a flag
stating that a recovery has been performed in this block is propagated
so that the type checker knows that the type of the block (which will be
identified as `()`) shouldn't be checked against the expectation to
reduce the amount of irrelevant diagnostic errors shown to the user.

Fix #44579.
@bors
Copy link
Contributor

bors commented Dec 22, 2017

⌛ Testing commit d90d5d1 with merge c2ecab1...

@bors
Copy link
Contributor

bors commented Dec 22, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: petrochenkov
Pushing c2ecab1 to master...

@bluss
Copy link
Member

bluss commented Jan 1, 2018

Awesome! Thanks a lot for this

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