-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Detect incorrect chaining of if and if let conditions and recover #103405
Conversation
(rust-highfive has picked a reviewer for you, use r? to override) |
cc @davidtwco, @compiler-errors, @JohnTitor, @estebank, @TaKO8Ki |
r? @estebank |
This comment has been minimized.
This comment has been minimized.
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.
This breaks existing code -- if
expressions are allowed to be their own conditions within other if
statements.
fn main() {
if true && if let 1 = 1 { true } else { true } {}
}
Before this PR: compiles
After this PR:
error: unexpected `if` in the condition expression
--> /home/gh-compiler-errors/test.rs:2:16
|
2 | if true && if let 1 = 1 { true } else { true } {}
| ^^^
|
help: remove the `if`
|
2 - if true && if let 1 = 1 { true } else { true } {}
2 + if true && let 1 = 1 { true } else { true } {}
|
error[E0658]: `let` expressions in this position are unstable
--> /home/gh-compiler-errors/test.rs:2:19
|
2 | if true && if let 1 = 1 { true } else { true } {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0308]: mismatched types
--> /home/gh-compiler-errors/test.rs:2:31
|
2 | if true && if let 1 = 1 { true } else { true } {}
| --------------------------^^^^----------------
| | |
| | expected `()`, found `bool`
| expected this to be `()`
error[E0308]: mismatched types
--> /home/gh-compiler-errors/test.rs:2:45
|
2 | if true && if let 1 = 1 { true } else { true } {}
| ----------------------------------------^^^^--
| | |
| | expected `()`, found `bool`
| expected this to be `()`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.
This code will also compile in current compiler: fn should_ok() {
if true && if let x = 1 { true } else { true } {}
} With this warning: warning: irrefutable `if let` pattern
--> /home/cat/code/rust/src/test/ui/parser/issue-103381.rs:13:19
|
13 | if true && if let x = 1 { true } else { true } {}
| ^^^^^^^^^
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
= note: this pattern will always match, so the `if let` is useless
= help: consider replacing the `if let` with a `let`
warning: 1 warning emitted |
Just noting that "irrefutable |
From the UI testing result, we have this syntax: fn shoule_match_ok() {
#[cfg(feature = "full")]
{
let a = 1;
let b = 2;
if match a {
1 if b == 1 => true,
_ => false,
} && if a > 1 { true } else { false }
{
true
}
}
} I think it's not a readable code, but it compiled and runnable 😂 // recovery from `if b && if let Some(x)`
if op == AssocOp::LAnd
&& self.token.is_keyword(kw::If)
&& self.look_ahead(1, |t| t.is_bool_lit())
|| (self.look_ahead(1, |t| t.is_keyword(kw::Let))
&& self.look_ahead(2, |t| {
t.is_ident_named(sym::Some) || t.is_ident_named(sym::None)
}))
{
// eat the `if`
self.bump();
self.sess.emit_err(UnexpectedIfWithIf(
self.prev_token.span.to(self.token.span.shrink_to_lo()),
));
} Not sure whether there is a better way. |
@chenyukang, this approach still has issues: fn main() {
if true && if true { true } else { false } {}
} This fails to compile with your new changes:
I'm pretty sure it's impossible to detect #103381 inside of This may be hard to do, or not worth the changes to the parser to allow this state to be tracked. |
Ok, I will have look later
Michael Goulet ***@***.***> 于 2022年10月23日周日 14:06写道:
… @chenyukang <https://github.com/chenyukang>, this approach still has
issues:
fn main() {
if true && if true { true } else { false } {}}
This fails to compile with your new changes:
error: unexpected `if` in the condition expression
--> /home/gh-compiler-errors/test.rs:2:16
|
2 | if true && if true { true } else { false } {}
| ^^^
|
help: remove the `if`
|
2 - if true && if true { true } else { false } {}
2 + if true && true { true } else { false } {}
|
error[E0308]: mismatched types
--> /home/gh-compiler-errors/test.rs:2:26
|
2 | if true && if true { true } else { false } {}
| ---------------------^^^^-----------------
| | |
| | expected `()`, found `bool`
| expected this to be `()`
error[E0308]: mismatched types
--> /home/gh-compiler-errors/test.rs:2:40
|
2 | if true && if true { true } else { false } {}
| -----------------------------------^^^^^--
| | |
| | expected `()`, found `bool`
| expected this to be `()`
error: aborting due to 3 previous errors
------------------------------
I'm pretty sure it's impossible to detect #103381
<#103381> inside of
parse_assoc_expr_with -- you need to add a suggestion to remove if only
*after* the parser has already detected an error, probably by passing the
correct state down to parse_if_after_cond or some similar function that
is involved in parsing if statements.
—
Reply to this email directly, view it on GitHub
<#103405 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABYJ5VZ7VWUZIXRMEQRUX3WETIUXANCNFSM6AAAAAARL5BSCU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
This comment has been minimized.
This comment has been minimized.
Hi, I've seen you changed some diagnostic structs in your PR. After #103345, the way we refer to fluent messages changed. They are now in a flat namespace with the same identifier as in the fluent file. For example, |
31bad2e
to
3fea71e
Compare
Take some time to investigate it. let _ = if true && if true { true } else { false };
let _ = if true && if false { true } else { false }; Only add check for |
3fea71e
to
43269b6
Compare
@rustbot ready |
&& self.token.is_keyword(kw::If) | ||
&& self.look_ahead(1, |t| t.is_keyword(kw::Let)) | ||
&& self | ||
.look_ahead(2, |t| t.is_ident_named(sym::Some) || t.is_ident_named(sym::None)) |
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.
The following code is perfectly valid:
if true
&& if let Some(1) = Some(1) { true } else { true }
{
todo!()
}
In general, it is always possible to write valid code containing if <some condition> && if let <some pattern>
.
I don't think it's possible to detect the scenario you're looking for until after you parse the inner if let ..
expression.
@chenyukang, camsteffen is correct, and as I noted in my previous comment, I'm pretty sure it's impossible to detect #103381 inside of This check needs to live in another function using a different strategy, after parsing has detected a failure. Be very careful about adding parser recoveries before we've detected an error, since it's very1 easy2 to accidentally introduce changes in parser behavior while improving error messages during parsing... |
Got it, thanks! |
43269b6
to
e7998ec
Compare
I think we'd better don't recover from these scenarios, but give proper diagnostics 😁 |
a6ea4bc
to
6cd4a2a
Compare
r? @compiler-errors as you're already familiar with the changes :) |
error: unexpected `if` in the condition expression | ||
--> $DIR/issue-103381.rs:19:15 | ||
| | ||
LL | if true && if true { true } else { false }; | ||
| ^^^^ | ||
| | ||
help: remove the `if` | ||
| | ||
LL - if true && if true { true } else { false }; | ||
LL + if true && true { true } else { false }; |
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.
What happens for if true && if true { true } else { false } { true } else { false };
?
Given where you call the recovery it should succeed, right? In that case I believe the code changes look fine because the error is only ever precluding another, so there are no changes of regressions.
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.
Given where you call the recovery it should succeed, right?
yeah, this is my thinking. I'll give this a better review later, but I much prefer this approach since it's already deep in the "bad path".
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.
Yes, this code will compile successfully, I have added it as a UI.
@rustbot ready I will get around to reviewing this soon. |
☔ The latest upstream changes (presumably #104418) made this pull request unmergeable. Please resolve the merge conflicts. |
dafa06f
to
cd2bde1
Compare
@rustbot ready conflict resolved. |
@bors r+ |
🌲 The tree is currently closed for pull requests below priority 1. This pull request will be tested once the tree is reopened. |
…iaskrgr Rollup of 8 pull requests Successful merges: - rust-lang#101162 (Migrate rustc_resolve to use SessionDiagnostic, part # 1) - rust-lang#103386 (Don't allow `CoerceUnsized` into `dyn*` (except for trait upcasting)) - rust-lang#103405 (Detect incorrect chaining of if and if let conditions and recover) - rust-lang#103594 (Fix non-associativity of `Instant` math on `aarch64-apple-darwin` targets) - rust-lang#104006 (Add variant_name function to `LangItem`) - rust-lang#104494 (Migrate GUI test to use functions) - rust-lang#104516 (rustdoc: clean up sidebar width CSS) - rust-lang#104550 (fix a typo) Failed merges: - rust-lang#104554 (Use `ErrorGuaranteed::unchecked_claim_error_was_emitted` less) r? `@ghost` `@rustbot` modify labels: rollup
…iaskrgr Rollup of 8 pull requests Successful merges: - rust-lang#101162 (Migrate rustc_resolve to use SessionDiagnostic, part # 1) - rust-lang#103386 (Don't allow `CoerceUnsized` into `dyn*` (except for trait upcasting)) - rust-lang#103405 (Detect incorrect chaining of if and if let conditions and recover) - rust-lang#103594 (Fix non-associativity of `Instant` math on `aarch64-apple-darwin` targets) - rust-lang#104006 (Add variant_name function to `LangItem`) - rust-lang#104494 (Migrate GUI test to use functions) - rust-lang#104516 (rustdoc: clean up sidebar width CSS) - rust-lang#104550 (fix a typo) Failed merges: - rust-lang#104554 (Use `ErrorGuaranteed::unchecked_claim_error_was_emitted` less) r? `@ghost` `@rustbot` modify labels: rollup
Fixes #103381