about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-09-29 09:26:02 +0200
committerMazdak Farrokhzad <twingoow@gmail.com>2019-09-29 12:55:45 +0200
commit8fd03b1e47147794ff955a13a474cd52a5f78359 (patch)
tree1c7bddb423c2a970ec7b3992f3ad9f61a9a716b6 /src/libsyntax/parse
parentb61e69433951e31f7bd746e22f516a48ad41623b (diff)
downloadrust-8fd03b1e47147794ff955a13a474cd52a5f78359.tar.gz
rust-8fd03b1e47147794ff955a13a474cd52a5f78359.zip
syntax: fix #64682.
Fuse parsing of `self` into `parse_param_general`.
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs73
-rw-r--r--src/libsyntax/parse/parser/item.rs44
2 files changed, 41 insertions, 76 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index cc582819b6b..6ef8a16269a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -974,15 +974,22 @@ impl<'a> Parser<'a> {
     /// This version of parse param doesn't necessarily require identifier names.
     fn parse_param_general(
         &mut self,
+        is_self_allowed: bool,
         is_trait_item: bool,
         allow_c_variadic: bool,
         is_name_required: impl Fn(&token::Token) -> bool,
     ) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
+
+        // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
         if let Some(mut param) = self.parse_self_param()? {
             param.attrs = attrs.into();
-            return self.recover_bad_self_param(param, is_trait_item);
+            return if is_self_allowed {
+                Ok(param)
+            } else {
+                self.recover_bad_self_param(param, is_trait_item)
+            };
         }
 
         let is_name_required = is_name_required(&self.token);
@@ -1208,6 +1215,7 @@ impl<'a> Parser<'a> {
                 };
             match p.parse_param_general(
                 false,
+                false,
                 allow_c_variadic,
                 do_not_enforce_named_arguments_for_c_variadic
             ) {
@@ -1359,60 +1367,25 @@ impl<'a> Parser<'a> {
         Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
     }
 
-    /// Returns the parsed optional self parameter with attributes and whether a self
-    /// shortcut was used.
-    fn parse_self_parameter_with_attrs(&mut self) -> PResult<'a, Option<Param>> {
-        let attrs = self.parse_outer_attributes()?;
-        let param_opt = self.parse_self_param()?;
-        Ok(param_opt.map(|mut param| {
-            param.attrs = attrs.into();
-            param
-        }))
-    }
-
     /// Parses the parameter list and result type of a function that may have a `self` parameter.
-    fn parse_fn_decl_with_self<F>(&mut self, parse_param_fn: F) -> PResult<'a, P<FnDecl>>
-        where F: FnMut(&mut Parser<'a>) -> PResult<'a,  Param>,
-    {
-        self.expect(&token::OpenDelim(token::Paren))?;
-
-        // Parse optional self argument.
-        let self_param = self.parse_self_parameter_with_attrs()?;
-
-        // Parse the rest of the function parameter list.
-        let sep = SeqSep::trailing_allowed(token::Comma);
-        let (mut fn_inputs, recovered) = if let Some(self_param) = self_param {
-            if self.check(&token::CloseDelim(token::Paren)) {
-                (vec![self_param], false)
-            } else if self.eat(&token::Comma) {
-                let mut fn_inputs = vec![self_param];
-                let (mut input, _, recovered) = self.parse_seq_to_before_end(
-                    &token::CloseDelim(token::Paren), sep, parse_param_fn)?;
-                fn_inputs.append(&mut input);
-                (fn_inputs, recovered)
-            } else {
-                match self.expect_one_of(&[], &[]) {
-                    Err(err) => return Err(err),
-                    Ok(recovered) => (vec![self_param], recovered),
-                }
-            }
-        } else {
-            let (input, _, recovered) =
-                self.parse_seq_to_before_end(&token::CloseDelim(token::Paren),
-                                             sep,
-                                             parse_param_fn)?;
-            (input, recovered)
-        };
+    fn parse_fn_decl_with_self(
+        &mut self,
+        is_name_required: impl Copy + Fn(&token::Token) -> bool,
+    ) -> PResult<'a, P<FnDecl>> {
+        // Parse the arguments, starting out with `self` being allowed...
+        let mut is_self_allowed = true;
+        let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| {
+            let res = p.parse_param_general(is_self_allowed, true, false, is_name_required);
+            // ...but now that we've parsed the first argument, `self` is no longer allowed.
+            is_self_allowed = false;
+            res
+        })?;
 
-        if !recovered {
-            // Parse closing paren and return type.
-            self.expect(&token::CloseDelim(token::Paren))?;
-        }
         // Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
-        self.deduplicate_recovered_params_names(&mut fn_inputs);
+        self.deduplicate_recovered_params_names(&mut inputs);
 
         Ok(P(FnDecl {
-            inputs: fn_inputs,
+            inputs,
             output: self.parse_ret_ty(true)?,
             c_variadic: false
         }))
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index 370030d02c7..9762d9d459f 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -424,13 +424,7 @@ impl<'a> Parser<'a> {
             } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
                 let ident = self.parse_ident().unwrap();
                 self.bump();  // `(`
-                let kw_name = if let Ok(Some(_)) = self.parse_self_parameter_with_attrs()
-                    .map_err(|mut e| e.cancel())
-                {
-                    "method"
-                } else {
-                    "function"
-                };
+                let kw_name = self.recover_first_param();
                 self.consume_block(token::Paren);
                 let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
                     self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
@@ -477,13 +471,7 @@ impl<'a> Parser<'a> {
                 self.eat_to_tokens(&[&token::Gt]);
                 self.bump();  // `>`
                 let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
-                    if let Ok(Some(_)) = self.parse_self_parameter_with_attrs()
-                        .map_err(|mut e| e.cancel())
-                    {
-                        ("fn", "method", false)
-                    } else {
-                        ("fn", "function", false)
-                    }
+                    ("fn", self.recover_first_param(), false)
                 } else if self.check(&token::OpenDelim(token::Brace)) {
                     ("struct", "struct", false)
                 } else {
@@ -505,6 +493,16 @@ impl<'a> Parser<'a> {
         self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)
     }
 
+    fn recover_first_param(&mut self) -> &'static str {
+        match self.parse_outer_attributes()
+            .and_then(|_| self.parse_self_param())
+            .map_err(|mut e| e.cancel())
+        {
+            Ok(Some(_)) => "method",
+            _ => "function",
+        }
+    }
+
     /// This is the fall-through for parsing items.
     fn parse_macro_use_or_failure(
         &mut self,
@@ -861,9 +859,7 @@ impl<'a> Parser<'a> {
             let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
-            let decl = self.parse_fn_decl_with_self(|p| {
-                p.parse_param_general(true, false, |_| true)
-            })?;
+            let decl = self.parse_fn_decl_with_self(|_| true)?;
             generics.where_clause = self.parse_where_clause()?;
             *at_end = true;
             let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -1034,15 +1030,11 @@ impl<'a> Parser<'a> {
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
 
-            let decl = 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...
-
-                // We don't allow argument names to be left off in edition 2018.
-                let is_name_required = p.token.span.rust_2018();
-                p.parse_param_general(true, false, |_| is_name_required)
-            })?;
+            // This is somewhat dubious; We don't want to allow
+            // argument names to be left off if there is a definition...
+            //
+            // We don't allow argument names to be left off in edition 2018.
+            let decl = self.parse_fn_decl_with_self(|t| t.span.rust_2018())?;
             generics.where_clause = self.parse_where_clause()?;
 
             let sig = ast::MethodSig {