| use crate::grammar::attributes::ATTRIBUTE_FIRST; |
| |
| use super::*; |
| |
| // test param_list |
| // fn a() {} |
| // fn b(x: i32) {} |
| // fn c(x: i32, ) {} |
| // fn d(x: i32, y: ()) {} |
| |
| // test_err empty_param_slot |
| // fn f(y: i32, ,t: i32) {} |
| pub(super) fn param_list_fn_def(p: &mut Parser<'_>) { |
| list_(p, Flavor::FnDef); |
| } |
| |
| pub(super) fn param_list_fn_ptr(p: &mut Parser<'_>) { |
| list_(p, Flavor::FnPointer); |
| } |
| |
| pub(super) fn param_list_closure(p: &mut Parser<'_>) { |
| list_(p, Flavor::Closure); |
| } |
| |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| enum Flavor { |
| FnDef, // Includes trait fn params; omitted param idents are not supported |
| FnPointer, |
| Closure, |
| } |
| |
| fn list_(p: &mut Parser<'_>, flavor: Flavor) { |
| use Flavor::*; |
| |
| let (bra, ket) = match flavor { |
| Closure => (T![|], T![|]), |
| FnDef | FnPointer => (T!['('], T![')']), |
| }; |
| |
| let list_marker = p.start(); |
| p.bump(bra); |
| |
| let mut param_marker = None; |
| if let FnDef = flavor { |
| // test self_param_outer_attr |
| // fn f(#[must_use] self) {} |
| let m = p.start(); |
| attributes::outer_attrs(p); |
| match opt_self_param(p, m) { |
| Ok(()) => {} |
| Err(m) => param_marker = Some(m), |
| } |
| } |
| |
| while !p.at(EOF) && !p.at(ket) { |
| // test param_outer_arg |
| // fn f(#[attr1] pat: Type) {} |
| let m = match param_marker.take() { |
| Some(m) => m, |
| None => { |
| let m = p.start(); |
| attributes::outer_attrs(p); |
| m |
| } |
| }; |
| |
| if !p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) { |
| p.error("expected value parameter"); |
| m.abandon(p); |
| if p.eat(T![,]) { |
| continue; |
| } |
| break; |
| } |
| param(p, m, flavor); |
| if !p.eat(T![,]) { |
| if p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) { |
| p.error("expected `,`"); |
| } else { |
| break; |
| } |
| } |
| } |
| |
| if let Some(m) = param_marker { |
| m.abandon(p); |
| } |
| |
| p.expect(ket); |
| list_marker.complete(p, PARAM_LIST); |
| } |
| |
| const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); |
| |
| fn param(p: &mut Parser<'_>, m: Marker, flavor: Flavor) { |
| match flavor { |
| // test param_list_vararg |
| // extern "C" { fn printf(format: *const i8, ..., _: u8) -> i32; } |
| Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => {} |
| |
| // test fn_def_param |
| // fn foo(..., (x, y): (i32, i32)) {} |
| Flavor::FnDef => { |
| patterns::pattern(p); |
| if !variadic_param(p) { |
| if p.at(T![:]) { |
| types::ascription(p); |
| } else { |
| // test_err missing_fn_param_type |
| // fn f(x y: i32, z, t: i32) {} |
| p.error("missing type for function parameter"); |
| } |
| } |
| } |
| // test fn_pointer_param_ident_path |
| // type Foo = fn(Bar::Baz); |
| // type Qux = fn(baz: Bar::Baz); |
| |
| // test fn_pointer_unnamed_arg |
| // type Foo = fn(_: bar); |
| Flavor::FnPointer => { |
| if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) { |
| patterns::pattern_single(p); |
| if !variadic_param(p) { |
| if p.at(T![:]) { |
| types::ascription(p); |
| } else { |
| p.error("missing type for function parameter"); |
| } |
| } |
| } else { |
| types::type_(p); |
| } |
| } |
| // test closure_params |
| // fn main() { |
| // let foo = |bar, baz: Baz, qux: Qux::Quux| (); |
| // } |
| Flavor::Closure => { |
| patterns::pattern_single(p); |
| if p.at(T![:]) && !p.at(T![::]) { |
| types::ascription(p); |
| } |
| } |
| } |
| m.complete(p, PARAM); |
| } |
| |
| fn variadic_param(p: &mut Parser<'_>) -> bool { |
| if p.at(T![:]) && p.nth_at(1, T![...]) { |
| p.bump(T![:]); |
| p.bump(T![...]); |
| true |
| } else { |
| false |
| } |
| } |
| |
| // test self_param |
| // impl S { |
| // fn a(self) {} |
| // fn b(&self,) {} |
| // fn c(&'a self,) {} |
| // fn d(&'a mut self, x: i32) {} |
| // fn e(mut self) {} |
| // } |
| fn opt_self_param(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { |
| if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { |
| p.eat(T![mut]); |
| self_as_name(p); |
| // test arb_self_types |
| // impl S { |
| // fn a(self: &Self) {} |
| // fn b(mut self: Box<Self>) {} |
| // } |
| if p.at(T![:]) { |
| types::ascription(p); |
| } |
| } else { |
| let la1 = p.nth(1); |
| let la2 = p.nth(2); |
| let la3 = p.nth(3); |
| if !matches!( |
| (p.current(), la1, la2, la3), |
| (T![&], T![self], _, _) |
| | (T![&], T![mut] | LIFETIME_IDENT, T![self], _) |
| | (T![&], LIFETIME_IDENT, T![mut], T![self]) |
| ) { |
| return Err(m); |
| } |
| p.bump(T![&]); |
| if p.at(LIFETIME_IDENT) { |
| lifetime(p); |
| } |
| p.eat(T![mut]); |
| self_as_name(p); |
| } |
| m.complete(p, SELF_PARAM); |
| if !p.at(T![')']) { |
| p.expect(T![,]); |
| } |
| Ok(()) |
| } |
| |
| fn self_as_name(p: &mut Parser<'_>) { |
| let m = p.start(); |
| p.bump(T![self]); |
| m.complete(p, NAME); |
| } |