Allow attributes in formal function parameters

This commit is contained in:
Caio
2019-06-09 07:58:40 -03:00
parent 5c45343f11
commit 1eaaf440d5
28 changed files with 1115 additions and 74 deletions

View File

@@ -1188,7 +1188,8 @@ impl<'a> Parser<'a> {
// definition...
// We don't allow argument names to be left off in edition 2018.
p.parse_arg_general(p.token.span.rust_2018(), true, false)
let is_name_required = p.token.span.rust_2018();
p.parse_arg_general(true, false, |_| is_name_required)
})?;
generics.where_clause = self.parse_where_clause()?;
@@ -1487,26 +1488,31 @@ impl<'a> Parser<'a> {
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
/// error.
/// This version of parse arg doesn't necessarily require identifier names.
fn parse_arg_general(
fn parse_arg_general<F>(
&mut self,
require_name: bool,
is_trait_item: bool,
allow_c_variadic: bool,
) -> PResult<'a, Arg> {
if let Ok(Some(arg)) = self.parse_self_arg() {
is_name_required: F,
) -> PResult<'a, Arg>
where
F: Fn(&token::Token) -> bool
{
let attrs = self.parse_arg_attributes()?;
if let Ok(Some(mut arg)) = self.parse_self_arg() {
arg.attrs = attrs.into();
return self.recover_bad_self_arg(arg, is_trait_item);
}
let (pat, ty) = if require_name || self.is_named_argument() {
debug!("parse_arg_general parse_pat (require_name:{})", require_name);
self.eat_incorrect_doc_comment("method arguments");
let pat = self.parse_pat(Some("argument name"))?;
let is_name_required = is_name_required(&self.token);
let (pat, ty) = if is_name_required || self.is_named_argument() {
debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required);
let pat = self.parse_pat(Some("argument name"))?;
if let Err(mut err) = self.expect(&token::Colon) {
if let Some(ident) = self.argument_without_type(
&mut err,
pat,
require_name,
is_name_required,
is_trait_item,
) {
err.emit();
@@ -1516,12 +1522,12 @@ impl<'a> Parser<'a> {
}
}
self.eat_incorrect_doc_comment("a method argument's type");
self.eat_incorrect_doc_comment_for_arg_type();
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
} else {
debug!("parse_arg_general ident_to_pat");
let parser_snapshot_before_ty = self.clone();
self.eat_incorrect_doc_comment("a method argument's type");
self.eat_incorrect_doc_comment_for_arg_type();
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
if ty.is_ok() && self.token != token::Comma &&
self.token != token::CloseDelim(token::Paren) {
@@ -1554,11 +1560,12 @@ impl<'a> Parser<'a> {
}
};
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, ty })
}
/// Parses an argument in a lambda header (e.g., `|arg, arg|`).
fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> {
let attrs = self.parse_arg_attributes()?;
let pat = self.parse_pat(Some("argument name"))?;
let t = if self.eat(&token::Colon) {
self.parse_ty()?
@@ -1570,6 +1577,7 @@ impl<'a> Parser<'a> {
})
};
Ok(Arg {
attrs: attrs.into(),
ty: t,
pat,
id: ast::DUMMY_NODE_ID
@@ -5411,15 +5419,19 @@ impl<'a> Parser<'a> {
&token::CloseDelim(token::Paren),
SeqSep::trailing_allowed(token::Comma),
|p| {
// If the argument is a C-variadic argument we should not
// enforce named arguments.
let enforce_named_args = if p.token == token::DotDotDot {
false
} else {
named_args
};
match p.parse_arg_general(enforce_named_args, false,
allow_c_variadic) {
let do_not_enforce_named_arguments_for_c_variadic =
|token: &token::Token| -> bool {
if token == &token::DotDotDot {
false
} else {
named_args
}
};
match p.parse_arg_general(
false,
allow_c_variadic,
do_not_enforce_named_arguments_for_c_variadic
) {
Ok(arg) => {
if let TyKind::CVarArgs = arg.ty.node {
c_variadic = true;
@@ -5464,7 +5476,6 @@ impl<'a> Parser<'a> {
/// Parses the argument list and result type of a function declaration.
fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> {
let (args, c_variadic) = self.parse_fn_args(true, allow_c_variadic)?;
let ret_ty = self.parse_ret_ty(true)?;
@@ -5476,6 +5487,8 @@ impl<'a> Parser<'a> {
}
/// Returns the parsed optional self argument and whether a self shortcut was used.
///
/// See `parse_self_arg_with_attrs` to collect attributes.
fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> {
let expect_ident = |this: &mut Self| match this.token.kind {
// Preserve hygienic context.
@@ -5581,7 +5594,18 @@ impl<'a> Parser<'a> {
};
let eself = source_map::respan(eself_lo.to(eself_hi), eself);
Ok(Some(Arg::from_self(eself, eself_ident)))
Ok(Some(Arg::from_self(ThinVec::default(), eself, eself_ident)))
}
/// Returns the parsed optional self argument with attributes and whether a self
/// shortcut was used.
fn parse_self_arg_with_attrs(&mut self) -> PResult<'a, Option<Arg>> {
let attrs = self.parse_arg_attributes()?;
let arg_opt = self.parse_self_arg()?;
Ok(arg_opt.map(|mut arg| {
arg.attrs = attrs.into();
arg
}))
}
/// Parses the parameter list and result type of a function that may have a `self` parameter.
@@ -5591,7 +5615,7 @@ impl<'a> Parser<'a> {
self.expect(&token::OpenDelim(token::Paren))?;
// Parse optional self argument.
let self_arg = self.parse_self_arg()?;
let self_arg = self.parse_self_arg_with_attrs()?;
// Parse the rest of the function parameter list.
let sep = SeqSep::trailing_allowed(token::Comma);
@@ -5865,7 +5889,7 @@ impl<'a> Parser<'a> {
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
let decl = self.parse_fn_decl_with_self(|p| {
p.parse_arg_general(true, true, false)
p.parse_arg_general(true, false, |_| true)
})?;
generics.where_clause = self.parse_where_clause()?;
*at_end = true;
@@ -7441,7 +7465,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_arg() {
let kw_name = if let Ok(Some(_)) = self.parse_self_arg_with_attrs() {
"method"
} else {
"function"
@@ -7492,7 +7516,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_arg() {
if let Ok(Some(_)) = self.parse_self_arg_with_attrs() {
("fn", "method", false)
} else {
("fn", "function", false)