Rollup merge of #65362 - Centril:extract_fun, r=petrochenkov
syntax: consolidate function parsing in item.rs Extracted from https://github.com/rust-lang/rust/pull/65324. r? @estebank
This commit is contained in:
commit
66e428824b
3 changed files with 491 additions and 487 deletions
|
@ -9,20 +9,19 @@ mod path;
|
||||||
pub use path::PathStyle;
|
pub use path::PathStyle;
|
||||||
mod stmt;
|
mod stmt;
|
||||||
mod generics;
|
mod generics;
|
||||||
|
use super::diagnostics::Error;
|
||||||
|
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident,
|
self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
|
||||||
IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility,
|
IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety,
|
||||||
VisibilityKind, Unsafety,
|
|
||||||
};
|
};
|
||||||
use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token};
|
use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token};
|
||||||
use crate::parse::diagnostics::{Error, dummy_arg};
|
|
||||||
use crate::parse::lexer::UnmatchedBrace;
|
use crate::parse::lexer::UnmatchedBrace;
|
||||||
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
|
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
|
||||||
use crate::parse::token::{Token, TokenKind, DelimToken};
|
use crate::parse::token::{Token, TokenKind, DelimToken};
|
||||||
use crate::print::pprust;
|
use crate::print::pprust;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::source_map::{self, respan};
|
use crate::source_map::respan;
|
||||||
use crate::symbol::{kw, sym, Symbol};
|
use crate::symbol::{kw, sym, Symbol};
|
||||||
use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
|
use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
|
||||||
use crate::ThinVec;
|
use crate::ThinVec;
|
||||||
|
@ -56,17 +55,6 @@ 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 {
|
||||||
|
@ -1105,271 +1093,6 @@ impl<'a> Parser<'a> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
|
|
||||||
fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
|
|
||||||
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<Param>> {
|
|
||||||
// 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 is_crate_vis(&self) -> bool {
|
fn is_crate_vis(&self) -> bool {
|
||||||
self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
|
self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,23 @@
|
||||||
use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode, ParamCfg};
|
use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode};
|
||||||
|
|
||||||
use crate::maybe_whole;
|
use crate::maybe_whole;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::ast::{
|
use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, AnonConst, Item, ItemKind};
|
||||||
self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle,
|
use crate::ast::{ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
|
||||||
Item, ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind,
|
use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness};
|
||||||
UseTree, UseTreeKind, PathSegment,
|
use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
|
||||||
IsAuto, Constness, IsAsync, Unsafety, Defaultness,
|
use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField};
|
||||||
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block,
|
use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, MethodSig, SelfKind, Param};
|
||||||
ForeignItem, ForeignItemKind,
|
|
||||||
Ty, TyKind, Generics, GenericBounds, TraitRef,
|
|
||||||
EnumDef, VariantData, StructField, AnonConst,
|
|
||||||
Mac, MacDelimiter,
|
|
||||||
};
|
|
||||||
use crate::ext::base::DummyResult;
|
use crate::ext::base::DummyResult;
|
||||||
use crate::parse::token;
|
use crate::parse::token;
|
||||||
use crate::parse::parser::maybe_append;
|
use crate::parse::parser::maybe_append;
|
||||||
use crate::parse::diagnostics::Error;
|
use crate::parse::diagnostics::{Error, dummy_arg};
|
||||||
use crate::tokenstream::{TokenTree, TokenStream};
|
use crate::tokenstream::{TokenTree, TokenStream};
|
||||||
use crate::source_map::{respan, Span};
|
|
||||||
use crate::symbol::{kw, sym};
|
use crate::symbol::{kw, sym};
|
||||||
|
use crate::source_map::{self, respan, Span};
|
||||||
|
use crate::ThinVec;
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
use std::mem;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey};
|
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey};
|
||||||
|
|
||||||
|
@ -412,7 +407,7 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis)
|
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_item_with_info(
|
pub(super) fn mk_item_with_info(
|
||||||
&self,
|
&self,
|
||||||
attrs: Vec<Attribute>,
|
attrs: Vec<Attribute>,
|
||||||
lo: Span,
|
lo: Span,
|
||||||
|
@ -425,16 +420,6 @@ impl<'a> Parser<'a> {
|
||||||
Ok(Some(self.mk_item(span, ident, item, vis, attrs)))
|
Ok(Some(self.mk_item(span, ident, item, vis, attrs)))
|
||||||
}
|
}
|
||||||
|
|
||||||
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",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is the fall-through for parsing items.
|
/// This is the fall-through for parsing items.
|
||||||
fn parse_macro_use_or_failure(
|
fn parse_macro_use_or_failure(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -707,9 +692,11 @@ impl<'a> Parser<'a> {
|
||||||
Ok(item)
|
Ok(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_impl_item_(&mut self,
|
fn parse_impl_item_(
|
||||||
at_end: &mut bool,
|
&mut self,
|
||||||
mut attrs: Vec<Attribute>) -> PResult<'a, ImplItem> {
|
at_end: &mut bool,
|
||||||
|
mut attrs: Vec<Attribute>,
|
||||||
|
) -> PResult<'a, ImplItem> {
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
let vis = self.parse_visibility(false)?;
|
let vis = self.parse_visibility(false)?;
|
||||||
let defaultness = self.parse_defaultness();
|
let defaultness = self.parse_defaultness();
|
||||||
|
@ -722,8 +709,11 @@ impl<'a> Parser<'a> {
|
||||||
(name, kind, generics)
|
(name, kind, generics)
|
||||||
} else if self.is_const_item() {
|
} else if self.is_const_item() {
|
||||||
self.parse_impl_const()?
|
self.parse_impl_const()?
|
||||||
|
} else if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(&vis), at_end)? {
|
||||||
|
// FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
|
||||||
|
(Ident::invalid(), ast::ImplItemKind::Macro(mac), Generics::default())
|
||||||
} else {
|
} else {
|
||||||
let (name, inner_attrs, generics, kind) = self.parse_impl_method(&vis, at_end)?;
|
let (name, inner_attrs, generics, kind) = self.parse_impl_method(at_end)?;
|
||||||
attrs.extend(inner_attrs);
|
attrs.extend(inner_attrs);
|
||||||
(name, kind, generics)
|
(name, kind, generics)
|
||||||
};
|
};
|
||||||
|
@ -783,71 +773,6 @@ impl<'a> Parser<'a> {
|
||||||
Ok((name, ImplItemKind::Const(typ, expr), Generics::default()))
|
Ok((name, ImplItemKind::Const(typ, expr), Generics::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a method or a macro invocation in a trait impl.
|
|
||||||
fn parse_impl_method(
|
|
||||||
&mut self,
|
|
||||||
vis: &Visibility,
|
|
||||||
at_end: &mut bool
|
|
||||||
) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ImplItemKind)> {
|
|
||||||
// FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
|
|
||||||
if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
|
|
||||||
// method macro
|
|
||||||
Ok((Ident::invalid(), vec![], Generics::default(), ast::ImplItemKind::Macro(mac)))
|
|
||||||
} else {
|
|
||||||
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)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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 })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
|
/// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
|
||||||
fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
|
fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
|
||||||
// Parse optional `auto` prefix.
|
// Parse optional `auto` prefix.
|
||||||
|
@ -957,13 +882,7 @@ impl<'a> Parser<'a> {
|
||||||
// trait item macro.
|
// trait item macro.
|
||||||
(Ident::invalid(), TraitItemKind::Macro(mac), Generics::default())
|
(Ident::invalid(), TraitItemKind::Macro(mac), Generics::default())
|
||||||
} else {
|
} else {
|
||||||
// This is somewhat dubious; We don't want to allow
|
self.parse_trait_item_method(at_end, &mut attrs)?
|
||||||
// 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, &mut attrs)?;
|
|
||||||
(ident, TraitItemKind::Method(sig, body), generics)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(TraitItem {
|
Ok(TraitItem {
|
||||||
|
@ -991,43 +910,6 @@ impl<'a> Parser<'a> {
|
||||||
Ok((ident, TraitItemKind::Const(ty, default), Generics::default()))
|
Ok((ident, TraitItemKind::Const(ty, default), Generics::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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<Attribute>,
|
|
||||||
) -> PResult<'a, Option<P<Block>>> {
|
|
||||||
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:
|
/// Parses the following grammar:
|
||||||
///
|
///
|
||||||
/// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
|
/// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
|
||||||
|
@ -1194,45 +1076,6 @@ impl<'a> Parser<'a> {
|
||||||
Ok(ident)
|
Ok(ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses an item-position function declaration.
|
|
||||||
fn parse_item_fn(
|
|
||||||
&mut self,
|
|
||||||
lo: Span,
|
|
||||||
vis: Visibility,
|
|
||||||
attrs: Vec<Attribute>,
|
|
||||||
header: FnHeader,
|
|
||||||
) -> PResult<'a, Option<P<Item>>> {
|
|
||||||
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<FnDecl>, 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<FnDecl>> {
|
|
||||||
Ok(P(FnDecl {
|
|
||||||
inputs: self.parse_fn_params(cfg)?,
|
|
||||||
output: self.parse_ret_ty(ret_allow_plus)?,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses `extern` for foreign ABIs modules.
|
/// Parses `extern` for foreign ABIs modules.
|
||||||
///
|
///
|
||||||
/// `extern` is expected to have been
|
/// `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<Attribute>,
|
|
||||||
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.
|
/// Parses a static item from a foreign module.
|
||||||
/// Assumes that the `static` keyword is already parsed.
|
/// Assumes that the `static` keyword is already parsed.
|
||||||
fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
|
fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
|
||||||
|
@ -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<Attribute>,
|
||||||
|
header: FnHeader,
|
||||||
|
) -> PResult<'a, Option<P<Item>>> {
|
||||||
|
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<Attribute>,
|
||||||
|
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<Attribute>, 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<Attribute>,
|
||||||
|
) -> 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<Attribute>,
|
||||||
|
) -> PResult<'a, Option<P<Block>>> {
|
||||||
|
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<FnDecl>, 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<FnDecl>> {
|
||||||
|
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<Param>> {
|
||||||
|
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<Param>> {
|
||||||
|
// 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",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{Parser, PResult, PathStyle, PrevTokenKind, TokenType};
|
use super::{Parser, PResult, PathStyle, PrevTokenKind, TokenType};
|
||||||
|
use super::item::ParamCfg;
|
||||||
|
|
||||||
use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
|
use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
|
@ -281,7 +282,7 @@ impl<'a> Parser<'a> {
|
||||||
let unsafety = self.parse_unsafety();
|
let unsafety = self.parse_unsafety();
|
||||||
let abi = self.parse_extern_abi()?;
|
let abi = self.parse_extern_abi()?;
|
||||||
self.expect_keyword(kw::Fn)?;
|
self.expect_keyword(kw::Fn)?;
|
||||||
let cfg = super::ParamCfg {
|
let cfg = ParamCfg {
|
||||||
is_self_allowed: false,
|
is_self_allowed: false,
|
||||||
allow_c_variadic: true,
|
allow_c_variadic: true,
|
||||||
is_name_required: |_| false,
|
is_name_required: |_| false,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue