diff options
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 53 |
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 |
