Skip to content

Commit a7ba754

Browse files
committed
syntax: unify and simplify fn signature parsing.
1 parent 7f9638d commit a7ba754

File tree

5 files changed

+88
-92
lines changed

5 files changed

+88
-92
lines changed

src/libsyntax/parse/parser.rs

+38-58
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ mod stmt;
1111
mod generics;
1212

1313
use crate::ast::{
14-
self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, FnDecl, Ident,
14+
self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident,
1515
IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility,
1616
VisibilityKind, Unsafety,
1717
};
@@ -56,6 +56,17 @@ crate enum BlockMode {
5656
Ignore,
5757
}
5858

59+
/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
60+
struct ParamCfg {
61+
/// Is `self` is allowed as the first parameter?
62+
is_self_allowed: bool,
63+
/// Is `...` allowed as the tail of the parameter list?
64+
allow_c_variadic: bool,
65+
/// `is_name_required` decides if, per-parameter,
66+
/// the parameter must have a pattern or just a type.
67+
is_name_required: fn(&token::Token) -> bool,
68+
}
69+
5970
/// Like `maybe_whole_expr`, but for things other than expressions.
6071
#[macro_export]
6172
macro_rules! maybe_whole {
@@ -1094,26 +1105,18 @@ impl<'a> Parser<'a> {
10941105
res
10951106
}
10961107

1097-
fn parse_fn_params(
1098-
&mut self,
1099-
named_params: bool,
1100-
allow_c_variadic: bool,
1101-
) -> PResult<'a, Vec<Param>> {
1108+
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
1109+
fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
11021110
let sp = self.token.span;
1103-
let do_not_enforce_named_params_for_c_variadic = |token: &token::Token| {
1104-
match token.kind {
1105-
token::DotDotDot => false,
1106-
_ => named_params,
1107-
}
1108-
};
1111+
let is_trait_item = cfg.is_self_allowed;
11091112
let mut c_variadic = false;
1113+
// Parse the arguments, starting out with `self` being possibly allowed...
11101114
let (params, _) = self.parse_paren_comma_seq(|p| {
1111-
match p.parse_param_general(
1112-
false,
1113-
false,
1114-
allow_c_variadic,
1115-
do_not_enforce_named_params_for_c_variadic,
1116-
) {
1115+
let param = p.parse_param_general(&cfg, is_trait_item);
1116+
// ...now that we've parsed the first argument, `self` is no longer allowed.
1117+
cfg.is_self_allowed = false;
1118+
1119+
match param {
11171120
Ok(param) => Ok(
11181121
if let TyKind::CVarArgs = param.ty.kind {
11191122
c_variadic = true;
@@ -1144,7 +1147,10 @@ impl<'a> Parser<'a> {
11441147
}
11451148
})?;
11461149

1147-
let params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
1150+
let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
1151+
1152+
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
1153+
self.deduplicate_recovered_params_names(&mut params);
11481154

11491155
if c_variadic && params.len() <= 1 {
11501156
self.span_err(
@@ -1156,79 +1162,53 @@ impl<'a> Parser<'a> {
11561162
Ok(params)
11571163
}
11581164

1159-
/// Parses the parameter list and result type of a function that may have a `self` parameter.
1160-
fn parse_fn_decl_with_self(
1161-
&mut self,
1162-
is_name_required: impl Copy + Fn(&token::Token) -> bool,
1163-
) -> PResult<'a, P<FnDecl>> {
1164-
// Parse the arguments, starting out with `self` being allowed...
1165-
let mut is_self_allowed = true;
1166-
let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| {
1167-
let res = p.parse_param_general(is_self_allowed, true, false, is_name_required);
1168-
// ...but now that we've parsed the first argument, `self` is no longer allowed.
1169-
is_self_allowed = false;
1170-
res
1171-
})?;
1172-
1173-
// Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
1174-
self.deduplicate_recovered_params_names(&mut inputs);
1175-
1176-
Ok(P(FnDecl {
1177-
inputs,
1178-
output: self.parse_ret_ty(true)?,
1179-
}))
1180-
}
1181-
11821165
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
11831166
/// error.
11841167
/// This version of parse param doesn't necessarily require identifier names.
1185-
fn parse_param_general(
1186-
&mut self,
1187-
is_self_allowed: bool,
1188-
is_trait_item: bool,
1189-
allow_c_variadic: bool,
1190-
is_name_required: impl Fn(&token::Token) -> bool,
1191-
) -> PResult<'a, Param> {
1168+
fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> {
11921169
let lo = self.token.span;
11931170
let attrs = self.parse_outer_attributes()?;
11941171

11951172
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
11961173
if let Some(mut param) = self.parse_self_param()? {
11971174
param.attrs = attrs.into();
1198-
return if is_self_allowed {
1175+
return if cfg.is_self_allowed {
11991176
Ok(param)
12001177
} else {
12011178
self.recover_bad_self_param(param, is_trait_item)
12021179
};
12031180
}
12041181

1205-
let is_name_required = is_name_required(&self.token);
1182+
let is_name_required = match self.token.kind {
1183+
token::DotDotDot => false,
1184+
_ => (cfg.is_name_required)(&self.token),
1185+
};
12061186
let (pat, ty) = if is_name_required || self.is_named_param() {
12071187
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
12081188

12091189
let pat = self.parse_fn_param_pat()?;
12101190
if let Err(mut err) = self.expect(&token::Colon) {
1211-
if let Some(ident) = self.parameter_without_type(
1191+
return if let Some(ident) = self.parameter_without_type(
12121192
&mut err,
12131193
pat,
12141194
is_name_required,
1215-
is_self_allowed,
1195+
cfg.is_self_allowed,
12161196
is_trait_item,
12171197
) {
12181198
err.emit();
1219-
return Ok(dummy_arg(ident));
1199+
Ok(dummy_arg(ident))
12201200
} else {
1221-
return Err(err);
1222-
}
1201+
Err(err)
1202+
};
12231203
}
12241204

12251205
self.eat_incorrect_doc_comment_for_param_type();
1226-
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
1206+
(pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
12271207
} else {
12281208
debug!("parse_param_general ident_to_pat");
12291209
let parser_snapshot_before_ty = self.clone();
12301210
self.eat_incorrect_doc_comment_for_param_type();
1231-
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
1211+
let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
12321212
if ty.is_ok() && self.token != token::Comma &&
12331213
self.token != token::CloseDelim(token::Paren) {
12341214
// This wasn't actually a type, but a pattern looking like a type,

src/libsyntax/parse/parser/item.rs

+29-26
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode};
1+
use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode, ParamCfg};
22

33
use crate::maybe_whole;
44
use crate::ptr::P;
@@ -805,14 +805,15 @@ impl<'a> Parser<'a> {
805805
/// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
806806
fn parse_method_sig(
807807
&mut self,
808-
is_name_required: impl Copy + Fn(&token::Token) -> bool,
808+
is_name_required: fn(&token::Token) -> bool,
809809
) -> PResult<'a, (Ident, MethodSig, Generics)> {
810810
let header = self.parse_fn_front_matter()?;
811-
let (ident, mut generics) = self.parse_fn_header()?;
812-
let decl = self.parse_fn_decl_with_self(is_name_required)?;
813-
let sig = MethodSig { header, decl };
814-
generics.where_clause = self.parse_where_clause()?;
815-
Ok((ident, sig, generics))
811+
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
812+
is_self_allowed: true,
813+
allow_c_variadic: false,
814+
is_name_required,
815+
})?;
816+
Ok((ident, MethodSig { header, decl }, generics))
816817
}
817818

818819
/// Parses all the "front matter" for a `fn` declaration, up to
@@ -1200,36 +1201,34 @@ impl<'a> Parser<'a> {
12001201
attrs: Vec<Attribute>,
12011202
header: FnHeader,
12021203
) -> PResult<'a, Option<P<Item>>> {
1203-
let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe;
1204-
let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?;
1204+
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
1205+
is_self_allowed: false,
1206+
allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe,
1207+
is_name_required: |_| true,
1208+
})?;
12051209
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
12061210
let kind = ItemKind::Fn(decl, header, generics, body);
12071211
self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
12081212
}
12091213

12101214
/// Parse the "signature", including the identifier, parameters, and generics of a function.
1211-
fn parse_fn_sig(
1212-
&mut self,
1213-
allow_c_variadic: bool,
1214-
) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
1215-
let (ident, mut generics) = self.parse_fn_header()?;
1216-
let decl = self.parse_fn_decl(allow_c_variadic)?;
1215+
fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
1216+
let ident = self.parse_ident()?;
1217+
let mut generics = self.parse_generics()?;
1218+
let decl = self.parse_fn_decl(cfg, true)?;
12171219
generics.where_clause = self.parse_where_clause()?;
12181220
Ok((ident, decl, generics))
12191221
}
12201222

1221-
/// Parses the name and optional generic types of a function header.
1222-
fn parse_fn_header(&mut self) -> PResult<'a, (Ident, Generics)> {
1223-
let id = self.parse_ident()?;
1224-
let generics = self.parse_generics()?;
1225-
Ok((id, generics))
1226-
}
1227-
12281223
/// Parses the parameter list and result type of a function declaration.
1229-
fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> {
1224+
pub(super) fn parse_fn_decl(
1225+
&mut self,
1226+
cfg: ParamCfg,
1227+
ret_allow_plus: bool,
1228+
) -> PResult<'a, P<FnDecl>> {
12301229
Ok(P(FnDecl {
1231-
inputs: self.parse_fn_params(true, allow_c_variadic)?,
1232-
output: self.parse_ret_ty(true)?,
1230+
inputs: self.parse_fn_params(cfg)?,
1231+
output: self.parse_ret_ty(ret_allow_plus)?,
12331232
}))
12341233
}
12351234

@@ -1353,7 +1352,11 @@ impl<'a> Parser<'a> {
13531352
extern_sp: Span,
13541353
) -> PResult<'a, ForeignItem> {
13551354
self.expect_keyword(kw::Fn)?;
1356-
let (ident, decl, generics) = self.parse_fn_sig(true)?;
1355+
let (ident, decl, generics) = self.parse_fn_sig(super::ParamCfg {
1356+
is_self_allowed: false,
1357+
allow_c_variadic: true,
1358+
is_name_required: |_| true,
1359+
})?;
13571360
let span = lo.to(self.token.span);
13581361
self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
13591362
Ok(ast::ForeignItem {

src/libsyntax/parse/parser/ty.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
44
use crate::ptr::P;
55
use crate::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident};
66
use crate::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
7-
use crate::ast::{Mutability, AnonConst, FnDecl, Mac};
7+
use crate::ast::{Mutability, AnonConst, Mac};
88
use crate::parse::token::{self, Token};
99
use crate::source_map::Span;
1010
use crate::symbol::{kw};
@@ -288,12 +288,12 @@ impl<'a> Parser<'a> {
288288
};
289289

290290
self.expect_keyword(kw::Fn)?;
291-
let inputs = self.parse_fn_params(false, true)?;
292-
let ret_ty = self.parse_ret_ty(false)?;
293-
let decl = P(FnDecl {
294-
inputs,
295-
output: ret_ty,
296-
});
291+
let cfg = super::ParamCfg {
292+
is_self_allowed: false,
293+
allow_c_variadic: true,
294+
is_name_required: |_| false,
295+
};
296+
let decl = self.parse_fn_decl(cfg, false)?;
297297
Ok(TyKind::BareFn(P(BareFnTy {
298298
abi,
299299
unsafety,

src/test/ui/parser/issue-33413.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ struct S;
33
impl S {
44
fn f(*, a: u8) -> u8 {}
55
//~^ ERROR expected parameter name, found `*`
6+
//~| ERROR mismatched types
67
}
78

89
fn main() {}

src/test/ui/parser/issue-33413.stderr

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,17 @@ error: expected parameter name, found `*`
44
LL | fn f(*, a: u8) -> u8 {}
55
| ^ expected parameter name
66

7-
error: aborting due to previous error
7+
error[E0308]: mismatched types
8+
--> $DIR/issue-33413.rs:4:23
9+
|
10+
LL | fn f(*, a: u8) -> u8 {}
11+
| - ^^ expected u8, found ()
12+
| |
13+
| implicitly returns `()` as its body has no tail or `return` expression
14+
|
15+
= note: expected type `u8`
16+
found type `()`
17+
18+
error: aborting due to 2 previous errors
819

20+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)