|
|
|
|
@@ -78,16 +78,17 @@ pub(super) type ItemInfo = (Ident, ItemKind);
|
|
|
|
|
|
|
|
|
|
impl<'a> Parser<'a> {
|
|
|
|
|
pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<P<Item>>> {
|
|
|
|
|
self.parse_item_(|_| true, force_collect).map(|i| i.map(P))
|
|
|
|
|
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
|
|
|
|
|
self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(P))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_item_(
|
|
|
|
|
&mut self,
|
|
|
|
|
req_name: ReqName,
|
|
|
|
|
fn_parse_mode: FnParseMode,
|
|
|
|
|
force_collect: ForceCollect,
|
|
|
|
|
) -> PResult<'a, Option<Item>> {
|
|
|
|
|
let attrs = self.parse_outer_attributes()?;
|
|
|
|
|
self.parse_item_common(attrs, true, false, req_name, force_collect)
|
|
|
|
|
self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn parse_item_common(
|
|
|
|
|
@@ -95,7 +96,7 @@ impl<'a> Parser<'a> {
|
|
|
|
|
attrs: AttrWrapper,
|
|
|
|
|
mac_allowed: bool,
|
|
|
|
|
attrs_allowed: bool,
|
|
|
|
|
req_name: ReqName,
|
|
|
|
|
fn_parse_mode: FnParseMode,
|
|
|
|
|
force_collect: ForceCollect,
|
|
|
|
|
) -> PResult<'a, Option<Item>> {
|
|
|
|
|
// Don't use `maybe_whole` so that we have precise control
|
|
|
|
|
@@ -113,7 +114,8 @@ impl<'a> Parser<'a> {
|
|
|
|
|
let mut unclosed_delims = vec![];
|
|
|
|
|
let item =
|
|
|
|
|
self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
|
|
|
|
|
let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
|
|
|
|
|
let item =
|
|
|
|
|
this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode);
|
|
|
|
|
unclosed_delims.append(&mut this.unclosed_delims);
|
|
|
|
|
Ok((item?, TrailingToken::None))
|
|
|
|
|
})?;
|
|
|
|
|
@@ -127,12 +129,13 @@ impl<'a> Parser<'a> {
|
|
|
|
|
mut attrs: Vec<Attribute>,
|
|
|
|
|
mac_allowed: bool,
|
|
|
|
|
attrs_allowed: bool,
|
|
|
|
|
req_name: ReqName,
|
|
|
|
|
fn_parse_mode: FnParseMode,
|
|
|
|
|
) -> PResult<'a, Option<Item>> {
|
|
|
|
|
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)?;
|
|
|
|
|
let kind =
|
|
|
|
|
self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, fn_parse_mode)?;
|
|
|
|
|
if let Some((ident, kind)) = kind {
|
|
|
|
|
self.error_on_unconsumed_default(def, &kind);
|
|
|
|
|
let span = lo.to(self.prev_token.span);
|
|
|
|
|
@@ -192,7 +195,7 @@ impl<'a> Parser<'a> {
|
|
|
|
|
lo: Span,
|
|
|
|
|
vis: &Visibility,
|
|
|
|
|
def: &mut Defaultness,
|
|
|
|
|
req_name: ReqName,
|
|
|
|
|
fn_parse_mode: FnParseMode,
|
|
|
|
|
) -> PResult<'a, Option<ItemInfo>> {
|
|
|
|
|
let def_final = def == &Defaultness::Final;
|
|
|
|
|
let mut def = || mem::replace(def, Defaultness::Final);
|
|
|
|
|
@@ -219,7 +222,7 @@ impl<'a> Parser<'a> {
|
|
|
|
|
(Ident::empty(), ItemKind::Use(tree))
|
|
|
|
|
} else if self.check_fn_front_matter(def_final) {
|
|
|
|
|
// FUNCTION ITEM
|
|
|
|
|
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
|
|
|
|
|
let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo)?;
|
|
|
|
|
(ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
|
|
|
|
|
} else if self.eat_keyword(kw::Extern) {
|
|
|
|
|
if self.eat_keyword(kw::Crate) {
|
|
|
|
|
@@ -733,23 +736,26 @@ impl<'a> Parser<'a> {
|
|
|
|
|
&mut self,
|
|
|
|
|
force_collect: ForceCollect,
|
|
|
|
|
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
|
|
|
|
|
self.parse_assoc_item(|_| true, force_collect)
|
|
|
|
|
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
|
|
|
|
|
self.parse_assoc_item(fn_parse_mode, force_collect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn parse_trait_item(
|
|
|
|
|
&mut self,
|
|
|
|
|
force_collect: ForceCollect,
|
|
|
|
|
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
|
|
|
|
|
self.parse_assoc_item(|edition| edition >= Edition::Edition2018, force_collect)
|
|
|
|
|
let fn_parse_mode =
|
|
|
|
|
FnParseMode { req_name: |edition| edition >= Edition::Edition2018, req_body: false };
|
|
|
|
|
self.parse_assoc_item(fn_parse_mode, force_collect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Parses associated items.
|
|
|
|
|
fn parse_assoc_item(
|
|
|
|
|
&mut self,
|
|
|
|
|
req_name: ReqName,
|
|
|
|
|
fn_parse_mode: FnParseMode,
|
|
|
|
|
force_collect: ForceCollect,
|
|
|
|
|
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
|
|
|
|
|
Ok(self.parse_item_(req_name, force_collect)?.map(
|
|
|
|
|
Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
|
|
|
|
|
|Item { attrs, id, span, vis, ident, kind, tokens }| {
|
|
|
|
|
let kind = match AssocItemKind::try_from(kind) {
|
|
|
|
|
Ok(kind) => kind,
|
|
|
|
|
@@ -944,7 +950,8 @@ impl<'a> Parser<'a> {
|
|
|
|
|
&mut self,
|
|
|
|
|
force_collect: ForceCollect,
|
|
|
|
|
) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
|
|
|
|
|
Ok(self.parse_item_(|_| true, force_collect)?.map(
|
|
|
|
|
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: false };
|
|
|
|
|
Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
|
|
|
|
|
|Item { attrs, id, span, vis, ident, kind, tokens }| {
|
|
|
|
|
let kind = match ForeignItemKind::try_from(kind) {
|
|
|
|
|
Ok(kind) => kind,
|
|
|
|
|
@@ -1484,7 +1491,8 @@ impl<'a> Parser<'a> {
|
|
|
|
|
if !is_raw && ident.is_reserved() {
|
|
|
|
|
let err = if self.check_fn_front_matter(false) {
|
|
|
|
|
// We use `parse_fn` to get a span for the function
|
|
|
|
|
if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
|
|
|
|
|
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
|
|
|
|
|
if let Err(mut db) = self.parse_fn(&mut Vec::new(), fn_parse_mode, lo) {
|
|
|
|
|
db.delay_as_bug();
|
|
|
|
|
}
|
|
|
|
|
let mut err = self.struct_span_err(
|
|
|
|
|
@@ -1698,25 +1706,82 @@ impl<'a> Parser<'a> {
|
|
|
|
|
/// 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.
|
|
|
|
|
///
|
|
|
|
|
/// This function pointer accepts an edition, because in edition 2015, trait declarations
|
|
|
|
|
/// were allowed to omit parameter names. In 2018, they became required.
|
|
|
|
|
type ReqName = fn(Edition) -> bool;
|
|
|
|
|
|
|
|
|
|
/// Parsing configuration for functions.
|
|
|
|
|
///
|
|
|
|
|
/// The syntax of function items is slightly different within trait definitions,
|
|
|
|
|
/// impl blocks, and modules. It is still parsed using the same code, just with
|
|
|
|
|
/// different flags set, so that even when the input is wrong and produces a parse
|
|
|
|
|
/// error, it still gets into the AST and the rest of the parser and
|
|
|
|
|
/// type checker can run.
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
|
pub(crate) struct FnParseMode {
|
|
|
|
|
/// A function pointer that decides if, per-parameter `p`, `p` must have a
|
|
|
|
|
/// pattern or just a type. This field affects parsing of the parameters list.
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// fn foo(alef: A) -> X { X::new() }
|
|
|
|
|
/// -----^^ affects parsing this part of the function signature
|
|
|
|
|
/// |
|
|
|
|
|
/// if req_name returns false, then this name is optional
|
|
|
|
|
///
|
|
|
|
|
/// fn bar(A) -> X;
|
|
|
|
|
/// ^
|
|
|
|
|
/// |
|
|
|
|
|
/// if req_name returns true, this is an error
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// Calling this function pointer should only return false if:
|
|
|
|
|
///
|
|
|
|
|
/// * The item is being parsed inside of a trait definition.
|
|
|
|
|
/// Within an impl block or a module, it should always evaluate
|
|
|
|
|
/// to true.
|
|
|
|
|
/// * The span is from Edition 2015. In particular, you can get a
|
|
|
|
|
/// 2015 span inside a 2021 crate using macros.
|
|
|
|
|
pub req_name: ReqName,
|
|
|
|
|
/// If this flag is set to `true`, then plain, semicolon-terminated function
|
|
|
|
|
/// prototypes are not allowed here.
|
|
|
|
|
///
|
|
|
|
|
/// ```text
|
|
|
|
|
/// fn foo(alef: A) -> X { X::new() }
|
|
|
|
|
/// ^^^^^^^^^^^^
|
|
|
|
|
/// |
|
|
|
|
|
/// this is always allowed
|
|
|
|
|
///
|
|
|
|
|
/// fn bar(alef: A, bet: B) -> X;
|
|
|
|
|
/// ^
|
|
|
|
|
/// |
|
|
|
|
|
/// if req_body is set to true, this is an error
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// This field should only be set to false if the item is inside of a trait
|
|
|
|
|
/// definition or extern block. Within an impl block or a module, it should
|
|
|
|
|
/// always be set to true.
|
|
|
|
|
pub req_body: bool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Parsing of functions and methods.
|
|
|
|
|
impl<'a> Parser<'a> {
|
|
|
|
|
/// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`.
|
|
|
|
|
fn parse_fn(
|
|
|
|
|
&mut self,
|
|
|
|
|
attrs: &mut Vec<Attribute>,
|
|
|
|
|
req_name: ReqName,
|
|
|
|
|
fn_parse_mode: FnParseMode,
|
|
|
|
|
sig_lo: Span,
|
|
|
|
|
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
|
|
|
|
|
let header = self.parse_fn_front_matter()?; // `const ... fn`
|
|
|
|
|
let ident = self.parse_ident()?; // `foo`
|
|
|
|
|
let mut generics = self.parse_generics()?; // `<'a, T, ...>`
|
|
|
|
|
let decl = self.parse_fn_decl(req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
|
|
|
|
|
let decl =
|
|
|
|
|
self.parse_fn_decl(fn_parse_mode.req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
|
|
|
|
|
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
|
|
|
|
|
|
|
|
|
|
let mut sig_hi = self.prev_token.span;
|
|
|
|
|
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`.
|
|
|
|
|
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body)?; // `;` or `{ ... }`.
|
|
|
|
|
let fn_sig_span = sig_lo.to(sig_hi);
|
|
|
|
|
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
|
|
|
|
|
}
|
|
|
|
|
@@ -1729,9 +1794,17 @@ impl<'a> Parser<'a> {
|
|
|
|
|
attrs: &mut Vec<Attribute>,
|
|
|
|
|
ident: &Ident,
|
|
|
|
|
sig_hi: &mut Span,
|
|
|
|
|
req_body: bool,
|
|
|
|
|
) -> PResult<'a, Option<P<Block>>> {
|
|
|
|
|
let (inner_attrs, body) = if self.eat(&token::Semi) {
|
|
|
|
|
let has_semi = if req_body {
|
|
|
|
|
self.token.kind == TokenKind::Semi
|
|
|
|
|
} else {
|
|
|
|
|
// Only include `;` in list of expected tokens if body is not required
|
|
|
|
|
self.check(&TokenKind::Semi)
|
|
|
|
|
};
|
|
|
|
|
let (inner_attrs, body) = if has_semi {
|
|
|
|
|
// Include the trailing semicolon in the span of the signature
|
|
|
|
|
self.expect_semi()?;
|
|
|
|
|
*sig_hi = self.prev_token.span;
|
|
|
|
|
(Vec::new(), None)
|
|
|
|
|
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
|
|
|
|
|
@@ -1752,9 +1825,12 @@ impl<'a> Parser<'a> {
|
|
|
|
|
.emit();
|
|
|
|
|
(Vec::new(), Some(self.mk_block_err(span)))
|
|
|
|
|
} else {
|
|
|
|
|
if let Err(mut err) =
|
|
|
|
|
self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
|
|
|
|
|
{
|
|
|
|
|
let expected = if req_body {
|
|
|
|
|
&[token::OpenDelim(token::Brace)][..]
|
|
|
|
|
} else {
|
|
|
|
|
&[token::Semi, token::OpenDelim(token::Brace)]
|
|
|
|
|
};
|
|
|
|
|
if let Err(mut err) = self.expected_one_of_not_found(&[], &expected) {
|
|
|
|
|
if self.token.kind == token::CloseDelim(token::Brace) {
|
|
|
|
|
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
|
|
|
|
|
// the AST for typechecking.
|
|
|
|
|
|