@@ -44,7 +44,7 @@ use ast::{RangeEnd, RangeSyntax};
4444use { ast, attr} ;
4545use codemap:: { self , CodeMap , Spanned , respan} ;
4646use syntax_pos:: { self , Span , MultiSpan , BytePos , FileName , edition:: Edition } ;
47- use errors:: { self , Applicability , DiagnosticBuilder } ;
47+ use errors:: { self , Applicability , DiagnosticBuilder , DiagnosticId } ;
4848use parse:: { self , SeqSep , classify, token} ;
4949use parse:: lexer:: TokenAndSpan ;
5050use parse:: lexer:: comments:: { doc_comment_style, strip_doc_comment_decoration} ;
@@ -1371,7 +1371,7 @@ impl<'a> Parser<'a> {
13711371 let ident = self . parse_ident ( ) ?;
13721372 let mut generics = self . parse_generics ( ) ?;
13731373
1374- let d = self . parse_fn_decl_with_self ( |p : & mut Parser < ' a > |{
1374+ let d = self . parse_fn_decl_with_self ( |p : & mut Parser < ' a > | {
13751375 // This is somewhat dubious; We don't want to allow
13761376 // argument names to be left off if there is a
13771377 // definition...
@@ -1753,21 +1753,59 @@ impl<'a> Parser<'a> {
17531753 ( pat, self . parse_ty ( ) ?)
17541754 } else {
17551755 debug ! ( "parse_arg_general ident_to_pat" ) ;
1756- let ident = Ident :: new ( keywords:: Invalid . name ( ) , self . prev_span ) ;
1757- let ty = self . parse_ty ( ) ?;
1758- let pat = P ( Pat {
1759- id : ast:: DUMMY_NODE_ID ,
1760- node : PatKind :: Ident ( BindingMode :: ByValue ( Mutability :: Immutable ) , ident, None ) ,
1761- span : ty. span ,
1762- } ) ;
1763- ( pat, ty)
1756+
1757+ let parser_snapshot_before_pat = self . clone ( ) ;
1758+
1759+ // We're going to try parsing the argument as a pattern (even though it's not
1760+ // allowed). This way we can provide better errors to the user.
1761+ let pat_arg: PResult < ' a , _ > = do catch {
1762+ let pat = self . parse_pat ( ) ?;
1763+ self . expect ( & token:: Colon ) ?;
1764+ ( pat, self . parse_ty ( ) ?)
1765+ } ;
1766+
1767+ match pat_arg {
1768+ Ok ( ( pat, ty) ) => {
1769+ let mut err = self . diagnostic ( ) . struct_span_err_with_code (
1770+ pat. span ,
1771+ "patterns aren't allowed in methods without bodies" ,
1772+ DiagnosticId :: Error ( "E0642" . into ( ) ) ,
1773+ ) ;
1774+ err. span_suggestion_short_with_applicability (
1775+ pat. span ,
1776+ "give this argument a name or use an underscore to ignore it" ,
1777+ "_" . to_owned ( ) ,
1778+ Applicability :: MachineApplicable ,
1779+ ) ;
1780+ err. emit ( ) ;
1781+ // Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
1782+ let pat = P ( Pat {
1783+ node : PatKind :: Wild ,
1784+ span : pat. span ,
1785+ id : ast:: DUMMY_NODE_ID
1786+ } ) ;
1787+ ( pat, ty)
1788+ }
1789+ Err ( mut err) => {
1790+ err. cancel ( ) ;
1791+ // Recover from attempting to parse the argument as a pattern. This means
1792+ // the type is alone, with no name, e.g. `fn foo(u32)`.
1793+ mem:: replace ( self , parser_snapshot_before_pat) ;
1794+ debug ! ( "parse_arg_general ident_to_pat" ) ;
1795+ let ident = Ident :: new ( keywords:: Invalid . name ( ) , self . prev_span ) ;
1796+ let ty = self . parse_ty ( ) ?;
1797+ let pat = P ( Pat {
1798+ id : ast:: DUMMY_NODE_ID ,
1799+ node : PatKind :: Ident (
1800+ BindingMode :: ByValue ( Mutability :: Immutable ) , ident, None ) ,
1801+ span : ty. span ,
1802+ } ) ;
1803+ ( pat, ty)
1804+ }
1805+ }
17641806 } ;
17651807
1766- Ok ( Arg {
1767- ty,
1768- pat,
1769- id : ast:: DUMMY_NODE_ID ,
1770- } )
1808+ Ok ( Arg { ty, pat, id: ast:: DUMMY_NODE_ID } )
17711809 }
17721810
17731811 /// Parse a single function argument
0 commit comments