diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9f8361a4b1ee2..7b5bb319ed8d1 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,20 +1451,18 @@ 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(); - self.restore_snapshot(snapshot); } }; } - } else { - self.restore_snapshot(snapshot); - }; - - false + } + self.restore_snapshot(snapshot); + 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 23d537e77f79e..c8810781b3d84 100644 --- a/tests/ui/parser/ternary_operator.rs +++ b/tests/ui/parser/ternary_operator.rs @@ -1,69 +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 main() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn bad() { + // regression test for #117208 + v ? return; + //~^ ERROR expected one of +} + +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 af9565bbead1b..6635e1672f781 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,15 +15,21 @@ 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; | ^^^^^^^^^^^^^^^^^^^^^^ | = help: use an `if-else` expression instead +error: expected one of `.`, `;`, `?`, `}`, or an operator, found keyword `return` + --> $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:53: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 @@ -31,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:53: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[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:53: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:53: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 13 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0277`.