Rollup merge of #103405 - chenyukang:yukang/fix-103381-and-if, r=compiler-errors
Detect incorrect chaining of if and if let conditions and recover Fixes #103381
This commit is contained in:
commit
3efbf30220
@ -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
|
||||
|
@ -1219,3 +1219,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,
|
||||
);
|
||||
|
@ -21,8 +21,8 @@
|
||||
NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
|
||||
OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
|
||||
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
|
||||
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
|
||||
UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
|
||||
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
|
||||
UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
|
||||
};
|
||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||
use core::mem;
|
||||
@ -2231,6 +2231,7 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
|
||||
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(
|
||||
@ -2367,6 +2368,16 @@ fn error_on_if_block_attrs(
|
||||
});
|
||||
}
|
||||
|
||||
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 (`.
|
||||
|
59
src/test/ui/parser/issue-103381.fixed
Normal file
59
src/test/ui/parser/issue-103381.fixed
Normal file
@ -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
src/test/ui/parser/issue-103381.rs
Normal file
59
src/test/ui/parser/issue-103381.rs
Normal file
@ -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
src/test/ui/parser/issue-103381.stderr
Normal file
50
src/test/ui/parser/issue-103381.stderr
Normal file
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user