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
6 changed files with 192 additions and 2 deletions
|
@ -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
|
parser_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
|
||||||
.suggestion = use `!` to perform bitwise not
|
.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 = unexpected {$negated_desc} after identifier
|
||||||
parser_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
|
parser_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
|
||||||
parser_unexpected_token_after_not_logical = use `!` to perform logical negation
|
parser_unexpected_token_after_not_logical = use `!` to perform logical negation
|
||||||
|
|
|
@ -1219,3 +1219,11 @@ pub(crate) struct FnPtrWithGenericsSugg {
|
||||||
pub arity: usize,
|
pub arity: usize,
|
||||||
pub for_param_list_exists: bool,
|
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 @@ use crate::errors::{
|
||||||
NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
|
NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
|
||||||
OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
|
OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
|
||||||
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
|
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
|
||||||
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
|
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
|
||||||
UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
|
UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
|
||||||
};
|
};
|
||||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
@ -2231,6 +2231,7 @@ impl<'a> Parser<'a> {
|
||||||
if let Some(block) = recover_block_from_condition(self) {
|
if let Some(block) = recover_block_from_condition(self) {
|
||||||
block
|
block
|
||||||
} else {
|
} else {
|
||||||
|
self.error_on_extra_if(&cond)?;
|
||||||
// Parse block, which will always fail, but we can add a nice note to the error
|
// Parse block, which will always fail, but we can add a nice note to the error
|
||||||
self.parse_block().map_err(|mut err| {
|
self.parse_block().map_err(|mut err| {
|
||||||
err.span_note(
|
err.span_note(
|
||||||
|
@ -2367,6 +2368,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).
|
/// 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>> {
|
fn parse_for_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
|
||||||
// Record whether we are about to parse `for (`.
|
// 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…
Add table
Add a link
Reference in a new issue