,
- ) -> PResult<'a, Option>> {
- Ok(match self.token.kind {
- token::Semi => {
- debug!("parse_trait_method_body(): parsing required method");
- self.bump();
- *at_end = true;
- None
- }
- token::OpenDelim(token::Brace) => {
- debug!("parse_trait_method_body(): parsing provided method");
- *at_end = true;
- let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
- attrs.extend(inner_attrs.iter().cloned());
- Some(body)
- }
- token::Interpolated(ref nt) => {
- match **nt {
- token::NtBlock(..) => {
- *at_end = true;
- let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
- attrs.extend(inner_attrs.iter().cloned());
- Some(body)
- }
- _ => return self.expected_semi_or_open_brace(),
- }
- }
- _ => return self.expected_semi_or_open_brace(),
- })
- }
-
/// Parses the following grammar:
///
/// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
@@ -1194,45 +1076,6 @@ impl<'a> Parser<'a> {
Ok(ident)
}
- /// Parses an item-position function declaration.
- fn parse_item_fn(
- &mut self,
- lo: Span,
- vis: Visibility,
- attrs: Vec,
- header: FnHeader,
- ) -> PResult<'a, Option>> {
- let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
- 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 kind = ItemKind::Fn(decl, header, generics, body);
- 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.
- fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P, Generics)> {
- let ident = self.parse_ident()?;
- let mut generics = self.parse_generics()?;
- let decl = self.parse_fn_decl(cfg, true)?;
- generics.where_clause = self.parse_where_clause()?;
- Ok((ident, decl, generics))
- }
-
- /// Parses the parameter list and result type of a function declaration.
- pub(super) fn parse_fn_decl(
- &mut self,
- cfg: ParamCfg,
- ret_allow_plus: bool,
- ) -> PResult<'a, P> {
- Ok(P(FnDecl {
- inputs: self.parse_fn_params(cfg)?,
- output: self.parse_ret_ty(ret_allow_plus)?,
- }))
- }
-
/// Parses `extern` for foreign ABIs modules.
///
/// `extern` is expected to have been
@@ -1344,32 +1187,6 @@ impl<'a> Parser<'a> {
}
}
- /// Parses a function declaration from a foreign module.
- fn parse_item_foreign_fn(
- &mut self,
- vis: ast::Visibility,
- lo: Span,
- attrs: Vec,
- extern_sp: Span,
- ) -> PResult<'a, ForeignItem> {
- self.expect_keyword(kw::Fn)?;
- 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);
- self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
- Ok(ast::ForeignItem {
- ident,
- attrs,
- kind: ForeignItemKind::Fn(decl, generics),
- id: DUMMY_NODE_ID,
- span,
- vis,
- })
- }
-
/// Parses a static item from a foreign module.
/// Assumes that the `static` keyword is already parsed.
fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec)
@@ -1910,3 +1727,466 @@ impl<'a> Parser<'a> {
})
}
}
+
+/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
+pub(super) struct ParamCfg {
+ /// Is `self` is allowed as the first parameter?
+ pub is_self_allowed: bool,
+ /// Is `...` allowed as the tail of the parameter list?
+ pub allow_c_variadic: bool,
+ /// `is_name_required` decides if, per-parameter,
+ /// the parameter must have a pattern or just a type.
+ pub is_name_required: fn(&token::Token) -> bool,
+}
+
+/// Parsing of functions and methods.
+impl<'a> Parser<'a> {
+ /// Parses an item-position function declaration.
+ fn parse_item_fn(
+ &mut self,
+ lo: Span,
+ vis: Visibility,
+ attrs: Vec,
+ header: FnHeader,
+ ) -> PResult<'a, Option>> {
+ let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+ 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 kind = ItemKind::Fn(decl, header, generics, body);
+ self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
+ }
+
+ /// Parses a function declaration from a foreign module.
+ fn parse_item_foreign_fn(
+ &mut self,
+ vis: ast::Visibility,
+ lo: Span,
+ attrs: Vec,
+ extern_sp: Span,
+ ) -> PResult<'a, ForeignItem> {
+ self.expect_keyword(kw::Fn)?;
+ let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+ is_self_allowed: false,
+ allow_c_variadic: true,
+ is_name_required: |_| true,
+ })?;
+ let span = lo.to(self.token.span);
+ self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
+ Ok(ast::ForeignItem {
+ ident,
+ attrs,
+ kind: ForeignItemKind::Fn(decl, generics),
+ id: DUMMY_NODE_ID,
+ span,
+ vis,
+ })
+ }
+
+ /// Parses a method or a macro invocation in a trait impl.
+ fn parse_impl_method(
+ &mut self,
+ at_end: &mut bool,
+ ) -> PResult<'a, (Ident, Vec, Generics, ImplItemKind)> {
+ let (ident, sig, generics) = self.parse_method_sig(|_| true)?;
+ *at_end = true;
+ let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+ Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body)))
+ }
+
+ fn parse_trait_item_method(
+ &mut self,
+ at_end: &mut bool,
+ attrs: &mut Vec,
+ ) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
+ // 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 (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
+ let body = self.parse_trait_method_body(at_end, attrs)?;
+ Ok((ident, TraitItemKind::Method(sig, body), generics))
+ }
+
+ /// Parse the "body" of a method in a trait item definition.
+ /// This can either be `;` when there's no body,
+ /// or e.g. a block when the method is a provided one.
+ fn parse_trait_method_body(
+ &mut self,
+ at_end: &mut bool,
+ attrs: &mut Vec,
+ ) -> PResult<'a, Option>> {
+ Ok(match self.token.kind {
+ token::Semi => {
+ debug!("parse_trait_method_body(): parsing required method");
+ self.bump();
+ *at_end = true;
+ None
+ }
+ token::OpenDelim(token::Brace) => {
+ debug!("parse_trait_method_body(): parsing provided method");
+ *at_end = true;
+ let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+ attrs.extend(inner_attrs.iter().cloned());
+ Some(body)
+ }
+ token::Interpolated(ref nt) => {
+ match **nt {
+ token::NtBlock(..) => {
+ *at_end = true;
+ let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+ attrs.extend(inner_attrs.iter().cloned());
+ Some(body)
+ }
+ _ => return self.expected_semi_or_open_brace(),
+ }
+ }
+ _ => return self.expected_semi_or_open_brace(),
+ })
+ }
+
+ /// Parse the "signature", including the identifier, parameters, and generics
+ /// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
+ fn parse_method_sig(
+ &mut self,
+ is_name_required: fn(&token::Token) -> bool,
+ ) -> PResult<'a, (Ident, MethodSig, Generics)> {
+ let header = self.parse_fn_front_matter()?;
+ let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+ is_self_allowed: true,
+ allow_c_variadic: false,
+ is_name_required,
+ })?;
+ Ok((ident, MethodSig { header, decl }, generics))
+ }
+
+ /// Parses all the "front matter" for a `fn` declaration, up to
+ /// and including the `fn` keyword:
+ ///
+ /// - `const fn`
+ /// - `unsafe fn`
+ /// - `const unsafe fn`
+ /// - `extern fn`
+ /// - etc.
+ fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
+ let is_const_fn = self.eat_keyword(kw::Const);
+ let const_span = self.prev_span;
+ let asyncness = self.parse_asyncness();
+ if let IsAsync::Async { .. } = asyncness {
+ self.ban_async_in_2015(self.prev_span);
+ }
+ let asyncness = respan(self.prev_span, asyncness);
+ let unsafety = self.parse_unsafety();
+ let (constness, unsafety, abi) = if is_const_fn {
+ (respan(const_span, Constness::Const), unsafety, Abi::Rust)
+ } else {
+ let abi = self.parse_extern_abi()?;
+ (respan(self.prev_span, Constness::NotConst), unsafety, abi)
+ };
+ if !self.eat_keyword(kw::Fn) {
+ // It is possible for `expect_one_of` to recover given the contents of
+ // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
+ // account for this.
+ if !self.expect_one_of(&[], &[])? { unreachable!() }
+ }
+ Ok(FnHeader { constness, unsafety, asyncness, abi })
+ }
+
+ /// Parse the "signature", including the identifier, parameters, and generics of a function.
+ fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P, Generics)> {
+ let ident = self.parse_ident()?;
+ let mut generics = self.parse_generics()?;
+ let decl = self.parse_fn_decl(cfg, true)?;
+ generics.where_clause = self.parse_where_clause()?;
+ Ok((ident, decl, generics))
+ }
+
+ /// Parses the parameter list and result type of a function declaration.
+ pub(super) fn parse_fn_decl(
+ &mut self,
+ cfg: ParamCfg,
+ ret_allow_plus: bool,
+ ) -> PResult<'a, P> {
+ Ok(P(FnDecl {
+ inputs: self.parse_fn_params(cfg)?,
+ output: self.parse_ret_ty(ret_allow_plus)?,
+ }))
+ }
+
+ /// Parses the parameter list of a function, including the `(` and `)` delimiters.
+ fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec> {
+ let sp = self.token.span;
+ let is_trait_item = cfg.is_self_allowed;
+ let mut c_variadic = false;
+ // Parse the arguments, starting out with `self` being possibly allowed...
+ let (params, _) = self.parse_paren_comma_seq(|p| {
+ let param = p.parse_param_general(&cfg, is_trait_item);
+ // ...now that we've parsed the first argument, `self` is no longer allowed.
+ cfg.is_self_allowed = false;
+
+ match param {
+ Ok(param) => Ok(
+ if let TyKind::CVarArgs = param.ty.kind {
+ c_variadic = true;
+ if p.token != token::CloseDelim(token::Paren) {
+ p.span_err(
+ p.token.span,
+ "`...` must be the last argument of a C-variadic function",
+ );
+ // FIXME(eddyb) this should probably still push `CVarArgs`.
+ // Maybe AST validation/HIR lowering should emit the above error?
+ None
+ } else {
+ Some(param)
+ }
+ } else {
+ Some(param)
+ }
+ ),
+ Err(mut e) => {
+ e.emit();
+ let lo = p.prev_span;
+ // Skip every token until next possible arg or end.
+ p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
+ // Create a placeholder argument for proper arg count (issue #34264).
+ let span = lo.to(p.prev_span);
+ Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
+ }
+ }
+ })?;
+
+ 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 {
+ self.span_err(
+ sp,
+ "C-variadic function must be declared with at least one named argument",
+ );
+ }
+
+ Ok(params)
+ }
+
+ /// Skips unexpected attributes and doc comments in this position and emits an appropriate
+ /// error.
+ /// This version of parse param doesn't necessarily require identifier names.
+ fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: 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 if cfg.is_self_allowed {
+ Ok(param)
+ } else {
+ self.recover_bad_self_param(param, is_trait_item)
+ };
+ }
+
+ 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() {
+ debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
+
+ let pat = self.parse_fn_param_pat()?;
+ if let Err(mut err) = self.expect(&token::Colon) {
+ return if let Some(ident) = self.parameter_without_type(
+ &mut err,
+ pat,
+ is_name_required,
+ cfg.is_self_allowed,
+ is_trait_item,
+ ) {
+ err.emit();
+ Ok(dummy_arg(ident))
+ } else {
+ Err(err)
+ };
+ }
+
+ self.eat_incorrect_doc_comment_for_param_type();
+ (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
+ } else {
+ debug!("parse_param_general ident_to_pat");
+ let parser_snapshot_before_ty = self.clone();
+ self.eat_incorrect_doc_comment_for_param_type();
+ let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
+ if ty.is_ok() && self.token != token::Comma &&
+ self.token != token::CloseDelim(token::Paren) {
+ // This wasn't actually a type, but a pattern looking like a type,
+ // so we are going to rollback and re-parse for recovery.
+ ty = self.unexpected();
+ }
+ match ty {
+ Ok(ty) => {
+ let ident = Ident::new(kw::Invalid, self.prev_span);
+ let bm = BindingMode::ByValue(Mutability::Immutable);
+ let pat = self.mk_pat_ident(ty.span, bm, ident);
+ (pat, ty)
+ }
+ // If this is a C-variadic argument and we hit an error, return the error.
+ Err(err) if self.token == token::DotDotDot => return Err(err),
+ // Recover from attempting to parse the argument as a type without pattern.
+ Err(mut err) => {
+ err.cancel();
+ mem::replace(self, parser_snapshot_before_ty);
+ self.recover_arg_parse()?
+ }
+ }
+ };
+
+ let span = lo.to(self.token.span);
+
+ Ok(Param {
+ attrs: attrs.into(),
+ id: ast::DUMMY_NODE_ID,
+ is_placeholder: false,
+ pat,
+ span,
+ ty,
+ })
+ }
+
+ /// Returns the parsed optional self parameter and whether a self shortcut was used.
+ ///
+ /// See `parse_self_param_with_attrs` to collect attributes.
+ fn parse_self_param(&mut self) -> PResult<'a, Option> {
+ // Extract an identifier *after* having confirmed that the token is one.
+ let expect_self_ident = |this: &mut Self| {
+ match this.token.kind {
+ // Preserve hygienic context.
+ token::Ident(name, _) => {
+ let span = this.token.span;
+ this.bump();
+ Ident::new(name, span)
+ }
+ _ => unreachable!(),
+ }
+ };
+ // Is `self` `n` tokens ahead?
+ let is_isolated_self = |this: &Self, n| {
+ this.is_keyword_ahead(n, &[kw::SelfLower])
+ && this.look_ahead(n + 1, |t| t != &token::ModSep)
+ };
+ // Is `mut self` `n` tokens ahead?
+ let is_isolated_mut_self = |this: &Self, n| {
+ this.is_keyword_ahead(n, &[kw::Mut])
+ && is_isolated_self(this, n + 1)
+ };
+ // Parse `self` or `self: TYPE`. We already know the current token is `self`.
+ let parse_self_possibly_typed = |this: &mut Self, m| {
+ let eself_ident = expect_self_ident(this);
+ let eself_hi = this.prev_span;
+ let eself = if this.eat(&token::Colon) {
+ SelfKind::Explicit(this.parse_ty()?, m)
+ } else {
+ SelfKind::Value(m)
+ };
+ Ok((eself, eself_ident, eself_hi))
+ };
+ // Recover for the grammar `*self`, `*const self`, and `*mut self`.
+ let recover_self_ptr = |this: &mut Self| {
+ let msg = "cannot pass `self` by raw pointer";
+ let span = this.token.span;
+ this.struct_span_err(span, msg)
+ .span_label(span, msg)
+ .emit();
+
+ Ok((SelfKind::Value(Mutability::Immutable), expect_self_ident(this), this.prev_span))
+ };
+
+ // Parse optional `self` parameter of a method.
+ // Only a limited set of initial token sequences is considered `self` parameters; anything
+ // else is parsed as a normal function parameter list, so some lookahead is required.
+ let eself_lo = self.token.span;
+ let (eself, eself_ident, eself_hi) = match self.token.kind {
+ token::BinOp(token::And) => {
+ let eself = if is_isolated_self(self, 1) {
+ // `&self`
+ self.bump();
+ SelfKind::Region(None, Mutability::Immutable)
+ } else if is_isolated_mut_self(self, 1) {
+ // `&mut self`
+ self.bump();
+ self.bump();
+ SelfKind::Region(None, Mutability::Mutable)
+ } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) {
+ // `&'lt self`
+ self.bump();
+ let lt = self.expect_lifetime();
+ SelfKind::Region(Some(lt), Mutability::Immutable)
+ } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) {
+ // `&'lt mut self`
+ self.bump();
+ let lt = self.expect_lifetime();
+ self.bump();
+ SelfKind::Region(Some(lt), Mutability::Mutable)
+ } else {
+ // `¬_self`
+ return Ok(None);
+ };
+ (eself, expect_self_ident(self), self.prev_span)
+ }
+ // `*self`
+ token::BinOp(token::Star) if is_isolated_self(self, 1) => {
+ self.bump();
+ recover_self_ptr(self)?
+ }
+ // `*mut self` and `*const self`
+ token::BinOp(token::Star) if
+ self.look_ahead(1, |t| t.is_mutability())
+ && is_isolated_self(self, 2) =>
+ {
+ self.bump();
+ self.bump();
+ recover_self_ptr(self)?
+ }
+ // `self` and `self: TYPE`
+ token::Ident(..) if is_isolated_self(self, 0) => {
+ parse_self_possibly_typed(self, Mutability::Immutable)?
+ }
+ // `mut self` and `mut self: TYPE`
+ token::Ident(..) if is_isolated_mut_self(self, 0) => {
+ self.bump();
+ parse_self_possibly_typed(self, Mutability::Mutable)?
+ }
+ _ => return Ok(None),
+ };
+
+ let eself = source_map::respan(eself_lo.to(eself_hi), eself);
+ Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
+ }
+
+ fn is_named_param(&self) -> bool {
+ let offset = match self.token.kind {
+ token::Interpolated(ref nt) => match **nt {
+ token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
+ _ => 0,
+ }
+ token::BinOp(token::And) | token::AndAnd => 1,
+ _ if self.token.is_keyword(kw::Mut) => 1,
+ _ => 0,
+ };
+
+ self.look_ahead(offset, |t| t.is_ident()) &&
+ self.look_ahead(offset + 1, |t| t == &token::Colon)
+ }
+
+ 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",
+ }
+ }
+}
diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs
index 018b5951e6e2e..e696ab0804d69 100644
--- a/src/libsyntax/parse/parser/ty.rs
+++ b/src/libsyntax/parse/parser/ty.rs
@@ -1,4 +1,5 @@
use super::{Parser, PResult, PathStyle, PrevTokenKind, TokenType};
+use super::item::ParamCfg;
use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
use crate::ptr::P;
@@ -281,7 +282,7 @@ impl<'a> Parser<'a> {
let unsafety = self.parse_unsafety();
let abi = self.parse_extern_abi()?;
self.expect_keyword(kw::Fn)?;
- let cfg = super::ParamCfg {
+ let cfg = ParamCfg {
is_self_allowed: false,
allow_c_variadic: true,
is_name_required: |_| false,