summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/item.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/parser/item.rs')
-rw-r--r--compiler/rustc_parse/src/parser/item.rs153
1 files changed, 97 insertions, 56 deletions
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 801860c21..09ee042ef 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -3,18 +3,12 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
use crate::errors::{self, MacroExpandsToAdtField};
use crate::fluent_generated as fluent;
-use ast::StaticItem;
use rustc_ast::ast::*;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::util::case::Case;
-use rustc_ast::MacCall;
-use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
-use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
-use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind};
-use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData};
-use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
+use rustc_ast::{self as ast};
use rustc_ast_pretty::pprust;
use rustc_errors::{
struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
@@ -123,7 +117,7 @@ impl<'a> Parser<'a> {
// Don't use `maybe_whole` so that we have precise control
// over when we bump the parser
if let token::Interpolated(nt) = &self.token.kind
- && let token::NtItem(item) = &**nt
+ && let token::NtItem(item) = &nt.0
{
let mut item = item.clone();
self.bump();
@@ -444,11 +438,7 @@ impl<'a> Parser<'a> {
None
};
- if let Some(err) = err {
- Err(err.into_diagnostic(&self.sess.span_diagnostic))
- } else {
- Ok(())
- }
+ if let Some(err) = err { Err(err.into_diagnostic(self.dcx())) } else { Ok(()) }
}
fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> {
@@ -769,7 +759,7 @@ impl<'a> Parser<'a> {
if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) {
// FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585)
struct_span_err!(
- self.diagnostic(),
+ self.dcx(),
self.token.span,
E0584,
"found a documentation comment that doesn't document anything",
@@ -933,7 +923,7 @@ impl<'a> Parser<'a> {
);
let where_predicates_split = before_where_clause.predicates.len();
let mut predicates = before_where_clause.predicates;
- predicates.extend(after_where_clause.predicates.into_iter());
+ predicates.extend(after_where_clause.predicates);
let where_clause = WhereClause {
has_where_token: before_where_clause.has_where_token
|| after_where_clause.has_where_token,
@@ -1143,9 +1133,11 @@ impl<'a> Parser<'a> {
Ok(kind) => kind,
Err(kind) => match kind {
ItemKind::Const(box ConstItem { ty, expr, .. }) => {
+ let const_span = Some(span.with_hi(ident.span.lo()))
+ .filter(|span| span.can_be_used_for_suggestions());
self.sess.emit_err(errors::ExternItemCannotBeConst {
ident_span: ident.span,
- const_span: span.with_hi(ident.span.lo()),
+ const_span,
});
ForeignItemKind::Static(ty, Mutability::Not, expr)
}
@@ -1382,8 +1374,7 @@ impl<'a> Parser<'a> {
let span = self.prev_token.span.shrink_to_hi();
let err: DiagnosticBuilder<'_, ErrorGuaranteed> =
- errors::MissingConstType { span, colon, kind }
- .into_diagnostic(&self.sess.span_diagnostic);
+ errors::MissingConstType { span, colon, kind }.into_diagnostic(self.dcx());
err.stash(span, StashKey::ItemNoType);
// The user intended that the type be inferred,
@@ -1400,7 +1391,7 @@ impl<'a> Parser<'a> {
self.bump();
self.sess.emit_err(err);
} else {
- return Err(err.into_diagnostic(&self.sess.span_diagnostic));
+ return Err(err.into_diagnostic(self.dcx()));
}
}
@@ -1415,8 +1406,8 @@ impl<'a> Parser<'a> {
self.bump();
(thin_vec![], false)
} else {
- self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
- |mut err| {
+ self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant(id.span))
+ .map_err(|mut err| {
err.span_label(id.span, "while parsing this enum");
if self.token == token::Colon {
let snapshot = self.create_snapshot_for_diagnostic();
@@ -1436,20 +1427,22 @@ impl<'a> Parser<'a> {
}
self.restore_snapshot(snapshot);
}
- self.recover_stmt();
+ self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
+ self.bump(); // }
err
- },
- )?
+ })?
};
let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
Ok((id, ItemKind::Enum(enum_definition, generics)))
}
- fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
+ fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option<Variant>> {
self.recover_diff_marker();
let variant_attrs = self.parse_outer_attributes()?;
self.recover_diff_marker();
+ let help = "enum variants can be `Variant`, `Variant = <integer>`, \
+ `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`";
self.collect_tokens_trailing_token(
variant_attrs,
ForceCollect::No,
@@ -1476,10 +1469,39 @@ impl<'a> Parser<'a> {
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
// Parse a struct variant.
let (fields, recovered) =
- this.parse_record_struct_body("struct", ident.span, false)?;
- VariantData::Struct(fields, recovered)
+ match this.parse_record_struct_body("struct", ident.span, false) {
+ Ok((fields, recovered)) => (fields, recovered),
+ Err(mut err) => {
+ if this.token == token::Colon {
+ // We handle `enum` to `struct` suggestion in the caller.
+ return Err(err);
+ }
+ this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
+ this.bump(); // }
+ err.span_label(span, "while parsing this enum");
+ err.help(help);
+ err.emit();
+ (thin_vec![], true)
+ }
+ };
+ VariantData::Struct { fields, recovered }
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
- VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
+ let body = match this.parse_tuple_struct_body() {
+ Ok(body) => body,
+ Err(mut err) => {
+ if this.token == token::Colon {
+ // We handle `enum` to `struct` suggestion in the caller.
+ return Err(err);
+ }
+ this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
+ this.bump(); // )
+ err.span_label(span, "while parsing this enum");
+ err.help(help);
+ err.emit();
+ thin_vec![]
+ }
+ };
+ VariantData::Tuple(body, DUMMY_NODE_ID)
} else {
VariantData::Unit(DUMMY_NODE_ID)
};
@@ -1500,8 +1522,9 @@ impl<'a> Parser<'a> {
Ok((Some(vr), TrailingToken::MaybeComma))
},
- ).map_err(|mut err| {
- err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
+ )
+ .map_err(|mut err| {
+ err.help(help);
err
})
}
@@ -1546,7 +1569,7 @@ impl<'a> Parser<'a> {
class_name.span,
generics.where_clause.has_where_token,
)?;
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
}
// No `where` so: `struct Foo<T>;`
} else if self.eat(&token::Semi) {
@@ -1558,7 +1581,7 @@ impl<'a> Parser<'a> {
class_name.span,
generics.where_clause.has_where_token,
)?;
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);
@@ -1568,7 +1591,7 @@ impl<'a> Parser<'a> {
} else {
let err =
errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone());
- return Err(err.into_diagnostic(&self.sess.span_diagnostic));
+ return Err(err.into_diagnostic(self.dcx()));
};
Ok((class_name, ItemKind::Struct(vdata, generics)))
@@ -1587,14 +1610,14 @@ impl<'a> Parser<'a> {
class_name.span,
generics.where_clause.has_where_token,
)?;
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
} else if self.token == token::OpenDelim(Delimiter::Brace) {
let (fields, recovered) = self.parse_record_struct_body(
"union",
class_name.span,
generics.where_clause.has_where_token,
)?;
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
} else {
let token_str = super::token_descr(&self.token);
let msg = format!("expected `where` or `{{` after union name, found {token_str}");
@@ -1764,7 +1787,7 @@ impl<'a> Parser<'a> {
let sp = previous_span.shrink_to_hi();
err.missing_comma = Some(sp);
}
- return Err(err.into_diagnostic(&self.sess.span_diagnostic));
+ return Err(err.into_diagnostic(self.dcx()));
}
}
_ => {
@@ -1814,7 +1837,7 @@ impl<'a> Parser<'a> {
// Make sure an error was emitted (either by recovering an angle bracket,
// or by finding an identifier as the next token), since we're
// going to continue parsing
- assert!(self.sess.span_diagnostic.has_errors().is_some());
+ assert!(self.dcx().has_errors().is_some());
} else {
return Err(err);
}
@@ -2271,7 +2294,7 @@ impl<'a> Parser<'a> {
} else {
&[token::Semi, token::OpenDelim(Delimiter::Brace)]
};
- if let Err(mut err) = self.expected_one_of_not_found(&[], &expected) {
+ if let Err(mut err) = self.expected_one_of_not_found(&[], expected) {
if self.token.kind == token::CloseDelim(Delimiter::Brace) {
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
// the AST for typechecking.
@@ -2330,8 +2353,10 @@ impl<'a> Parser<'a> {
|| case == Case::Insensitive
&& t.is_non_raw_ident_where(|i| quals.iter().any(|qual| qual.as_str() == i.name.as_str().to_lowercase()))
)
- // Rule out unsafe extern block.
- && !self.is_unsafe_foreign_mod())
+ // Rule out `unsafe extern {`.
+ && !self.is_unsafe_foreign_mod()
+ // Rule out `async gen {` and `async gen move {`
+ && !self.is_async_gen_block())
})
// `extern ABI fn`
|| self.check_keyword_case(kw::Extern, case)
@@ -2363,10 +2388,7 @@ impl<'a> Parser<'a> {
let constness = self.parse_constness(case);
let async_start_sp = self.token.span;
- let asyncness = self.parse_asyncness(case);
-
- let _gen_start_sp = self.token.span;
- let genness = self.parse_genness(case);
+ let coroutine_kind = self.parse_coroutine_kind(case);
let unsafe_start_sp = self.token.span;
let unsafety = self.parse_unsafety(case);
@@ -2374,7 +2396,7 @@ impl<'a> Parser<'a> {
let ext_start_sp = self.token.span;
let ext = self.parse_extern(case);
- if let Async::Yes { span, .. } = asyncness {
+ if let Some(CoroutineKind::Async { span, .. }) = coroutine_kind {
if span.is_rust_2015() {
self.sess.emit_err(errors::AsyncFnIn2015 {
span,
@@ -2383,8 +2405,11 @@ impl<'a> Parser<'a> {
}
}
- if let Gen::Yes { span, .. } = genness {
- self.sess.emit_err(errors::GenFn { span });
+ match coroutine_kind {
+ Some(CoroutineKind::Gen { span, .. }) | Some(CoroutineKind::AsyncGen { span, .. }) => {
+ self.sess.gated_spans.gate(sym::gen_blocks, span);
+ }
+ Some(CoroutineKind::Async { .. }) | None => {}
}
if !self.eat_keyword_case(kw::Fn, case) {
@@ -2403,7 +2428,7 @@ impl<'a> Parser<'a> {
// We may be able to recover
let mut recover_constness = constness;
- let mut recover_asyncness = asyncness;
+ let mut recover_coroutine_kind = coroutine_kind;
let mut recover_unsafety = unsafety;
// This will allow the machine fix to directly place the keyword in the correct place or to indicate
// that the keyword is already present and the second instance should be removed.
@@ -2416,14 +2441,28 @@ impl<'a> Parser<'a> {
}
}
} else if self.check_keyword(kw::Async) {
- match asyncness {
- Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)),
- Async::No => {
- recover_asyncness = Async::Yes {
+ match coroutine_kind {
+ Some(CoroutineKind::Async { span, .. }) => {
+ Some(WrongKw::Duplicated(span))
+ }
+ Some(CoroutineKind::AsyncGen { span, .. }) => {
+ Some(WrongKw::Duplicated(span))
+ }
+ Some(CoroutineKind::Gen { .. }) => {
+ recover_coroutine_kind = Some(CoroutineKind::AsyncGen {
+ span: self.token.span,
+ closure_id: DUMMY_NODE_ID,
+ return_impl_trait_id: DUMMY_NODE_ID,
+ });
+ // FIXME(gen_blocks): This span is wrong, didn't want to think about it.
+ Some(WrongKw::Misplaced(unsafe_start_sp))
+ }
+ None => {
+ recover_coroutine_kind = Some(CoroutineKind::Async {
span: self.token.span,
closure_id: DUMMY_NODE_ID,
return_impl_trait_id: DUMMY_NODE_ID,
- };
+ });
Some(WrongKw::Misplaced(unsafe_start_sp))
}
}
@@ -2504,6 +2543,8 @@ impl<'a> Parser<'a> {
}
}
+ // FIXME(gen_blocks): add keyword recovery logic for genness
+
if wrong_kw.is_some()
&& self.may_recover()
&& self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case))
@@ -2515,7 +2556,7 @@ impl<'a> Parser<'a> {
return Ok(FnHeader {
constness: recover_constness,
unsafety: recover_unsafety,
- asyncness: recover_asyncness,
+ coroutine_kind: recover_coroutine_kind,
ext,
});
}
@@ -2525,7 +2566,7 @@ impl<'a> Parser<'a> {
}
}
- Ok(FnHeader { constness, unsafety, asyncness, ext })
+ Ok(FnHeader { constness, unsafety, coroutine_kind, ext })
}
/// Parses the parameter list and result type of a function declaration.
@@ -2750,7 +2791,7 @@ impl<'a> Parser<'a> {
fn is_named_param(&self) -> bool {
let offset = match &self.token.kind {
- token::Interpolated(nt) => match **nt {
+ token::Interpolated(nt) => match &nt.0 {
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
_ => 0,
},