about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser
diff options
context:
space:
mode:
authorCatherine Flores <catherine.3.flores@gmail.com>2023-07-25 18:27:24 +0000
committerCatherine Flores <catherine.3.flores@gmail.com>2023-07-25 18:27:24 +0000
commit16481807f5b106a6dcc627075fbdcd14add9495d (patch)
treec4abe79f49189d9dcd5f29d8e3d92f0553ac603b /compiler/rustc_parse/src/parser
parentcb6ab9516bbbd3859b56dd23e32fe41600e0ae02 (diff)
downloadrust-16481807f5b106a6dcc627075fbdcd14add9495d.tar.gz
rust-16481807f5b106a6dcc627075fbdcd14add9495d.zip
Gracefully handle missing ternary operator
Diffstat (limited to 'compiler/rustc_parse/src/parser')
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs46
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs9
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs4
3 files changed, 55 insertions, 4 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index c3cf6437afa..8f422d90175 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,13 @@ impl<'a> Parser<'a> {
 
         // Special-case "expected `;`" errors
         if expected.contains(&TokenType::Token(token::Semi)) {
+            if self.prev_token.kind == token::Question {
+                self.maybe_ternary_lo = Some(self.prev_token.span.lo());
+                let result = self.maybe_recover_from_ternary_operator().map(|_| true);
+                self.maybe_ternary_lo = None;
+                return result;
+            }
+
             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 +1337,41 @@ 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.
+    pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> PResult<'a, ()> {
+        let snapshot = self.create_snapshot_for_diagnostic();
+        let lo = self.prev_token.span.lo();
+
+        if self.prev_token == token::Question
+            && 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) });
+                    }
+                    Err(err) => {
+                        err.cancel();
+                        self.restore_snapshot(snapshot);
+                    }
+                };
+            }
+        } else {
+            self.restore_snapshot(snapshot);
+        };
+
+        Ok(())
+    }
+
     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 +2153,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);
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 2e1a61e634e..20515b36fa1 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -37,6 +37,7 @@ use rustc_errors::{
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{Span, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::BytePos;
 use std::ops::Range;
 use std::{cmp, mem, slice};
 use thin_vec::ThinVec;
@@ -157,12 +158,17 @@ pub struct Parser<'a> {
     /// Whether the parser is allowed to do recovery.
     /// This is disabled when parsing macro arguments, see #103534
     pub recovery: Recovery,
+    /// The low part of a ternary operator (`cond ? then : else`).
+    /// FIXME(Centri3): This is currently only used so that type ascription is
+    /// not mentioned in the error. Once the error in `stmt.rs` is removed, this
+    /// can be removed.
+    maybe_ternary_lo: Option<BytePos>,
 }
 
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 272);
+rustc_data_structures::static_assert_size!(Parser<'_>, 280);
 
 /// Stores span information about a closure.
 #[derive(Clone)]
@@ -475,6 +481,7 @@ impl<'a> Parser<'a> {
             },
             current_closure: None,
             recovery: Recovery::Allowed,
+            maybe_ternary_lo: None,
         };
 
         // Make parser point to the first token.
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 9fcf51a04ec..5a7f3aa53dc 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -576,7 +576,9 @@ impl<'a> Parser<'a> {
                                 Applicability::MaybeIncorrect,
                             );
                         }
-                        if self.sess.unstable_features.is_nightly_build() {
+                        if self.sess.unstable_features.is_nightly_build()
+                            && self.maybe_ternary_lo.is_none()
+                        {
                             // FIXME(Nilstrieb): Remove this again after a few months.
                             err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>");
                         }