about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2018-09-22 09:56:40 +0200
committerGitHub <noreply@github.com>2018-09-22 09:56:40 +0200
commit7c34cf7ee3e70bbd6b1f0d8d2bd6931d75989aed (patch)
tree64a9f99b64bee235afd611aba8a512740ce25269 /src/libsyntax/parse
parent0bf52b3a5be7f0b6aa38779b0d78d5469b93494f (diff)
parent9784d3543f524f142aae52da9d2a6ce1eb9d702a (diff)
downloadrust-7c34cf7ee3e70bbd6b1f0d8d2bd6931d75989aed.tar.gz
rust-7c34cf7ee3e70bbd6b1f0d8d2bd6931d75989aed.zip
Rollup merge of #54415 - petrochenkov:norollback, r=estebank
parser: Tweak function parameter parsing to avoid rollback on succesfull path

Since rollback is not perfect and may e.g. leave non-fatal errors after it, we need to make sure compilation fails if it happens.
So in particular case of `fn parse_arg_general` we need to parse the "good" `TYPE` first and only then rollback and recover erroneous `PAT: TYPE` if necessary.
Found when working on https://github.com/rust-lang/rfcs/pull/2544#issuecomment-423293222.

r? @ghost
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs62
1 files changed, 26 insertions, 36 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 4411e008a4d..7a13beb7852 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1781,27 +1781,32 @@ impl<'a> Parser<'a> {
             (pat, self.parse_ty()?)
         } else {
             debug!("parse_arg_general ident_to_pat");
+            let parser_snapshot_before_ty = self.clone();
+            let mut ty = self.parse_ty();
+            if ty.is_ok() && self.token == token::Colon {
+                // This wasn't actually a type, but a pattern looking like a type,
+                // so we are going to rollback and re-parse for recovery.
+                ty = self.unexpected();
+            }
+            match ty {
+                Ok(ty) => {
+                    let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
+                    let pat = P(Pat {
+                        id: ast::DUMMY_NODE_ID,
+                        node: PatKind::Ident(
+                            BindingMode::ByValue(Mutability::Immutable), ident, None),
+                        span: ty.span,
+                    });
+                    (pat, ty)
+                }
+                Err(mut err) => {
+                    // Recover from attempting to parse the argument as a type without pattern.
+                    err.cancel();
+                    mem::replace(self, parser_snapshot_before_ty);
+                    let pat = self.parse_pat()?;
+                    self.expect(&token::Colon)?;
+                    let ty = self.parse_ty()?;
 
-            let parser_snapshot_before_pat = self.clone();
-
-            // Once we can use edition 2018 in the compiler,
-            // replace this with real try blocks.
-            macro_rules! try_block {
-                ($($inside:tt)*) => (
-                    (||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
-                )
-            }
-
-            // We're going to try parsing the argument as a pattern (even though it's not
-            // allowed). This way we can provide better errors to the user.
-            let pat_arg: PResult<'a, _> = try_block! {
-                let pat = self.parse_pat()?;
-                self.expect(&token::Colon)?;
-                (pat, self.parse_ty()?)
-            };
-
-            match pat_arg {
-                Ok((pat, ty)) => {
                     let mut err = self.diagnostic().struct_span_err_with_code(
                         pat.span,
                         "patterns aren't allowed in methods without bodies",
@@ -1814,6 +1819,7 @@ impl<'a> Parser<'a> {
                         Applicability::MachineApplicable,
                     );
                     err.emit();
+
                     // Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
                     let pat = P(Pat {
                         node: PatKind::Wild,
@@ -1822,22 +1828,6 @@ impl<'a> Parser<'a> {
                     });
                     (pat, ty)
                 }
-                Err(mut err) => {
-                    err.cancel();
-                    // Recover from attempting to parse the argument as a pattern. This means
-                    // the type is alone, with no name, e.g. `fn foo(u32)`.
-                    mem::replace(self, parser_snapshot_before_pat);
-                    debug!("parse_arg_general ident_to_pat");
-                    let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
-                    let ty = self.parse_ty()?;
-                    let pat = P(Pat {
-                        id: ast::DUMMY_NODE_ID,
-                        node: PatKind::Ident(
-                            BindingMode::ByValue(Mutability::Immutable), ident, None),
-                        span: ty.span,
-                    });
-                    (pat, ty)
-                }
             }
         };