syntax: unify and simplify fn signature parsing.
This commit is contained in:
parent
7f9638d5d4
commit
a7ba754b6c
5 changed files with 88 additions and 92 deletions
|
@ -11,7 +11,7 @@ mod stmt;
|
||||||
mod generics;
|
mod generics;
|
||||||
|
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, FnDecl, Ident,
|
self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident,
|
||||||
IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility,
|
IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility,
|
||||||
VisibilityKind, Unsafety,
|
VisibilityKind, Unsafety,
|
||||||
};
|
};
|
||||||
|
@ -56,6 +56,17 @@ crate enum BlockMode {
|
||||||
Ignore,
|
Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
|
||||||
|
struct ParamCfg {
|
||||||
|
/// Is `self` is allowed as the first parameter?
|
||||||
|
is_self_allowed: bool,
|
||||||
|
/// Is `...` allowed as the tail of the parameter list?
|
||||||
|
allow_c_variadic: bool,
|
||||||
|
/// `is_name_required` decides if, per-parameter,
|
||||||
|
/// the parameter must have a pattern or just a type.
|
||||||
|
is_name_required: fn(&token::Token) -> bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Like `maybe_whole_expr`, but for things other than expressions.
|
/// Like `maybe_whole_expr`, but for things other than expressions.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! maybe_whole {
|
macro_rules! maybe_whole {
|
||||||
|
@ -1094,26 +1105,18 @@ impl<'a> Parser<'a> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_params(
|
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
|
||||||
&mut self,
|
fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
|
||||||
named_params: bool,
|
|
||||||
allow_c_variadic: bool,
|
|
||||||
) -> PResult<'a, Vec<Param>> {
|
|
||||||
let sp = self.token.span;
|
let sp = self.token.span;
|
||||||
let do_not_enforce_named_params_for_c_variadic = |token: &token::Token| {
|
let is_trait_item = cfg.is_self_allowed;
|
||||||
match token.kind {
|
|
||||||
token::DotDotDot => false,
|
|
||||||
_ => named_params,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut c_variadic = false;
|
let mut c_variadic = false;
|
||||||
|
// Parse the arguments, starting out with `self` being possibly allowed...
|
||||||
let (params, _) = self.parse_paren_comma_seq(|p| {
|
let (params, _) = self.parse_paren_comma_seq(|p| {
|
||||||
match p.parse_param_general(
|
let param = p.parse_param_general(&cfg, is_trait_item);
|
||||||
false,
|
// ...now that we've parsed the first argument, `self` is no longer allowed.
|
||||||
false,
|
cfg.is_self_allowed = false;
|
||||||
allow_c_variadic,
|
|
||||||
do_not_enforce_named_params_for_c_variadic,
|
match param {
|
||||||
) {
|
|
||||||
Ok(param) => Ok(
|
Ok(param) => Ok(
|
||||||
if let TyKind::CVarArgs = param.ty.kind {
|
if let TyKind::CVarArgs = param.ty.kind {
|
||||||
c_variadic = true;
|
c_variadic = true;
|
||||||
|
@ -1144,7 +1147,10 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
|
let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
|
||||||
|
|
||||||
|
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
|
||||||
|
self.deduplicate_recovered_params_names(&mut params);
|
||||||
|
|
||||||
if c_variadic && params.len() <= 1 {
|
if c_variadic && params.len() <= 1 {
|
||||||
self.span_err(
|
self.span_err(
|
||||||
|
@ -1156,79 +1162,53 @@ impl<'a> Parser<'a> {
|
||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the parameter list and result type of a function that may have a `self` parameter.
|
|
||||||
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
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
|
|
||||||
self.deduplicate_recovered_params_names(&mut inputs);
|
|
||||||
|
|
||||||
Ok(P(FnDecl {
|
|
||||||
inputs,
|
|
||||||
output: self.parse_ret_ty(true)?,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
|
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
|
||||||
/// error.
|
/// error.
|
||||||
/// This version of parse param doesn't necessarily require identifier names.
|
/// This version of parse param doesn't necessarily require identifier names.
|
||||||
fn parse_param_general(
|
fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> {
|
||||||
&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 lo = self.token.span;
|
||||||
let attrs = self.parse_outer_attributes()?;
|
let attrs = self.parse_outer_attributes()?;
|
||||||
|
|
||||||
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
||||||
if let Some(mut param) = self.parse_self_param()? {
|
if let Some(mut param) = self.parse_self_param()? {
|
||||||
param.attrs = attrs.into();
|
param.attrs = attrs.into();
|
||||||
return if is_self_allowed {
|
return if cfg.is_self_allowed {
|
||||||
Ok(param)
|
Ok(param)
|
||||||
} else {
|
} else {
|
||||||
self.recover_bad_self_param(param, is_trait_item)
|
self.recover_bad_self_param(param, is_trait_item)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_name_required = is_name_required(&self.token);
|
let is_name_required = match self.token.kind {
|
||||||
|
token::DotDotDot => false,
|
||||||
|
_ => (cfg.is_name_required)(&self.token),
|
||||||
|
};
|
||||||
let (pat, ty) = if is_name_required || self.is_named_param() {
|
let (pat, ty) = if is_name_required || self.is_named_param() {
|
||||||
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
||||||
|
|
||||||
let pat = self.parse_fn_param_pat()?;
|
let pat = self.parse_fn_param_pat()?;
|
||||||
if let Err(mut err) = self.expect(&token::Colon) {
|
if let Err(mut err) = self.expect(&token::Colon) {
|
||||||
if let Some(ident) = self.parameter_without_type(
|
return if let Some(ident) = self.parameter_without_type(
|
||||||
&mut err,
|
&mut err,
|
||||||
pat,
|
pat,
|
||||||
is_name_required,
|
is_name_required,
|
||||||
is_self_allowed,
|
cfg.is_self_allowed,
|
||||||
is_trait_item,
|
is_trait_item,
|
||||||
) {
|
) {
|
||||||
err.emit();
|
err.emit();
|
||||||
return Ok(dummy_arg(ident));
|
Ok(dummy_arg(ident))
|
||||||
} else {
|
} else {
|
||||||
return Err(err);
|
Err(err)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
self.eat_incorrect_doc_comment_for_param_type();
|
self.eat_incorrect_doc_comment_for_param_type();
|
||||||
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
|
(pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
|
||||||
} else {
|
} else {
|
||||||
debug!("parse_param_general ident_to_pat");
|
debug!("parse_param_general ident_to_pat");
|
||||||
let parser_snapshot_before_ty = self.clone();
|
let parser_snapshot_before_ty = self.clone();
|
||||||
self.eat_incorrect_doc_comment_for_param_type();
|
self.eat_incorrect_doc_comment_for_param_type();
|
||||||
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
|
let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
|
||||||
if ty.is_ok() && self.token != token::Comma &&
|
if ty.is_ok() && self.token != token::Comma &&
|
||||||
self.token != token::CloseDelim(token::Paren) {
|
self.token != token::CloseDelim(token::Paren) {
|
||||||
// This wasn't actually a type, but a pattern looking like a type,
|
// This wasn't actually a type, but a pattern looking like a type,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode};
|
use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode, ParamCfg};
|
||||||
|
|
||||||
use crate::maybe_whole;
|
use crate::maybe_whole;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
|
@ -805,14 +805,15 @@ impl<'a> Parser<'a> {
|
||||||
/// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
|
/// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
|
||||||
fn parse_method_sig(
|
fn parse_method_sig(
|
||||||
&mut self,
|
&mut self,
|
||||||
is_name_required: impl Copy + Fn(&token::Token) -> bool,
|
is_name_required: fn(&token::Token) -> bool,
|
||||||
) -> PResult<'a, (Ident, MethodSig, Generics)> {
|
) -> PResult<'a, (Ident, MethodSig, Generics)> {
|
||||||
let header = self.parse_fn_front_matter()?;
|
let header = self.parse_fn_front_matter()?;
|
||||||
let (ident, mut generics) = self.parse_fn_header()?;
|
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
|
||||||
let decl = self.parse_fn_decl_with_self(is_name_required)?;
|
is_self_allowed: true,
|
||||||
let sig = MethodSig { header, decl };
|
allow_c_variadic: false,
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
is_name_required,
|
||||||
Ok((ident, sig, generics))
|
})?;
|
||||||
|
Ok((ident, MethodSig { header, decl }, generics))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses all the "front matter" for a `fn` declaration, up to
|
/// Parses all the "front matter" for a `fn` declaration, up to
|
||||||
|
@ -1200,36 +1201,34 @@ impl<'a> Parser<'a> {
|
||||||
attrs: Vec<Attribute>,
|
attrs: Vec<Attribute>,
|
||||||
header: FnHeader,
|
header: FnHeader,
|
||||||
) -> PResult<'a, Option<P<Item>>> {
|
) -> PResult<'a, Option<P<Item>>> {
|
||||||
let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe;
|
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
|
||||||
let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?;
|
is_self_allowed: false,
|
||||||
|
allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe,
|
||||||
|
is_name_required: |_| true,
|
||||||
|
})?;
|
||||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||||
let kind = ItemKind::Fn(decl, header, generics, body);
|
let kind = ItemKind::Fn(decl, header, generics, body);
|
||||||
self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
|
self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the "signature", including the identifier, parameters, and generics of a function.
|
/// Parse the "signature", including the identifier, parameters, and generics of a function.
|
||||||
fn parse_fn_sig(
|
fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
|
||||||
&mut self,
|
let ident = self.parse_ident()?;
|
||||||
allow_c_variadic: bool,
|
let mut generics = self.parse_generics()?;
|
||||||
) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
|
let decl = self.parse_fn_decl(cfg, true)?;
|
||||||
let (ident, mut generics) = self.parse_fn_header()?;
|
|
||||||
let decl = self.parse_fn_decl(allow_c_variadic)?;
|
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
generics.where_clause = self.parse_where_clause()?;
|
||||||
Ok((ident, decl, generics))
|
Ok((ident, decl, generics))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the name and optional generic types of a function header.
|
|
||||||
fn parse_fn_header(&mut self) -> PResult<'a, (Ident, Generics)> {
|
|
||||||
let id = self.parse_ident()?;
|
|
||||||
let generics = self.parse_generics()?;
|
|
||||||
Ok((id, generics))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses the parameter list and result type of a function declaration.
|
/// Parses the parameter list and result type of a function declaration.
|
||||||
fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> {
|
pub(super) fn parse_fn_decl(
|
||||||
|
&mut self,
|
||||||
|
cfg: ParamCfg,
|
||||||
|
ret_allow_plus: bool,
|
||||||
|
) -> PResult<'a, P<FnDecl>> {
|
||||||
Ok(P(FnDecl {
|
Ok(P(FnDecl {
|
||||||
inputs: self.parse_fn_params(true, allow_c_variadic)?,
|
inputs: self.parse_fn_params(cfg)?,
|
||||||
output: self.parse_ret_ty(true)?,
|
output: self.parse_ret_ty(ret_allow_plus)?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1353,7 +1352,11 @@ impl<'a> Parser<'a> {
|
||||||
extern_sp: Span,
|
extern_sp: Span,
|
||||||
) -> PResult<'a, ForeignItem> {
|
) -> PResult<'a, ForeignItem> {
|
||||||
self.expect_keyword(kw::Fn)?;
|
self.expect_keyword(kw::Fn)?;
|
||||||
let (ident, decl, generics) = self.parse_fn_sig(true)?;
|
let (ident, decl, generics) = self.parse_fn_sig(super::ParamCfg {
|
||||||
|
is_self_allowed: false,
|
||||||
|
allow_c_variadic: true,
|
||||||
|
is_name_required: |_| true,
|
||||||
|
})?;
|
||||||
let span = lo.to(self.token.span);
|
let span = lo.to(self.token.span);
|
||||||
self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
|
self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
|
||||||
Ok(ast::ForeignItem {
|
Ok(ast::ForeignItem {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident};
|
use crate::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident};
|
||||||
use crate::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
|
use crate::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
|
||||||
use crate::ast::{Mutability, AnonConst, FnDecl, Mac};
|
use crate::ast::{Mutability, AnonConst, Mac};
|
||||||
use crate::parse::token::{self, Token};
|
use crate::parse::token::{self, Token};
|
||||||
use crate::source_map::Span;
|
use crate::source_map::Span;
|
||||||
use crate::symbol::{kw};
|
use crate::symbol::{kw};
|
||||||
|
@ -288,12 +288,12 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.expect_keyword(kw::Fn)?;
|
self.expect_keyword(kw::Fn)?;
|
||||||
let inputs = self.parse_fn_params(false, true)?;
|
let cfg = super::ParamCfg {
|
||||||
let ret_ty = self.parse_ret_ty(false)?;
|
is_self_allowed: false,
|
||||||
let decl = P(FnDecl {
|
allow_c_variadic: true,
|
||||||
inputs,
|
is_name_required: |_| false,
|
||||||
output: ret_ty,
|
};
|
||||||
});
|
let decl = self.parse_fn_decl(cfg, false)?;
|
||||||
Ok(TyKind::BareFn(P(BareFnTy {
|
Ok(TyKind::BareFn(P(BareFnTy {
|
||||||
abi,
|
abi,
|
||||||
unsafety,
|
unsafety,
|
||||||
|
|
|
@ -3,6 +3,7 @@ struct S;
|
||||||
impl S {
|
impl S {
|
||||||
fn f(*, a: u8) -> u8 {}
|
fn f(*, a: u8) -> u8 {}
|
||||||
//~^ ERROR expected parameter name, found `*`
|
//~^ ERROR expected parameter name, found `*`
|
||||||
|
//~| ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,5 +4,17 @@ error: expected parameter name, found `*`
|
||||||
LL | fn f(*, a: u8) -> u8 {}
|
LL | fn f(*, a: u8) -> u8 {}
|
||||||
| ^ expected parameter name
|
| ^ expected parameter name
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-33413.rs:4:23
|
||||||
|
|
|
||||||
|
LL | fn f(*, a: u8) -> u8 {}
|
||||||
|
| - ^^ expected u8, found ()
|
||||||
|
| |
|
||||||
|
| implicitly returns `()` as its body has no tail or `return` expression
|
||||||
|
|
|
||||||
|
= note: expected type `u8`
|
||||||
|
found type `()`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue