about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-08-04 02:23:21 +0100
committervarkor <github@varkor.com>2018-08-11 21:08:24 +0100
commit90a6954327bb4f018eab155f43299d4bf67abe41 (patch)
treefcea45cfe932db552ea2f5db5c553d15eabd0b5f /src/libsyntax/parse/parser.rs
parenta77dfcc79fe3e7e1a10ae4dccfd4b2e5e0e49195 (diff)
downloadrust-90a6954327bb4f018eab155f43299d4bf67abe41.tar.gz
rust-90a6954327bb4f018eab155f43299d4bf67abe41.zip
Emit error for pattern arguments in trait methods
The error and check for this already existed, but the parser didn't try to parse trait method arguments as patterns, so the error was never emitted. This surfaces the error, so we get better errors than simple parse errors.
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs53
1 files changed, 33 insertions, 20 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 9011b6e48b9..5a2fd5f0145 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1371,7 +1371,7 @@ impl<'a> Parser<'a> {
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
 
-            let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
+            let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
                 // This is somewhat dubious; We don't want to allow
                 // argument names to be left off if there is a
                 // definition...
@@ -1744,30 +1744,43 @@ impl<'a> Parser<'a> {
     fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
         maybe_whole!(self, NtArg, |x| x);
 
-        let (pat, ty) = if require_name || self.is_named_argument() {
-            debug!("parse_arg_general parse_pat (require_name:{})",
-                   require_name);
-            let pat = self.parse_pat()?;
+        let parser_snapshot_before_pat = self.clone();
 
+        // We're going to try parsing the argument as a pattern (even if it's not
+        // allowed, such as for trait methods without bodies). This way we can provide
+        // better errors to the user.
+        let pat_arg: PResult<'a, (P<Pat>, P<Ty>)> = do catch {
+            let pat = self.parse_pat()?;
             self.expect(&token::Colon)?;
             (pat, self.parse_ty()?)
-        } else {
-            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)
         };
 
-        Ok(Arg {
-            ty,
-            pat,
-            id: ast::DUMMY_NODE_ID,
-        })
+        let is_named_argument = self.is_named_argument();
+        match pat_arg {
+            Ok((pat, ty)) => {
+                Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
+            }
+            Err(mut err) => {
+                if require_name || is_named_argument {
+                    Err(err)
+                } else {
+                    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,
+                    });
+                    Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
+                }
+            }
+        }
     }
 
     /// Parse a single function argument