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
@ -9,20 +9,19 @@ mod path;
|
||||
pub use path::PathStyle;
|
||||
mod stmt;
|
||||
mod generics;
|
||||
use super::diagnostics::Error;
|
||||
|
||||
use crate::ast::{
|
||||
self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident,
|
||||
IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility,
|
||||
VisibilityKind, Unsafety,
|
||||
self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
|
||||
IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety,
|
||||
};
|
||||
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::comments::{doc_comment_style, strip_doc_comment_decoration};
|
||||
use crate::parse::token::{Token, TokenKind, DelimToken};
|
||||
use crate::print::pprust;
|
||||
use crate::ptr::P;
|
||||
use crate::source_map::{self, respan};
|
||||
use crate::source_map::respan;
|
||||
use crate::symbol::{kw, sym, Symbol};
|
||||
use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
|
||||
use crate::ThinVec;
|
||||
@ -56,17 +55,6 @@ crate enum BlockMode {
|
||||
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.
|
||||
#[macro_export]
|
||||
macro_rules! maybe_whole {
|
||||
@ -1105,271 +1093,6 @@ impl<'a> Parser<'a> {
|
||||
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 {
|
||||
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::ptr::P;
|
||||
use crate::ast::{
|
||||
self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle,
|
||||
Item, ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind,
|
||||
UseTree, UseTreeKind, PathSegment,
|
||||
IsAuto, Constness, IsAsync, Unsafety, Defaultness,
|
||||
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block,
|
||||
ForeignItem, ForeignItemKind,
|
||||
Ty, TyKind, Generics, GenericBounds, TraitRef,
|
||||
EnumDef, VariantData, StructField, AnonConst,
|
||||
Mac, MacDelimiter,
|
||||
};
|
||||
use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, AnonConst, Item, ItemKind};
|
||||
use crate::ast::{ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
|
||||
use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness};
|
||||
use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
|
||||
use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField};
|
||||
use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, MethodSig, SelfKind, Param};
|
||||
use crate::ext::base::DummyResult;
|
||||
use crate::parse::token;
|
||||
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::source_map::{respan, Span};
|
||||
use crate::symbol::{kw, sym};
|
||||
use crate::source_map::{self, respan, Span};
|
||||
use crate::ThinVec;
|
||||
|
||||
use std::mem;
|
||||
use log::debug;
|
||||
use std::mem;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
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)
|
||||
}
|
||||
|
||||
fn mk_item_with_info(
|
||||
pub(super) fn mk_item_with_info(
|
||||
&self,
|
||||
attrs: Vec<Attribute>,
|
||||
lo: Span,
|
||||
@ -425,16 +420,6 @@ impl<'a> Parser<'a> {
|
||||
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.
|
||||
fn parse_macro_use_or_failure(
|
||||
&mut self,
|
||||
@ -707,9 +692,11 @@ impl<'a> Parser<'a> {
|
||||
Ok(item)
|
||||
}
|
||||
|
||||
fn parse_impl_item_(&mut self,
|
||||
at_end: &mut bool,
|
||||
mut attrs: Vec<Attribute>) -> PResult<'a, ImplItem> {
|
||||
fn parse_impl_item_(
|
||||
&mut self,
|
||||
at_end: &mut bool,
|
||||
mut attrs: Vec<Attribute>,
|
||||
) -> PResult<'a, ImplItem> {
|
||||
let lo = self.token.span;
|
||||
let vis = self.parse_visibility(false)?;
|
||||
let defaultness = self.parse_defaultness();
|
||||
@ -722,8 +709,11 @@ impl<'a> Parser<'a> {
|
||||
(name, kind, generics)
|
||||
} else if self.is_const_item() {
|
||||
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 {
|
||||
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);
|
||||
(name, kind, generics)
|
||||
};
|
||||
@ -783,71 +773,6 @@ impl<'a> Parser<'a> {
|
||||
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;`.
|
||||
fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
|
||||
// Parse optional `auto` prefix.
|
||||
@ -957,13 +882,7 @@ impl<'a> Parser<'a> {
|
||||
// trait item macro.
|
||||
(Ident::invalid(), TraitItemKind::Macro(mac), Generics::default())
|
||||
} else {
|
||||
// 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, &mut attrs)?;
|
||||
(ident, TraitItemKind::Method(sig, body), generics)
|
||||
self.parse_trait_item_method(at_end, &mut attrs)?
|
||||
};
|
||||
|
||||
Ok(TraitItem {
|
||||
@ -991,43 +910,6 @@ impl<'a> Parser<'a> {
|
||||
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:
|
||||
///
|
||||
/// 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<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.
|
||||
///
|
||||
/// `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.
|
||||
/// Assumes that the `static` keyword is already parsed.
|
||||
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::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,
|
||||
|
Loading…
Reference in New Issue
Block a user