diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-09-29 09:26:02 +0200 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-09-29 12:55:45 +0200 |
| commit | 8fd03b1e47147794ff955a13a474cd52a5f78359 (patch) | |
| tree | 1c7bddb423c2a970ec7b3992f3ad9f61a9a716b6 /src/libsyntax/parse | |
| parent | b61e69433951e31f7bd746e22f516a48ad41623b (diff) | |
| download | rust-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.rs | 73 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser/item.rs | 44 |
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 { |
