From e81a5c65d9b254e625b96dfc756f1695ee1824ed Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 26 Oct 2023 11:35:11 +0000 Subject: [PATCH] Recover ternary expression as error --- .../rustc_parse/src/parser/diagnostics.rs | 20 +++-- tests/ui/parser/ternary_operator.rs | 54 +----------- tests/ui/parser/ternary_operator.stderr | 87 ++----------------- 3 files changed, 22 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 64db7d9809e..7b5bb319ed8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -504,8 +504,10 @@ impl<'a> Parser<'a> { // Special-case "expected `;`" errors if expected.contains(&TokenType::Token(token::Semi)) { - if self.prev_token == token::Question && self.maybe_recover_from_ternary_operator() { - return Ok(true); + // If the user is trying to write a ternary expression, recover it and + // return an Err to prevent a cascade of irrelevant diagnostics + if self.prev_token == token::Question && let Err(e) = self.maybe_recover_from_ternary_operator() { + return Err(e); } if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP { @@ -1428,10 +1430,10 @@ impl<'a> Parser<'a> { /// Rust has no ternary operator (`cond ? then : else`). Parse it and try /// to recover from it if `then` and `else` are valid expressions. Returns - /// whether it was a ternary operator. - pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> bool { + /// an err if this appears to be a ternary expression. + pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> PResult<'a, ()> { if self.prev_token != token::Question { - return false; + return PResult::Ok(()); } let lo = self.prev_token.span.lo(); @@ -1449,8 +1451,9 @@ impl<'a> Parser<'a> { if self.eat_noexpect(&token::Colon) { match self.parse_expr() { Ok(_) => { - self.sess.emit_err(TernaryOperator { span: self.token.span.with_lo(lo) }); - return true; + return Err(self + .sess + .create_err(TernaryOperator { span: self.token.span.with_lo(lo) })); } Err(err) => { err.cancel(); @@ -1459,8 +1462,7 @@ impl<'a> Parser<'a> { } } self.restore_snapshot(snapshot); - - false + Ok(()) } pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> { diff --git a/tests/ui/parser/ternary_operator.rs b/tests/ui/parser/ternary_operator.rs index 03cf86f6da4..c8810781b3d 100644 --- a/tests/ui/parser/ternary_operator.rs +++ b/tests/ui/parser/ternary_operator.rs @@ -1,76 +1,30 @@ -// A good chunk of these errors aren't shown to the user, but are still -// required in the test for it to pass. - -fn a() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn a() { let x = 5 > 2 ? true : false; //~^ ERROR Rust has no ternary operator //~| HELP use an `if-else` expression instead - //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277] - //~| HELP the trait `Try` is not implemented for `{integer}` - //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277] - //~| HELP the trait `FromResidual<_>` is not implemented for `()` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE the `?` operator cannot be applied to type `{integer}` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE cannot use the `?` operator in a function that returns `()` - //~| NOTE in this expansion of desugaring of operator `?` } -fn b() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn b() { let x = 5 > 2 ? { true } : { false }; //~^ ERROR Rust has no ternary operator //~| HELP use an `if-else` expression instead - //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277] - //~| HELP the trait `Try` is not implemented for `{integer}` - //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277] - //~| HELP the trait `FromResidual<_>` is not implemented for `()` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE the `?` operator cannot be applied to type `{integer}` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE cannot use the `?` operator in a function that returns `()` - //~| NOTE in this expansion of desugaring of operator `?` } -fn c() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn c() { let x = 5 > 2 ? f32::MAX : f32::MIN; //~^ ERROR Rust has no ternary operator //~| HELP use an `if-else` expression instead - //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277] - //~| HELP the trait `Try` is not implemented for `{integer}` - //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277] - //~| HELP the trait `FromResidual<_>` is not implemented for `()` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE the `?` operator cannot be applied to type `{integer}` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE cannot use the `?` operator in a function that returns `()` - //~| NOTE in this expansion of desugaring of operator `?` } fn bad() { // regression test for #117208 v ? return; //~^ ERROR expected one of - //~| NOTE expected one of } -fn main() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn main() { let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; //~^ ERROR Rust has no ternary operator //~| HELP use an `if-else` expression instead //~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `:` - //~| NOTE expected one of `.`, `;`, `?`, `else`, or an operator - //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277] - //~| HELP the trait `Try` is not implemented for `{integer}` - //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277] - //~| HELP the trait `FromResidual<_>` is not implemented for `()` - //~| NOTE type ascription syntax has been removed, see issue #101728 - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE the `?` operator cannot be applied to type `{integer}` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE cannot use the `?` operator in a function that returns `()` - //~| NOTE in this expansion of desugaring of operator `?` } diff --git a/tests/ui/parser/ternary_operator.stderr b/tests/ui/parser/ternary_operator.stderr index 61d3c35eb97..6635e1672f7 100644 --- a/tests/ui/parser/ternary_operator.stderr +++ b/tests/ui/parser/ternary_operator.stderr @@ -1,5 +1,5 @@ error: Rust has no ternary operator - --> $DIR/ternary_operator.rs:5:19 + --> $DIR/ternary_operator.rs:2:19 | LL | let x = 5 > 2 ? true : false; | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let x = 5 > 2 ? true : false; = help: use an `if-else` expression instead error: Rust has no ternary operator - --> $DIR/ternary_operator.rs:21:19 + --> $DIR/ternary_operator.rs:8:19 | LL | let x = 5 > 2 ? { true } : { false }; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | let x = 5 > 2 ? { true } : { false }; = help: use an `if-else` expression instead error: Rust has no ternary operator - --> $DIR/ternary_operator.rs:37:19 + --> $DIR/ternary_operator.rs:14:19 | LL | let x = 5 > 2 ? f32::MAX : f32::MIN; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -23,13 +23,13 @@ LL | let x = 5 > 2 ? f32::MAX : f32::MIN; = help: use an `if-else` expression instead error: expected one of `.`, `;`, `?`, `}`, or an operator, found keyword `return` - --> $DIR/ternary_operator.rs:54:9 + --> $DIR/ternary_operator.rs:21:9 | LL | v ? return; | ^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` - --> $DIR/ternary_operator.rs:60:37 + --> $DIR/ternary_operator.rs:26:37 | LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; | ^ expected one of `.`, `;`, `?`, `else`, or an operator @@ -37,85 +37,12 @@ LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; = note: type ascription syntax has been removed, see issue #101728 error: Rust has no ternary operator - --> $DIR/ternary_operator.rs:60:19 + --> $DIR/ternary_operator.rs:26:19 | LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use an `if-else` expression instead -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/ternary_operator.rs:5:17 - | -LL | let x = 5 > 2 ? true : false; - | ^^^ the `?` operator cannot be applied to type `{integer}` - | - = help: the trait `Try` is not implemented for `{integer}` +error: aborting due to 6 previous errors -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/ternary_operator.rs:5:19 - | -LL | fn a() { - | ------ this function should return `Result` or `Option` to accept `?` -LL | let x = 5 > 2 ? true : false; - | ^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `FromResidual<_>` is not implemented for `()` - -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/ternary_operator.rs:21:17 - | -LL | let x = 5 > 2 ? { true } : { false }; - | ^^^ the `?` operator cannot be applied to type `{integer}` - | - = help: the trait `Try` is not implemented for `{integer}` - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/ternary_operator.rs:21:19 - | -LL | fn b() { - | ------ this function should return `Result` or `Option` to accept `?` -LL | let x = 5 > 2 ? { true } : { false }; - | ^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `FromResidual<_>` is not implemented for `()` - -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/ternary_operator.rs:37:17 - | -LL | let x = 5 > 2 ? f32::MAX : f32::MIN; - | ^^^ the `?` operator cannot be applied to type `{integer}` - | - = help: the trait `Try` is not implemented for `{integer}` - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/ternary_operator.rs:37:19 - | -LL | fn c() { - | ------ this function should return `Result` or `Option` to accept `?` -LL | let x = 5 > 2 ? f32::MAX : f32::MIN; - | ^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `FromResidual<_>` is not implemented for `()` - -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/ternary_operator.rs:60:17 - | -LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; - | ^^^ the `?` operator cannot be applied to type `{integer}` - | - = help: the trait `Try` is not implemented for `{integer}` - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/ternary_operator.rs:60:19 - | -LL | fn main() { - | --------- this function should return `Result` or `Option` to accept `?` -LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; - | ^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `FromResidual<_>` is not implemented for `()` - -error: aborting due to 14 previous errors - -For more information about this error, try `rustc --explain E0277`.