diff options
| author | bors <bors@rust-lang.org> | 2023-07-29 16:45:29 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-07-29 16:45:29 +0000 |
| commit | a04e649c09183b35ac0309266468c037396b6b88 (patch) | |
| tree | b657bcdd9145e18c94d3bb34476557202292bdfc /compiler/rustc_parse/src | |
| parent | 4c968227965f101e41bda8a38ff02fd1baee28c4 (diff) | |
| parent | 79b6ed0e0860dc4a75af50a975d47efabdd95cbc (diff) | |
| download | rust-a04e649c09183b35ac0309266468c037396b6b88.tar.gz rust-a04e649c09183b35ac0309266468c037396b6b88.zip | |
Auto merge of #114028 - Centri3:ternary-operator, r=compiler-errors
Gracefully handle ternary operator Fixes #112578 ~~May not be the best way to do this as it doesn't check for a single `:`, so it could perhaps appear even when the actual issue is just a missing semicolon. May not be the biggest deal, though?~~ Nevermind, got it working properly now ^^
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 47 |
2 files changed, 53 insertions, 2 deletions
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 5456a708898..06c09960727 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -365,6 +365,14 @@ pub(crate) enum IfExpressionMissingThenBlockSub { AddThenBlock(#[primary_span] Span), } +#[derive(Diagnostic)] +#[diag(parse_ternary_operator)] +#[help] +pub struct TernaryOperator { + #[primary_span] + pub span: Span, +} + #[derive(Subdiagnostic)] #[suggestion(parse_extra_if_in_let_else, applicability = "maybe-incorrect", code = "")] pub(crate) struct IfExpressionLetSomeSub { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c3cf6437afa..7d04a335c9e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -14,7 +14,7 @@ use crate::errors::{ PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, - UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; @@ -500,6 +500,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 self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP { // Likely inside a macro, can't provide meaningful suggestions. } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) { @@ -1330,6 +1334,45 @@ 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 { + if self.prev_token != token::Question { + return false; + } + + let lo = self.prev_token.span.lo(); + let snapshot = self.create_snapshot_for_diagnostic(); + + if match self.parse_expr() { + Ok(_) => true, + Err(err) => { + err.cancel(); + // The colon can sometimes be mistaken for type + // ascription. Catch when this happens and continue. + self.token == token::Colon + } + } { + 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; + } + Err(err) => { + err.cancel(); + self.restore_snapshot(snapshot); + } + }; + } + } else { + self.restore_snapshot(snapshot); + }; + + false + } + pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> { // Do not add `+` to expected tokens. if !self.token.is_like_plus() { @@ -2111,7 +2154,7 @@ impl<'a> Parser<'a> { } _ => ( self.token.span, - format!("expected expression, found {}", super::token_descr(&self.token),), + format!("expected expression, found {}", super::token_descr(&self.token)), ), }; let mut err = self.struct_span_err(span, msg); |
