Skip to content

Commit

Permalink
fix #103381, Detect incorrect chaining of if and if let conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Nov 15, 2022
1 parent 101e182 commit 74c9a6c
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 2 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/parser.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ parser_invalid_logical_operator = `{$incorrect}` is not a logical operator
parser_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
.suggestion = use `!` to perform bitwise not
parser_unexpected_if_with_if = unexpected `if` in the condition expression
.suggestion = remove the `if`
parser_unexpected_token_after_not = unexpected {$negated_desc} after identifier
parser_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
parser_unexpected_token_after_not_logical = use `!` to perform logical negation
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1301,3 +1301,11 @@ pub(crate) struct FnPtrWithGenericsSugg {
pub arity: usize,
pub for_param_list_exists: bool,
}

#[derive(Diagnostic)]
#[diag(parser_unexpected_if_with_if)]
pub(crate) struct UnexpectedIfWithIf(
#[primary_span]
#[suggestion(applicability = "machine-applicable", code = " ", style = "verbose")]
pub Span,
);
15 changes: 13 additions & 2 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use crate::errors::{
NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
OctalFloatLiteralNotSupported, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
};
use crate::maybe_recover_from_interpolated_ty_qpath;

Expand Down Expand Up @@ -2279,6 +2279,7 @@ impl<'a> Parser<'a> {
if let Some(block) = recover_block_from_condition(self) {
block
} else {
self.error_on_extra_if(&cond)?;
// Parse block, which will always fail, but we can add a nice note to the error
self.parse_block().map_err(|mut err| {
err.span_note(
Expand Down Expand Up @@ -2415,6 +2416,16 @@ impl<'a> Parser<'a> {
});
}

fn error_on_extra_if(&mut self, cond: &P<Expr>) -> PResult<'a, ()> {
if let ExprKind::Binary(Spanned { span: binop_span, node: binop}, _, right) = &cond.kind &&
let BinOpKind::And = binop &&
let ExprKind::If(cond, ..) = &right.kind {
Err(self.sess.create_err(UnexpectedIfWithIf(binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()))))
} else {
Ok(())
}
}

/// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
fn parse_for_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
// Record whether we are about to parse `for (`.
Expand Down
59 changes: 59 additions & 0 deletions src/test/ui/parser/issue-103381.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// run-rustfix

#![feature(let_chains)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(irrefutable_let_patterns)]

fn err_some(b: bool, x: Option<u32>) {
if b && let Some(x) = x {}
//~^ ERROR unexpected `if` in the condition expression
}

fn err_none(b: bool, x: Option<u32>) {
if b && let None = x {}
//~^ ERROR unexpected `if` in the condition expression
}

fn err_bool_1() {
if true && true { true } else { false };
//~^ ERROR unexpected `if` in the condition expression
}

fn err_bool_2() {
if true && false { true } else { false };
//~^ ERROR unexpected `if` in the condition expression
}

fn should_ok_1() {
if true && if let x = 1 { true } else { true } {}
}

fn should_ok_2() {
if true && if let 1 = 1 { true } else { true } {}
}

fn should_ok_3() {
if true && if true { true } else { false } {}
}

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
}
}
}

fn should_ok_in_nested() {
if true && if true { true } else { false } { true } else { false };
}

fn main() {}
59 changes: 59 additions & 0 deletions src/test/ui/parser/issue-103381.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// run-rustfix

#![feature(let_chains)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(irrefutable_let_patterns)]

fn err_some(b: bool, x: Option<u32>) {
if b && if let Some(x) = x {}
//~^ ERROR unexpected `if` in the condition expression
}

fn err_none(b: bool, x: Option<u32>) {
if b && if let None = x {}
//~^ ERROR unexpected `if` in the condition expression
}

fn err_bool_1() {
if true && if true { true } else { false };
//~^ ERROR unexpected `if` in the condition expression
}

fn err_bool_2() {
if true && if false { true } else { false };
//~^ ERROR unexpected `if` in the condition expression
}

fn should_ok_1() {
if true && if let x = 1 { true } else { true } {}
}

fn should_ok_2() {
if true && if let 1 = 1 { true } else { true } {}
}

fn should_ok_3() {
if true && if true { true } else { false } {}
}

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
}
}
}

fn should_ok_in_nested() {
if true && if true { true } else { false } { true } else { false };
}

fn main() {}
50 changes: 50 additions & 0 deletions src/test/ui/parser/issue-103381.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
error: unexpected `if` in the condition expression
--> $DIR/issue-103381.rs:9:12
|
LL | if b && if let Some(x) = x {}
| ^^^^
|
help: remove the `if`
|
LL - if b && if let Some(x) = x {}
LL + if b && let Some(x) = x {}
|

error: unexpected `if` in the condition expression
--> $DIR/issue-103381.rs:14:12
|
LL | if b && if let None = x {}
| ^^^^
|
help: remove the `if`
|
LL - if b && if let None = x {}
LL + if b && let None = x {}
|

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 };
|

error: unexpected `if` in the condition expression
--> $DIR/issue-103381.rs:24:15
|
LL | if true && if false { true } else { false };
| ^^^^
|
help: remove the `if`
|
LL - if true && if false { true } else { false };
LL + if true && false { true } else { false };
|

error: aborting due to 4 previous errors

0 comments on commit 74c9a6c

Please sign in to comment.