use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
use super::ty::{AllowPlus, RecoverQPath};
use super::{FollowedByType, Parser, PathStyle};
use crate::maybe_whole;
use rustc_ast::ast::{self, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind};
use rustc_ast::ast::{
Async, Const, Defaultness, IsAuto, PathSegment, Unsafe, UseTree, UseTreeKind,
};
use rustc_ast::ast::{
BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind,
};
use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
use rustc_ast::ast::{FnHeader, ForeignItem, Mutability, Visibility, VisibilityKind};
use rustc_ast::ptr::P;
use rustc_ast::token;
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
use rustc_span::edition::Edition;
use rustc_span::source_map::{self, Span};
use rustc_span::symbol::{kw, sym, Symbol};
use log::debug;
use std::convert::TryFrom;
use std::mem;
pub(super) type ItemInfo = (Ident, ItemKind);
impl<'a> Parser<'a> {
pub fn parse_item(&mut self) -> PResult<'a, Option
>> {
self.parse_item_(|_| true).map(|i| i.map(P))
}
fn parse_item_(&mut self, req_name: ReqName) -> PResult<'a, Option> {
let attrs = self.parse_outer_attributes()?;
self.parse_item_common(attrs, true, false, req_name)
}
pub(super) fn parse_item_common(
&mut self,
mut attrs: Vec,
mac_allowed: bool,
attrs_allowed: bool,
req_name: ReqName,
) -> PResult<'a, Option> {
maybe_whole!(self, NtItem, |item| {
let mut item = item;
mem::swap(&mut item.attrs, &mut attrs);
item.attrs.extend(attrs);
Some(item.into_inner())
});
let mut unclosed_delims = vec![];
let (mut item, tokens) = self.collect_tokens(|this| {
let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
unclosed_delims.append(&mut this.unclosed_delims);
item
})?;
self.unclosed_delims.append(&mut unclosed_delims);
// Once we've parsed an item and recorded the tokens we got while
// parsing we may want to store `tokens` into the item we're about to
// return. Note, though, that we specifically didn't capture tokens
// related to outer attributes. The `tokens` field here may later be
// used with procedural macros to convert this item back into a token
// stream, but during expansion we may be removing attributes as we go
// along.
//
// If we've got inner attributes then the `tokens` we've got above holds
// these inner attributes. If an inner attribute is expanded we won't
// actually remove it from the token stream, so we'll just keep yielding
// it (bad!). To work around this case for now we just avoid recording
// `tokens` if we detect any inner attributes. This should help keep
// expansion correct, but we should fix this bug one day!
if let Some(item) = &mut item {
if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
item.tokens = Some(tokens);
}
}
Ok(item)
}
fn parse_item_common_(
&mut self,
mut attrs: Vec,
mac_allowed: bool,
attrs_allowed: bool,
req_name: ReqName,
) -> PResult<'a, Option> {
let lo = self.token.span;
let vis = self.parse_visibility(FollowedByType::No)?;
let mut def = self.parse_defaultness();
let kind = self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, req_name)?;
if let Some((ident, kind)) = kind {
self.error_on_unconsumed_default(def, &kind);
let span = lo.to(self.prev_token.span);
let id = DUMMY_NODE_ID;
let item = Item { ident, attrs, id, kind, vis, span, tokens: None };
return Ok(Some(item));
}
// At this point, we have failed to parse an item.
self.error_on_unmatched_vis(&vis);
self.error_on_unmatched_defaultness(def);
if !attrs_allowed {
self.recover_attrs_no_item(&attrs)?;
}
Ok(None)
}
/// Error in-case a non-inherited visibility was parsed but no item followed.
fn error_on_unmatched_vis(&self, vis: &Visibility) {
if let VisibilityKind::Inherited = vis.node {
return;
}
let vs = pprust::vis_to_string(&vis);
let vs = vs.trim_end();
self.struct_span_err(vis.span, &format!("visibility `{}` is not followed by an item", vs))
.span_label(vis.span, "the visibility")
.help(&format!("you likely meant to define an item, e.g., `{} fn foo() {{}}`", vs))
.emit();
}
/// Error in-case a `default` was parsed but no item followed.
fn error_on_unmatched_defaultness(&self, def: Defaultness) {
if let Defaultness::Default(sp) = def {
self.struct_span_err(sp, "`default` is not followed by an item")
.span_label(sp, "the `default` qualifier")
.note("only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`")
.emit();
}
}
/// Error in-case `default` was parsed in an in-appropriate context.
fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
if let Defaultness::Default(span) = def {
let msg = format!("{} {} cannot be `default`", kind.article(), kind.descr());
self.struct_span_err(span, &msg)
.span_label(span, "`default` because of this")
.note("only associated `fn`, `const`, and `type` items can be `default`")
.emit();
}
}
/// Parses one of the items allowed by the flags.
fn parse_item_kind(
&mut self,
attrs: &mut Vec,
macros_allowed: bool,
lo: Span,
vis: &Visibility,
def: &mut Defaultness,
req_name: ReqName,
) -> PResult<'a, Option> {
let mut def = || mem::replace(def, Defaultness::Final);
let info = if self.eat_keyword(kw::Use) {
// USE ITEM
let tree = self.parse_use_tree()?;
self.expect_semi()?;
(Ident::invalid(), ItemKind::Use(P(tree)))
} else if self.check_fn_front_matter() {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name)?;
(ident, ItemKind::Fn(def(), sig, generics, body))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
// EXTERN CRATE
self.parse_item_extern_crate()?
} else {
// EXTERN BLOCK
self.parse_item_foreign_mod(attrs)?
}
} else if self.is_static_global() {
// STATIC ITEM
self.bump(); // `static`
let m = self.parse_mutability();
let (ident, ty, expr) = self.parse_item_global(Some(m))?;
(ident, ItemKind::Static(ty, m, expr))
} else if let Const::Yes(const_span) = self.parse_constness() {
// CONST ITEM
self.recover_const_mut(const_span);
let (ident, ty, expr) = self.parse_item_global(None)?;
(ident, ItemKind::Const(def(), ty, expr))
} else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() {
// TRAIT ITEM
self.parse_item_trait(attrs, lo)?
} else if self.check_keyword(kw::Impl)
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl])
{
// IMPL ITEM
self.parse_item_impl(attrs, def())?
} else if self.eat_keyword(kw::Mod) {
// MODULE ITEM
self.parse_item_mod(attrs)?
} else if self.eat_keyword(kw::Type) {
// TYPE ITEM
self.parse_type_alias(def())?
} else if self.eat_keyword(kw::Enum) {
// ENUM ITEM
self.parse_item_enum()?
} else if self.eat_keyword(kw::Struct) {
// STRUCT ITEM
self.parse_item_struct()?
} else if self.is_kw_followed_by_ident(kw::Union) {
// UNION ITEM
self.bump(); // `union`
self.parse_item_union()?
} else if self.eat_keyword(kw::Macro) {
// MACROS 2.0 ITEM
self.parse_item_decl_macro(lo)?
} else if self.is_macro_rules_item() {
// MACRO_RULES ITEM
self.parse_item_macro_rules(vis)?
} else if vis.node.is_pub() && self.isnt_macro_invocation() {
self.recover_missing_kw_before_item()?;
return Ok(None);
} else if macros_allowed && self.token.is_path_start() {
// MACRO INVOCATION ITEM
(Ident::invalid(), ItemKind::Mac(self.parse_item_macro(vis)?))
} else {
return Ok(None);
};
Ok(Some(info))
}
/// When parsing a statement, would the start of a path be an item?
pub(super) fn is_path_start_item(&mut self) -> bool {
self.is_crate_vis() // no: `crate::b`, yes: `crate $item`
|| self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|| self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
|| self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
|| self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac`
}
/// Are we sure this could not possibly be a macro invocation?
fn isnt_macro_invocation(&mut self) -> bool {
self.check_ident() && self.look_ahead(1, |t| *t != token::Not && *t != token::ModSep)
}
/// Recover on encountering a struct or method definition where the user
/// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`.
fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
// Space between `pub` keyword and the identifier
//
// pub S {}
// ^^^ `sp` points here
let sp = self.prev_token.span.between(self.token.span);
let full_sp = self.prev_token.span.to(self.token.span);
let ident_sp = self.token.span;
if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
// possible public struct definition where `struct` was forgotten
let ident = self.parse_ident().unwrap();
let msg = format!("add `struct` here to parse `{}` as a public struct", ident);
let mut err = self.struct_span_err(sp, "missing `struct` for struct definition");
err.span_suggestion_short(
sp,
&msg,
" struct ".into(),
Applicability::MaybeIncorrect, // speculative
);
return Err(err);
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
let ident = self.parse_ident().unwrap();
self.bump(); // `(`
let kw_name = self.recover_first_param();
self.consume_block(token::Paren, ConsumeClosingDelim::Yes);
let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
self.bump(); // `{`
("fn", kw_name, false)
} else if self.check(&token::OpenDelim(token::Brace)) {
self.bump(); // `{`
("fn", kw_name, false)
} else if self.check(&token::Colon) {
let kw = "struct";
(kw, kw, false)
} else {
("fn` or `struct", "function or struct", true)
};
let msg = format!("missing `{}` for {} definition", kw, kw_name);
let mut err = self.struct_span_err(sp, &msg);
if !ambiguous {
self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
let suggestion =
format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name);
err.span_suggestion_short(
sp,
&suggestion,
format!(" {} ", kw),
Applicability::MachineApplicable,
);
} else {
if let Ok(snippet) = self.span_to_snippet(ident_sp) {
err.span_suggestion(
full_sp,
"if you meant to call a macro, try",
format!("{}!", snippet),
// this is the `ambiguous` conditional branch
Applicability::MaybeIncorrect,
);
} else {
err.help(
"if you meant to call a macro, remove the `pub` \
and add a trailing `!` after the identifier",
);
}
}
return Err(err);
} else if self.look_ahead(1, |t| *t == token::Lt) {
let ident = self.parse_ident().unwrap();
self.eat_to_tokens(&[&token::Gt]);
self.bump(); // `>`
let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
("fn", self.recover_first_param(), false)
} else if self.check(&token::OpenDelim(token::Brace)) {
("struct", "struct", false)
} else {
("fn` or `struct", "function or struct", true)
};
let msg = format!("missing `{}` for {} definition", kw, kw_name);
let mut err = self.struct_span_err(sp, &msg);
if !ambiguous {
err.span_suggestion_short(
sp,
&format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name),
format!(" {} ", kw),
Applicability::MachineApplicable,
);
}
return Err(err);
} else {
Ok(())
}
}
/// Parses an item macro, e.g., `item!();`.
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, Mac> {
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
self.expect(&token::Not)?; // `!`
let args = self.parse_mac_args()?; // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
self.eat_semi_for_macro_if_needed(&args);
self.complain_if_pub_macro(vis, false);
Ok(Mac { path, args, prior_type_ascription: self.last_type_ascription })
}
/// Recover if we parsed attributes and expected an item but there was none.
fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
let (start, end) = match attrs {
[] => return Ok(()),
[x0] => (x0, x0),
[x0, .., xn] => (x0, xn),
};
let msg = if end.is_doc_comment() {
"expected item after doc comment"
} else {
"expected item after attributes"
};
let mut err = self.struct_span_err(end.span, msg);
if end.is_doc_comment() {
err.span_label(end.span, "this doc comment doesn't document anything");
}
if let [.., penultimate, _] = attrs {
err.span_label(start.span.to(penultimate.span), "other attributes here");
}
Err(err)
}
fn is_async_fn(&self) -> bool {
self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn])
}
/// Parses an implementation item.
///
/// ```
/// impl<'a, T> TYPE { /* impl items */ }
/// impl<'a, T> TRAIT for TYPE { /* impl items */ }
/// impl<'a, T> !TRAIT for TYPE { /* impl items */ }
/// impl<'a, T> const TRAIT for TYPE { /* impl items */ }
/// ```
///
/// We actually parse slightly more relaxed grammar for better error reporting and recovery.
/// ```
/// "impl" GENERICS "const"? "!"? TYPE "for"? (TYPE | "..") ("where" PREDICATES)? "{" BODY "}"
/// "impl" GENERICS "const"? "!"? TYPE ("where" PREDICATES)? "{" BODY "}"
/// ```
fn parse_item_impl(
&mut self,
attrs: &mut Vec,
defaultness: Defaultness,
) -> PResult<'a, ItemInfo> {
let unsafety = self.parse_unsafety();
self.expect_keyword(kw::Impl)?;
// First, parse generic parameters if necessary.
let mut generics = if self.choose_generics_over_qpath() {
self.parse_generics()?
} else {
let mut generics = Generics::default();
// impl A for B {}
// /\ this is where `generics.span` should point when there are no type params.
generics.span = self.prev_token.span.shrink_to_hi();
generics
};
let constness = self.parse_constness();
if let Const::Yes(span) = constness {
self.sess.gated_spans.gate(sym::const_trait_impl, span);
}
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) {
self.bump(); // `!`
ast::ImplPolarity::Negative
} else {
ast::ImplPolarity::Positive
};
// Parse both types and traits as a type, then reinterpret if necessary.
let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span));
let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
{
let span = self.prev_token.span.between(self.token.span);
self.struct_span_err(span, "missing trait in a trait impl").emit();
P(Ty { kind: TyKind::Path(None, err_path(span)), span, id: DUMMY_NODE_ID })
} else {
self.parse_ty()?
};
// If `for` is missing we try to recover.
let has_for = self.eat_keyword(kw::For);
let missing_for_span = self.prev_token.span.between(self.token.span);
let ty_second = if self.token == token::DotDot {
// We need to report this error after `cfg` expansion for compatibility reasons
self.bump(); // `..`, do not add it to expected tokens
Some(self.mk_ty(self.prev_token.span, TyKind::Err))
} else if has_for || self.token.can_begin_type() {
Some(self.parse_ty()?)
} else {
None
};
generics.where_clause = self.parse_where_clause()?;
let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item())?;
let item_kind = match ty_second {
Some(ty_second) => {
// impl Trait for Type
if !has_for {
self.struct_span_err(missing_for_span, "missing `for` in a trait impl")
.span_suggestion_short(
missing_for_span,
"add `for` here",
" for ".to_string(),
Applicability::MachineApplicable,
)
.emit();
}
let ty_first = ty_first.into_inner();
let path = match ty_first.kind {
// This notably includes paths passed through `ty` macro fragments (#46438).
TyKind::Path(None, path) => path,
_ => {
self.struct_span_err(ty_first.span, "expected a trait, found type").emit();
err_path(ty_first.span)
}
};
let trait_ref = TraitRef { path, ref_id: ty_first.id };
ItemKind::Impl {
unsafety,
polarity,
defaultness,
constness,
generics,
of_trait: Some(trait_ref),
self_ty: ty_second,
items: impl_items,
}
}
None => {
// impl Type
ItemKind::Impl {
unsafety,
polarity,
defaultness,
constness,
generics,
of_trait: None,
self_ty: ty_first,
items: impl_items,
}
}
};
Ok((Ident::invalid(), item_kind))
}
fn parse_item_list(
&mut self,
attrs: &mut Vec,
mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option