From 041f0313cf39f1be4fbceebf3186fe5254e7be78 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 26 Oct 2023 11:11:36 +0000 Subject: [PATCH 1/2] Properly restore snapshot when failing to recover parsing ternary --- compiler/rustc_parse/src/parser/diagnostics.rs | 6 ++---- tests/ui/parser/ternary_operator.rs | 7 +++++++ tests/ui/parser/ternary_operator.stderr | 16 +++++++++++----- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9f8361a4b1ee2..64db7d9809eff 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1454,13 +1454,11 @@ impl<'a> Parser<'a> { } Err(err) => { err.cancel(); - self.restore_snapshot(snapshot); } }; } - } else { - self.restore_snapshot(snapshot); - }; + } + self.restore_snapshot(snapshot); false } diff --git a/tests/ui/parser/ternary_operator.rs b/tests/ui/parser/ternary_operator.rs index 23d537e77f79e..03cf86f6da42b 100644 --- a/tests/ui/parser/ternary_operator.rs +++ b/tests/ui/parser/ternary_operator.rs @@ -49,6 +49,13 @@ fn c() { //~ NOTE this function should return `Result` or `Option` to accept `?` //~| 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 `?` let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; //~^ ERROR Rust has no ternary operator diff --git a/tests/ui/parser/ternary_operator.stderr b/tests/ui/parser/ternary_operator.stderr index af9565bbead1b..61d3c35eb9769 100644 --- a/tests/ui/parser/ternary_operator.stderr +++ b/tests/ui/parser/ternary_operator.stderr @@ -22,8 +22,14 @@ 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 + | +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:60:37 | LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; | ^ expected one of `.`, `;`, `?`, `else`, or an operator @@ -31,7 +37,7 @@ 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:60:19 | LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +99,7 @@ LL | let x = 5 > 2 ? f32::MAX : f32::MIN; = 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 + --> $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}` @@ -101,7 +107,7 @@ LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; = 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 + --> $DIR/ternary_operator.rs:60:19 | LL | fn main() { | --------- this function should return `Result` or `Option` to accept `?` @@ -110,6 +116,6 @@ LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; | = help: the trait `FromResidual<_>` is not implemented for `()` -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0277`. From e81a5c65d9b254e625b96dfc756f1695ee1824ed Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 26 Oct 2023 11:35:11 +0000 Subject: [PATCH 2/2] 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 64db7d9809eff..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,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 03cf86f6da42b..c8810781b3d84 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 61d3c35eb9769..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,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[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 +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0277`.