syntax: cleanup method parsing.
This commit is contained in:
parent
8431f261dd
commit
f2904674e8
2 changed files with 66 additions and 74 deletions
|
@ -1180,7 +1180,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, ast::TraitItem> {
|
crate fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
|
||||||
let token_str = self.this_token_descr();
|
let token_str = self.this_token_descr();
|
||||||
let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
|
let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
|
||||||
err.span_label(self.token.span, "expected `;` or `{`");
|
err.span_label(self.token.span, "expected `;` or `{`");
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::ast::{
|
||||||
Item, ItemKind, ImplItem, TraitItem, TraitItemKind,
|
Item, ItemKind, ImplItem, TraitItem, TraitItemKind,
|
||||||
UseTree, UseTreeKind, PathSegment,
|
UseTree, UseTreeKind, PathSegment,
|
||||||
IsAuto, Constness, IsAsync, Unsafety, Defaultness,
|
IsAuto, Constness, IsAsync, Unsafety, Defaultness,
|
||||||
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader,
|
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block,
|
||||||
ForeignItem, ForeignItemKind,
|
ForeignItem, ForeignItemKind,
|
||||||
Ty, TyKind, Generics, GenericBounds, TraitRef,
|
Ty, TyKind, Generics, GenericBounds, TraitRef,
|
||||||
EnumDef, VariantData, StructField, AnonConst,
|
EnumDef, VariantData, StructField, AnonConst,
|
||||||
|
@ -848,29 +848,38 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a method or a macro invocation in a trait impl.
|
/// Parses a method or a macro invocation in a trait impl.
|
||||||
fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool)
|
fn parse_impl_method(
|
||||||
-> PResult<'a, (Ident, Vec<Attribute>, Generics, ast::ImplItemKind)> {
|
&mut self,
|
||||||
|
vis: &Visibility,
|
||||||
|
at_end: &mut bool
|
||||||
|
) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ast::ImplItemKind)> {
|
||||||
// FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
|
// 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)? {
|
if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
|
||||||
// method macro
|
// method macro
|
||||||
Ok((Ident::invalid(), vec![], Generics::default(),
|
Ok((Ident::invalid(), vec![], Generics::default(), ast::ImplItemKind::Macro(mac)))
|
||||||
ast::ImplItemKind::Macro(mac)))
|
|
||||||
} else {
|
} else {
|
||||||
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
|
let (ident, sig, generics) = self.parse_method_sig(|_| true)?;
|
||||||
let ident = self.parse_ident()?;
|
|
||||||
let mut generics = self.parse_generics()?;
|
|
||||||
let decl = self.parse_fn_decl_with_self(|_| true)?;
|
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
|
||||||
*at_end = true;
|
*at_end = true;
|
||||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||||
let header = ast::FnHeader { abi, unsafety, constness, asyncness };
|
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body)))
|
||||||
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(
|
|
||||||
ast::MethodSig { header, decl },
|
|
||||||
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: impl Copy + Fn(&token::Token) -> bool,
|
||||||
|
) -> PResult<'a, (Ident, MethodSig, Generics)> {
|
||||||
|
let header = self.parse_fn_front_matter()?;
|
||||||
|
let ident = self.parse_ident()?;
|
||||||
|
let mut generics = self.parse_generics()?;
|
||||||
|
let decl = self.parse_fn_decl_with_self(is_name_required)?;
|
||||||
|
let sig = MethodSig { header, decl };
|
||||||
|
generics.where_clause = self.parse_where_clause()?;
|
||||||
|
Ok((ident, sig, generics))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses all the "front matter" for a `fn` declaration, up to
|
/// Parses all the "front matter" for a `fn` declaration, up to
|
||||||
/// and including the `fn` keyword:
|
/// and including the `fn` keyword:
|
||||||
///
|
///
|
||||||
|
@ -879,14 +888,7 @@ impl<'a> Parser<'a> {
|
||||||
/// - `const unsafe fn`
|
/// - `const unsafe fn`
|
||||||
/// - `extern fn`
|
/// - `extern fn`
|
||||||
/// - etc.
|
/// - etc.
|
||||||
fn parse_fn_front_matter(&mut self)
|
fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
|
||||||
-> PResult<'a, (
|
|
||||||
Spanned<Constness>,
|
|
||||||
Unsafety,
|
|
||||||
Spanned<IsAsync>,
|
|
||||||
Abi
|
|
||||||
)>
|
|
||||||
{
|
|
||||||
let is_const_fn = self.eat_keyword(kw::Const);
|
let is_const_fn = self.eat_keyword(kw::Const);
|
||||||
let const_span = self.prev_span;
|
let const_span = self.prev_span;
|
||||||
let asyncness = self.parse_asyncness();
|
let asyncness = self.parse_asyncness();
|
||||||
|
@ -911,7 +913,7 @@ impl<'a> Parser<'a> {
|
||||||
// account for this.
|
// account for this.
|
||||||
if !self.expect_one_of(&[], &[])? { unreachable!() }
|
if !self.expect_one_of(&[], &[])? { unreachable!() }
|
||||||
}
|
}
|
||||||
Ok((constness, unsafety, asyncness, abi))
|
Ok(FnHeader { constness, unsafety, asyncness, abi })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `trait Foo { ... }` or `trait Foo = Bar;`.
|
/// Parses `trait Foo { ... }` or `trait Foo = Bar;`.
|
||||||
|
@ -1025,37 +1027,43 @@ impl<'a> Parser<'a> {
|
||||||
// trait item macro.
|
// trait item macro.
|
||||||
(Ident::invalid(), ast::TraitItemKind::Macro(mac), Generics::default())
|
(Ident::invalid(), ast::TraitItemKind::Macro(mac), Generics::default())
|
||||||
} else {
|
} else {
|
||||||
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
|
|
||||||
|
|
||||||
let ident = self.parse_ident()?;
|
|
||||||
let mut generics = self.parse_generics()?;
|
|
||||||
|
|
||||||
// This is somewhat dubious; We don't want to allow
|
// This is somewhat dubious; We don't want to allow
|
||||||
// argument names to be left off if there is a definition...
|
// argument names to be left off if there is a definition...
|
||||||
//
|
//
|
||||||
// We don't allow argument names to be left off in edition 2018.
|
// We don't allow argument names to be left off in edition 2018.
|
||||||
let decl = self.parse_fn_decl_with_self(|t| t.span.rust_2018())?;
|
let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
let body = self.parse_trait_method_body(at_end, &mut attrs)?;
|
||||||
|
(ident, ast::TraitItemKind::Method(sig, body), generics)
|
||||||
let sig = ast::MethodSig {
|
|
||||||
header: FnHeader {
|
|
||||||
unsafety,
|
|
||||||
constness,
|
|
||||||
abi,
|
|
||||||
asyncness,
|
|
||||||
},
|
|
||||||
decl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = match self.token.kind {
|
Ok(TraitItem {
|
||||||
|
id: DUMMY_NODE_ID,
|
||||||
|
ident: name,
|
||||||
|
attrs,
|
||||||
|
generics,
|
||||||
|
kind,
|
||||||
|
span: lo.to(self.prev_span),
|
||||||
|
tokens: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 => {
|
token::Semi => {
|
||||||
|
debug!("parse_trait_method_body(): parsing required method");
|
||||||
self.bump();
|
self.bump();
|
||||||
*at_end = true;
|
*at_end = true;
|
||||||
debug!("parse_trait_methods(): parsing required method");
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
token::OpenDelim(token::Brace) => {
|
token::OpenDelim(token::Brace) => {
|
||||||
debug!("parse_trait_methods(): parsing provided method");
|
debug!("parse_trait_method_body(): parsing provided method");
|
||||||
*at_end = true;
|
*at_end = true;
|
||||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||||
attrs.extend(inner_attrs.iter().cloned());
|
attrs.extend(inner_attrs.iter().cloned());
|
||||||
|
@ -1069,26 +1077,10 @@ impl<'a> Parser<'a> {
|
||||||
attrs.extend(inner_attrs.iter().cloned());
|
attrs.extend(inner_attrs.iter().cloned());
|
||||||
Some(body)
|
Some(body)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => return self.expected_semi_or_open_brace(),
|
||||||
return self.expected_semi_or_open_brace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
_ => return self.expected_semi_or_open_brace(),
|
||||||
_ => {
|
|
||||||
return self.expected_semi_or_open_brace();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(ident, ast::TraitItemKind::Method(sig, body), generics)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(TraitItem {
|
|
||||||
id: DUMMY_NODE_ID,
|
|
||||||
ident: name,
|
|
||||||
attrs,
|
|
||||||
generics,
|
|
||||||
kind,
|
|
||||||
span: lo.to(self.prev_span),
|
|
||||||
tokens: None,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue