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 syntax::ast::{self, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
-use syntax::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind};
-use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, Unsafe, UseTree, UseTreeKind};
-use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind};
-use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
-use syntax::ast::{FnHeader, ForeignItem, Mutability, Visibility, VisibilityKind};
-use syntax::ptr::P;
-use syntax::token;
-use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
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<P<Item>>> {
+ self.parse_item_(|_| true).map(|i| i.map(P))
+ }
+
+ fn parse_item_(&mut self, req_name: ReqName) -> PResult<'a, Option<Item>> {
let attrs = self.parse_outer_attributes()?;
- self.parse_item_(attrs, true, false)
+ self.parse_item_common(attrs, true, false, req_name)
}
- pub(super) fn parse_item_(
+ pub(super) fn parse_item_common(
&mut self,
mut attrs: Vec<Attribute>,
- macros_allowed: bool,
- attributes_allowed: bool,
- ) -> PResult<'a, Option<P<Item>>> {
+ mac_allowed: bool,
+ attrs_allowed: bool,
+ req_name: ReqName,
+ ) -> PResult<'a, Option<Item>> {
maybe_whole!(self, NtItem, |item| {
let mut item = item;
mem::swap(&mut item.attrs, &mut attrs);
item.attrs.extend(attrs);
- Some(item)
+ Some(item.into_inner())
});
- let item = self.parse_item_common(attrs, macros_allowed, attributes_allowed, |_| true)?;
- if let Some(ref item) = item {
- self.error_on_illegal_default(item.defaultness);
- }
- Ok(item.map(P))
- }
- fn parse_item_common(
- &mut self,
- attrs: Vec<Attribute>,
- mac_allowed: bool,
- attrs_allowed: bool,
- req_name: ReqName,
- ) -> PResult<'a, Option<Item>> {
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);
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_span);
let id = DUMMY_NODE_ID;
- let item = Item { ident, attrs, id, kind, vis, defaultness: def, span, tokens: None };
+ let item = Item { ident, attrs, id, kind, vis, span, tokens: None };
return Ok(Some(item));
}
}
let vs = pprust::vis_to_string(&vis);
let vs = vs.trim_end();
- self.struct_span_err(vis.span, &format!("visibility `{}` not followed by an item", vs))
+ 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` not followed by an item")
+ 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_illegal_default(&self, def: Defaultness) {
+ fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
if let Defaultness::Default(span) = def {
- self.struct_span_err(span, "item cannot be `default`")
+ 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();
def: &mut Defaultness,
req_name: ReqName,
) -> PResult<'a, Option<ItemInfo>> {
+ let mut def = || mem::replace(def, Defaultness::Final);
+
let info = if self.eat_keyword(kw::Use) {
// USE ITEM
let tree = self.parse_use_tree()?;
} else if self.check_fn_front_matter() {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name)?;
- (ident, ItemKind::Fn(sig, generics, body))
+ (ident, ItemKind::Fn(def(), sig, generics, body))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
// EXTERN CRATE
// STATIC ITEM
self.bump(); // `static`
let m = self.parse_mutability();
- self.parse_item_const(Some(m))?
+ 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);
- self.parse_item_const(None)?
+ 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)?
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl])
{
// IMPL ITEM
- self.parse_item_impl(attrs, mem::replace(def, Defaultness::Final))?
+ 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()?
+ self.parse_type_alias(def())?
} else if self.eat_keyword(kw::Enum) {
// ENUM ITEM
self.parse_item_enum()?
}
pub fn parse_impl_item(&mut self) -> PResult<'a, Option<Option<P<AssocItem>>>> {
- maybe_whole!(self, NtImplItem, |x| Some(Some(x)));
self.parse_assoc_item(|_| true)
}
pub fn parse_trait_item(&mut self) -> PResult<'a, Option<Option<P<AssocItem>>>> {
- maybe_whole!(self, NtTraitItem, |x| Some(Some(x)));
- // This is somewhat dubious; We don't want to allow
- // param names to be left off if there is a definition...
- //
- // We don't allow param names to be left off in edition 2018.
- self.parse_assoc_item(|t| t.span.rust_2018())
+ self.parse_assoc_item(|edition| edition >= Edition::Edition2018)
}
/// Parses associated items.
fn parse_assoc_item(&mut self, req_name: ReqName) -> PResult<'a, Option<Option<P<AssocItem>>>> {
- let attrs = self.parse_outer_attributes()?;
- let it = self.parse_item_common(attrs, true, false, req_name)?;
- Ok(it.map(|Item { attrs, id, span, vis, ident, defaultness, kind, tokens }| {
- let kind = match kind {
- ItemKind::Mac(a) => AssocItemKind::Macro(a),
- ItemKind::Fn(a, b, c) => AssocItemKind::Fn(a, b, c),
- ItemKind::TyAlias(a, b, c) => AssocItemKind::TyAlias(a, b, c),
- ItemKind::Const(a, c) => AssocItemKind::Const(a, c),
- ItemKind::Static(a, _, b) => {
- self.struct_span_err(span, "associated `static` items are not allowed").emit();
- AssocItemKind::Const(a, b)
- }
- _ => {
- let span = self.sess.source_map().def_span(span);
- self.struct_span_err(span, "item kind not supported in `trait` or `impl`")
- .emit();
- return None;
- }
+ Ok(self.parse_item_(req_name)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
+ let kind = match AssocItemKind::try_from(kind) {
+ Ok(kind) => kind,
+ Err(kind) => match kind {
+ ItemKind::Static(a, _, b) => {
+ self.struct_span_err(span, "associated `static` items are not allowed")
+ .emit();
+ AssocItemKind::Const(Defaultness::Final, a, b)
+ }
+ _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
+ },
};
- Some(P(Item { attrs, id, span, vis, ident, defaultness, kind, tokens }))
+ Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
}))
}
/// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
/// ```
/// The `"type"` has already been eaten.
- fn parse_type_alias(&mut self) -> PResult<'a, (Ident, ItemKind)> {
+ fn parse_type_alias(&mut self, def: Defaultness) -> PResult<'a, ItemInfo> {
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
self.expect_semi()?;
- Ok((ident, ItemKind::TyAlias(generics, bounds, default)))
+ Ok((ident, ItemKind::TyAlias(def, generics, bounds, default)))
}
/// Parses a `UseTree`.
}
fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> {
- match self.token.kind {
+ match self.normalized_token.kind {
token::Ident(name @ kw::Underscore, false) => {
- let span = self.token.span;
self.bump();
- Ok(Ident::new(name, span))
+ Ok(Ident::new(name, self.normalized_prev_token.span))
}
_ => self.parse_ident(),
}
/// Parses a foreign item (one in an `extern { ... }` block).
pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
- maybe_whole!(self, NtForeignItem, |item| Some(Some(item)));
-
- let attrs = self.parse_outer_attributes()?;
- let item = self.parse_item_common(attrs, true, false, |_| true)?;
- Ok(item.map(|Item { attrs, id, span, vis, ident, defaultness, kind, tokens }| {
- self.error_on_illegal_default(defaultness);
- let kind = match kind {
- ItemKind::Mac(a) => ForeignItemKind::Macro(a),
- ItemKind::Fn(a, b, c) => ForeignItemKind::Fn(a, b, c),
- ItemKind::TyAlias(a, b, c) => ForeignItemKind::TyAlias(a, b, c),
- ItemKind::Static(a, b, c) => ForeignItemKind::Static(a, b, c),
- ItemKind::Const(a, b) => {
- self.error_on_foreign_const(span, ident);
- ForeignItemKind::Static(a, Mutability::Not, b)
- }
- _ => {
- let span = self.sess.source_map().def_span(span);
- self.struct_span_err(span, "item kind not supported in `extern` block").emit();
- return None;
- }
+ Ok(self.parse_item_(|_| true)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
+ let kind = match ForeignItemKind::try_from(kind) {
+ Ok(kind) => kind,
+ Err(kind) => match kind {
+ ItemKind::Const(_, a, b) => {
+ self.error_on_foreign_const(span, ident);
+ ForeignItemKind::Static(a, Mutability::Not, b)
+ }
+ _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
+ },
};
- Some(P(Item { attrs, id, span, vis, ident, defaultness, kind, tokens }))
+ Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
}))
}
+ fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
+ let span = self.sess.source_map().def_span(span);
+ let msg = format!("{} is not supported in {}", kind.descr(), ctx);
+ self.struct_span_err(span, &msg).emit();
+ return None;
+ }
+
fn error_on_foreign_const(&self, span: Span, ident: Ident) {
self.struct_span_err(ident.span, "extern items cannot be `const`")
.span_suggestion(
/// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
///
/// When `m` is `"const"`, `$ident` may also be `"_"`.
- fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
+ fn parse_item_global(
+ &mut self,
+ m: Option<Mutability>,
+ ) -> PResult<'a, (Ident, P<Ty>, Option<P<ast::Expr>>)> {
let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?;
// Parse the type of a `const` or `static mut?` item.
let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
self.expect_semi()?;
-
- let item = match m {
- Some(m) => ItemKind::Static(ty, m, expr),
- None => ItemKind::Const(ty, expr),
- };
- Ok((id, item))
+ Ok((id, ty, expr))
}
/// We were supposed to parse `:` but the `:` was missing.
let comma_after_doc_seen = self.eat(&token::Comma);
// `seen_comma` is always false, because we are inside doc block
// condition is here to make code more readable
- if seen_comma == false && comma_after_doc_seen == true {
+ if !seen_comma && comma_after_doc_seen {
seen_comma = true;
}
if comma_after_doc_seen || self.token == token::CloseDelim(token::Brace) {
err.emit();
} else {
- if seen_comma == false {
+ if !seen_comma {
let sp = self.sess.source_map().next_point(previous_span);
err.span_suggestion(
sp,
/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
///
/// The function decides if, per-parameter `p`, `p` must have a pattern or just a type.
-type ReqName = fn(&token::Token) -> bool;
+type ReqName = fn(Edition) -> bool;
/// Parsing of functions and methods.
impl<'a> Parser<'a> {
let is_name_required = match self.token.kind {
token::DotDotDot => false,
- _ => req_name(&self.token),
+ _ => req_name(self.normalized_token.span.edition()),
};
let (pat, ty) = if is_name_required || self.is_named_param() {
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
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 {
+ match this.normalized_token.kind {
// Preserve hygienic context.
token::Ident(name, _) => {
- let span = this.token.span;
this.bump();
- Ident::new(name, span)
+ Ident::new(name, this.normalized_prev_token.span)
}
_ => unreachable!(),
}
// 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 {
+ let (eself, eself_ident, eself_hi) = match self.normalized_token.kind {
token::BinOp(token::And) => {
let eself = if is_isolated_self(self, 1) {
// `&self`