Rollup merge of #64910 - Centril:params-cleanup, r=petrochenkov
syntax: cleanup param, method, and misc parsing Do some misc cleanup of the parser: - Method and parameter parsing is refactored. - A parser for `const | mut` is introduced that https://github.com/rust-lang/rust/pull/64588 can reuse. - Some other misc parsing. Next up in a different PR: - ~Implementing https://github.com/rust-lang/rust/issues/64252.~ -- maybe some other time... - Heavily restructuring up `item.rs` which is a mess (hopefully, no promises ^^). r? @petrochenkov
This commit is contained in:
commit
db9689333a
5 changed files with 518 additions and 586 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 mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
|
||||
err.span_label(self.token.span, "expected `;` or `{`");
|
||||
|
|
|
|||
|
|
@ -511,13 +511,15 @@ impl<'a> Parser<'a> {
|
|||
is_present
|
||||
}
|
||||
|
||||
/// If the next token is the given keyword, returns `true` without eating it.
|
||||
/// An expectation is also added for diagnostics purposes.
|
||||
fn check_keyword(&mut self, kw: Symbol) -> bool {
|
||||
self.expected_tokens.push(TokenType::Keyword(kw));
|
||||
self.token.is_keyword(kw)
|
||||
}
|
||||
|
||||
/// If the next token is the given keyword, eats it and returns
|
||||
/// `true`. Otherwise, returns `false`.
|
||||
/// If the next token is the given keyword, eats it and returns `true`.
|
||||
/// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
|
||||
pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
|
||||
if self.check_keyword(kw) {
|
||||
self.bump();
|
||||
|
|
@ -547,40 +549,38 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn check_ident(&mut self) -> bool {
|
||||
if self.token.is_ident() {
|
||||
fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool {
|
||||
if ok {
|
||||
true
|
||||
} else {
|
||||
self.expected_tokens.push(TokenType::Ident);
|
||||
self.expected_tokens.push(typ);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
crate fn check_ident(&mut self) -> bool {
|
||||
self.check_or_expected(self.token.is_ident(), TokenType::Ident)
|
||||
}
|
||||
|
||||
fn check_path(&mut self) -> bool {
|
||||
if self.token.is_path_start() {
|
||||
true
|
||||
} else {
|
||||
self.expected_tokens.push(TokenType::Path);
|
||||
false
|
||||
}
|
||||
self.check_or_expected(self.token.is_path_start(), TokenType::Path)
|
||||
}
|
||||
|
||||
fn check_type(&mut self) -> bool {
|
||||
if self.token.can_begin_type() {
|
||||
true
|
||||
} else {
|
||||
self.expected_tokens.push(TokenType::Type);
|
||||
false
|
||||
}
|
||||
self.check_or_expected(self.token.can_begin_type(), TokenType::Type)
|
||||
}
|
||||
|
||||
fn check_const_arg(&mut self) -> bool {
|
||||
if self.token.can_begin_const_arg() {
|
||||
true
|
||||
} else {
|
||||
self.expected_tokens.push(TokenType::Const);
|
||||
false
|
||||
}
|
||||
self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const)
|
||||
}
|
||||
|
||||
/// Checks to see if the next token is either `+` or `+=`.
|
||||
/// Otherwise returns `false`.
|
||||
fn check_plus(&mut self) -> bool {
|
||||
self.check_or_expected(
|
||||
self.token.is_like_plus(),
|
||||
TokenType::Token(token::BinOp(token::Plus)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=`
|
||||
|
|
@ -604,18 +604,6 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks to see if the next token is either `+` or `+=`.
|
||||
/// Otherwise returns `false`.
|
||||
fn check_plus(&mut self) -> bool {
|
||||
if self.token.is_like_plus() {
|
||||
true
|
||||
}
|
||||
else {
|
||||
self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus)));
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Expects and consumes an `&`. If `&&` is seen, replaces it with a single
|
||||
/// `&` and continues. If an `&` is not seen, signals an error.
|
||||
fn expect_and(&mut self) -> PResult<'a, ()> {
|
||||
|
|
@ -910,15 +898,15 @@ impl<'a> Parser<'a> {
|
|||
self.expected_tokens.clear();
|
||||
}
|
||||
|
||||
pub fn look_ahead<R, F>(&self, dist: usize, f: F) -> R where
|
||||
F: FnOnce(&Token) -> R,
|
||||
{
|
||||
/// Look-ahead `dist` tokens of `self.token` and get access to that token there.
|
||||
/// When `dist == 0` then the current token is looked at.
|
||||
pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R {
|
||||
if dist == 0 {
|
||||
return f(&self.token);
|
||||
return looker(&self.token);
|
||||
}
|
||||
|
||||
let frame = &self.token_cursor.frame;
|
||||
f(&match frame.tree_cursor.look_ahead(dist - 1) {
|
||||
looker(&match frame.tree_cursor.look_ahead(dist - 1) {
|
||||
Some(tree) => match tree {
|
||||
TokenTree::Token(token) => token,
|
||||
TokenTree::Delimited(dspan, delim, _) =>
|
||||
|
|
@ -954,109 +942,6 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_named_argument(&self) -> bool {
|
||||
let offset = match self.token.kind {
|
||||
token::Interpolated(ref nt) => match **nt {
|
||||
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
|
||||
_ => 0,
|
||||
}
|
||||
token::BinOp(token::And) | token::AndAnd => 1,
|
||||
_ if self.token.is_keyword(kw::Mut) => 1,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
self.look_ahead(offset, |t| t.is_ident()) &&
|
||||
self.look_ahead(offset + 1, |t| t == &token::Colon)
|
||||
}
|
||||
|
||||
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
|
||||
/// error.
|
||||
/// This version of parse param doesn't necessarily require identifier names.
|
||||
fn parse_param_general(
|
||||
&mut self,
|
||||
is_self_allowed: bool,
|
||||
is_trait_item: bool,
|
||||
allow_c_variadic: bool,
|
||||
is_name_required: impl Fn(&token::Token) -> bool,
|
||||
) -> PResult<'a, Param> {
|
||||
let lo = self.token.span;
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
|
||||
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
||||
if let Some(mut param) = self.parse_self_param()? {
|
||||
param.attrs = attrs.into();
|
||||
return if is_self_allowed {
|
||||
Ok(param)
|
||||
} else {
|
||||
self.recover_bad_self_param(param, is_trait_item)
|
||||
};
|
||||
}
|
||||
|
||||
let is_name_required = is_name_required(&self.token);
|
||||
let (pat, ty) = if is_name_required || self.is_named_argument() {
|
||||
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
||||
|
||||
let pat = self.parse_fn_param_pat()?;
|
||||
if let Err(mut err) = self.expect(&token::Colon) {
|
||||
if let Some(ident) = self.parameter_without_type(
|
||||
&mut err,
|
||||
pat,
|
||||
is_name_required,
|
||||
is_trait_item,
|
||||
) {
|
||||
err.emit();
|
||||
return Ok(dummy_arg(ident));
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
self.eat_incorrect_doc_comment_for_param_type();
|
||||
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
|
||||
} else {
|
||||
debug!("parse_param_general ident_to_pat");
|
||||
let parser_snapshot_before_ty = self.clone();
|
||||
self.eat_incorrect_doc_comment_for_param_type();
|
||||
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
|
||||
if ty.is_ok() && self.token != token::Comma &&
|
||||
self.token != token::CloseDelim(token::Paren) {
|
||||
// This wasn't actually a type, but a pattern looking like a type,
|
||||
// so we are going to rollback and re-parse for recovery.
|
||||
ty = self.unexpected();
|
||||
}
|
||||
match ty {
|
||||
Ok(ty) => {
|
||||
let ident = Ident::new(kw::Invalid, self.prev_span);
|
||||
let bm = BindingMode::ByValue(Mutability::Immutable);
|
||||
let pat = self.mk_pat_ident(ty.span, bm, ident);
|
||||
(pat, ty)
|
||||
}
|
||||
Err(mut err) => {
|
||||
// If this is a C-variadic argument and we hit an error, return the
|
||||
// error.
|
||||
if self.token == token::DotDotDot {
|
||||
return Err(err);
|
||||
}
|
||||
// Recover from attempting to parse the argument as a type without pattern.
|
||||
err.cancel();
|
||||
mem::replace(self, parser_snapshot_before_ty);
|
||||
self.recover_arg_parse()?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let span = lo.to(self.token.span);
|
||||
|
||||
Ok(Param {
|
||||
attrs: attrs.into(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
pat,
|
||||
span,
|
||||
ty,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses mutability (`mut` or nothing).
|
||||
fn parse_mutability(&mut self) -> Mutability {
|
||||
if self.eat_keyword(kw::Mut) {
|
||||
|
|
@ -1066,6 +951,17 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Possibly parses mutability (`const` or `mut`).
|
||||
fn parse_const_or_mut(&mut self) -> Option<Mutability> {
|
||||
if self.eat_keyword(kw::Mut) {
|
||||
Some(Mutability::Mutable)
|
||||
} else if self.eat_keyword(kw::Const) {
|
||||
Some(Mutability::Immutable)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_field_name(&mut self) -> PResult<'a, Ident> {
|
||||
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
|
||||
self.token.kind {
|
||||
|
|
@ -1100,9 +996,10 @@ impl<'a> Parser<'a> {
|
|||
Ok((delim, tts.into()))
|
||||
}
|
||||
|
||||
fn parse_or_use_outer_attributes(&mut self,
|
||||
already_parsed_attrs: Option<ThinVec<Attribute>>)
|
||||
-> PResult<'a, ThinVec<Attribute>> {
|
||||
fn parse_or_use_outer_attributes(
|
||||
&mut self,
|
||||
already_parsed_attrs: Option<ThinVec<Attribute>>,
|
||||
) -> PResult<'a, ThinVec<Attribute>> {
|
||||
if let Some(attrs) = already_parsed_attrs {
|
||||
Ok(attrs)
|
||||
} else {
|
||||
|
|
@ -1189,53 +1086,52 @@ impl<'a> Parser<'a> {
|
|||
/// Evaluates the closure with restrictions in place.
|
||||
///
|
||||
/// Afters the closure is evaluated, restrictions are reset.
|
||||
fn with_res<F, T>(&mut self, r: Restrictions, f: F) -> T
|
||||
where F: FnOnce(&mut Self) -> T
|
||||
{
|
||||
fn with_res<T>(&mut self, res: Restrictions, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let old = self.restrictions;
|
||||
self.restrictions = r;
|
||||
let r = f(self);
|
||||
self.restrictions = res;
|
||||
let res = f(self);
|
||||
self.restrictions = old;
|
||||
return r;
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn parse_fn_params(&mut self, named_params: bool, allow_c_variadic: bool)
|
||||
-> PResult<'a, Vec<Param>> {
|
||||
fn parse_fn_params(
|
||||
&mut self,
|
||||
named_params: bool,
|
||||
allow_c_variadic: bool,
|
||||
) -> PResult<'a, Vec<Param>> {
|
||||
let sp = self.token.span;
|
||||
let do_not_enforce_named_params_for_c_variadic = |token: &token::Token| {
|
||||
match token.kind {
|
||||
token::DotDotDot => false,
|
||||
_ => named_params,
|
||||
}
|
||||
};
|
||||
let mut c_variadic = false;
|
||||
let (params, _): (Vec<Option<Param>>, _) = self.parse_paren_comma_seq(|p| {
|
||||
let do_not_enforce_named_arguments_for_c_variadic =
|
||||
|token: &token::Token| -> bool {
|
||||
if token == &token::DotDotDot {
|
||||
false
|
||||
} else {
|
||||
named_params
|
||||
}
|
||||
};
|
||||
let (params, _) = self.parse_paren_comma_seq(|p| {
|
||||
match p.parse_param_general(
|
||||
false,
|
||||
false,
|
||||
allow_c_variadic,
|
||||
do_not_enforce_named_arguments_for_c_variadic
|
||||
do_not_enforce_named_params_for_c_variadic,
|
||||
) {
|
||||
Ok(param) => {
|
||||
Ok(param) => Ok(
|
||||
if let TyKind::CVarArgs = param.ty.kind {
|
||||
c_variadic = true;
|
||||
if p.token != token::CloseDelim(token::Paren) {
|
||||
let span = p.token.span;
|
||||
p.span_err(span,
|
||||
"`...` must be the last argument of a C-variadic function");
|
||||
p.span_err(
|
||||
p.token.span,
|
||||
"`...` must be the last argument of a C-variadic function",
|
||||
);
|
||||
// FIXME(eddyb) this should probably still push `CVarArgs`.
|
||||
// Maybe AST validation/HIR lowering should emit the above error?
|
||||
Ok(None)
|
||||
None
|
||||
} else {
|
||||
Ok(Some(param))
|
||||
Some(param)
|
||||
}
|
||||
} else {
|
||||
Ok(Some(param))
|
||||
Some(param)
|
||||
}
|
||||
},
|
||||
),
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
let lo = p.prev_span;
|
||||
|
|
@ -1251,124 +1147,15 @@ impl<'a> Parser<'a> {
|
|||
let params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
|
||||
|
||||
if c_variadic && params.len() <= 1 {
|
||||
self.span_err(sp,
|
||||
"C-variadic function must be declared with at least one named argument");
|
||||
self.span_err(
|
||||
sp,
|
||||
"C-variadic function must be declared with at least one named argument",
|
||||
);
|
||||
}
|
||||
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
/// Returns the parsed optional self parameter and whether a self shortcut was used.
|
||||
///
|
||||
/// See `parse_self_param_with_attrs` to collect attributes.
|
||||
fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
|
||||
let expect_ident = |this: &mut Self| match this.token.kind {
|
||||
// Preserve hygienic context.
|
||||
token::Ident(name, _) =>
|
||||
{ let span = this.token.span; this.bump(); Ident::new(name, span) }
|
||||
_ => unreachable!()
|
||||
};
|
||||
let isolated_self = |this: &mut Self, n| {
|
||||
this.look_ahead(n, |t| t.is_keyword(kw::SelfLower)) &&
|
||||
this.look_ahead(n + 1, |t| t != &token::ModSep)
|
||||
};
|
||||
|
||||
// Parse optional `self` parameter of a method.
|
||||
// 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 {
|
||||
token::BinOp(token::And) => {
|
||||
// `&self`
|
||||
// `&mut self`
|
||||
// `&'lt self`
|
||||
// `&'lt mut self`
|
||||
// `¬_self`
|
||||
(if isolated_self(self, 1) {
|
||||
self.bump();
|
||||
SelfKind::Region(None, Mutability::Immutable)
|
||||
} else if self.is_keyword_ahead(1, &[kw::Mut]) &&
|
||||
isolated_self(self, 2) {
|
||||
self.bump();
|
||||
self.bump();
|
||||
SelfKind::Region(None, Mutability::Mutable)
|
||||
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
||||
isolated_self(self, 2) {
|
||||
self.bump();
|
||||
let lt = self.expect_lifetime();
|
||||
SelfKind::Region(Some(lt), Mutability::Immutable)
|
||||
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
||||
self.is_keyword_ahead(2, &[kw::Mut]) &&
|
||||
isolated_self(self, 3) {
|
||||
self.bump();
|
||||
let lt = self.expect_lifetime();
|
||||
self.bump();
|
||||
SelfKind::Region(Some(lt), Mutability::Mutable)
|
||||
} else {
|
||||
return Ok(None);
|
||||
}, expect_ident(self), self.prev_span)
|
||||
}
|
||||
token::BinOp(token::Star) => {
|
||||
// `*self`
|
||||
// `*const self`
|
||||
// `*mut self`
|
||||
// `*not_self`
|
||||
// Emit special error for `self` cases.
|
||||
let msg = "cannot pass `self` by raw pointer";
|
||||
(if isolated_self(self, 1) {
|
||||
self.bump();
|
||||
self.struct_span_err(self.token.span, msg)
|
||||
.span_label(self.token.span, msg)
|
||||
.emit();
|
||||
SelfKind::Value(Mutability::Immutable)
|
||||
} else if self.look_ahead(1, |t| t.is_mutability()) &&
|
||||
isolated_self(self, 2) {
|
||||
self.bump();
|
||||
self.bump();
|
||||
self.struct_span_err(self.token.span, msg)
|
||||
.span_label(self.token.span, msg)
|
||||
.emit();
|
||||
SelfKind::Value(Mutability::Immutable)
|
||||
} else {
|
||||
return Ok(None);
|
||||
}, expect_ident(self), self.prev_span)
|
||||
}
|
||||
token::Ident(..) => {
|
||||
if isolated_self(self, 0) {
|
||||
// `self`
|
||||
// `self: TYPE`
|
||||
let eself_ident = expect_ident(self);
|
||||
let eself_hi = self.prev_span;
|
||||
(if self.eat(&token::Colon) {
|
||||
let ty = self.parse_ty()?;
|
||||
SelfKind::Explicit(ty, Mutability::Immutable)
|
||||
} else {
|
||||
SelfKind::Value(Mutability::Immutable)
|
||||
}, eself_ident, eself_hi)
|
||||
} else if self.token.is_keyword(kw::Mut) &&
|
||||
isolated_self(self, 1) {
|
||||
// `mut self`
|
||||
// `mut self: TYPE`
|
||||
self.bump();
|
||||
let eself_ident = expect_ident(self);
|
||||
let eself_hi = self.prev_span;
|
||||
(if self.eat(&token::Colon) {
|
||||
let ty = self.parse_ty()?;
|
||||
SelfKind::Explicit(ty, Mutability::Mutable)
|
||||
} else {
|
||||
SelfKind::Value(Mutability::Mutable)
|
||||
}, eself_ident, eself_hi)
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
let eself = source_map::respan(eself_lo.to(eself_hi), eself);
|
||||
Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
|
||||
}
|
||||
|
||||
/// Parses the parameter list and result type of a function that may have a `self` parameter.
|
||||
fn parse_fn_decl_with_self(
|
||||
&mut self,
|
||||
|
|
@ -1392,6 +1179,216 @@ impl<'a> Parser<'a> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
|
||||
/// error.
|
||||
/// This version of parse param doesn't necessarily require identifier names.
|
||||
fn parse_param_general(
|
||||
&mut self,
|
||||
is_self_allowed: bool,
|
||||
is_trait_item: bool,
|
||||
allow_c_variadic: bool,
|
||||
is_name_required: impl Fn(&token::Token) -> bool,
|
||||
) -> PResult<'a, Param> {
|
||||
let lo = self.token.span;
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
|
||||
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
|
||||
if let Some(mut param) = self.parse_self_param()? {
|
||||
param.attrs = attrs.into();
|
||||
return if is_self_allowed {
|
||||
Ok(param)
|
||||
} else {
|
||||
self.recover_bad_self_param(param, is_trait_item)
|
||||
};
|
||||
}
|
||||
|
||||
let is_name_required = is_name_required(&self.token);
|
||||
let (pat, ty) = if is_name_required || self.is_named_param() {
|
||||
debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
|
||||
|
||||
let pat = self.parse_fn_param_pat()?;
|
||||
if let Err(mut err) = self.expect(&token::Colon) {
|
||||
if let Some(ident) = self.parameter_without_type(
|
||||
&mut err,
|
||||
pat,
|
||||
is_name_required,
|
||||
is_trait_item,
|
||||
) {
|
||||
err.emit();
|
||||
return Ok(dummy_arg(ident));
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
self.eat_incorrect_doc_comment_for_param_type();
|
||||
(pat, self.parse_ty_common(true, true, allow_c_variadic)?)
|
||||
} else {
|
||||
debug!("parse_param_general ident_to_pat");
|
||||
let parser_snapshot_before_ty = self.clone();
|
||||
self.eat_incorrect_doc_comment_for_param_type();
|
||||
let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
|
||||
if ty.is_ok() && self.token != token::Comma &&
|
||||
self.token != token::CloseDelim(token::Paren) {
|
||||
// This wasn't actually a type, but a pattern looking like a type,
|
||||
// so we are going to rollback and re-parse for recovery.
|
||||
ty = self.unexpected();
|
||||
}
|
||||
match ty {
|
||||
Ok(ty) => {
|
||||
let ident = Ident::new(kw::Invalid, self.prev_span);
|
||||
let bm = BindingMode::ByValue(Mutability::Immutable);
|
||||
let pat = self.mk_pat_ident(ty.span, bm, ident);
|
||||
(pat, ty)
|
||||
}
|
||||
// If this is a C-variadic argument and we hit an error, return the error.
|
||||
Err(err) if self.token == token::DotDotDot => return Err(err),
|
||||
// Recover from attempting to parse the argument as a type without pattern.
|
||||
Err(mut err) => {
|
||||
err.cancel();
|
||||
mem::replace(self, parser_snapshot_before_ty);
|
||||
self.recover_arg_parse()?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let span = lo.to(self.token.span);
|
||||
|
||||
Ok(Param {
|
||||
attrs: attrs.into(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
pat,
|
||||
span,
|
||||
ty,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the parsed optional self parameter and whether a self shortcut was used.
|
||||
///
|
||||
/// See `parse_self_param_with_attrs` to collect attributes.
|
||||
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 {
|
||||
// Preserve hygienic context.
|
||||
token::Ident(name, _) => {
|
||||
let span = this.token.span;
|
||||
this.bump();
|
||||
Ident::new(name, span)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
// Is `self` `n` tokens ahead?
|
||||
let is_isolated_self = |this: &Self, n| {
|
||||
this.is_keyword_ahead(n, &[kw::SelfLower])
|
||||
&& this.look_ahead(n + 1, |t| t != &token::ModSep)
|
||||
};
|
||||
// Is `mut self` `n` tokens ahead?
|
||||
let is_isolated_mut_self = |this: &Self, n| {
|
||||
this.is_keyword_ahead(n, &[kw::Mut])
|
||||
&& is_isolated_self(this, n + 1)
|
||||
};
|
||||
// Parse `self` or `self: TYPE`. We already know the current token is `self`.
|
||||
let parse_self_possibly_typed = |this: &mut Self, m| {
|
||||
let eself_ident = expect_self_ident(this);
|
||||
let eself_hi = this.prev_span;
|
||||
let eself = if this.eat(&token::Colon) {
|
||||
SelfKind::Explicit(this.parse_ty()?, m)
|
||||
} else {
|
||||
SelfKind::Value(m)
|
||||
};
|
||||
Ok((eself, eself_ident, eself_hi))
|
||||
};
|
||||
// Recover for the grammar `*self`, `*const self`, and `*mut self`.
|
||||
let recover_self_ptr = |this: &mut Self| {
|
||||
let msg = "cannot pass `self` by raw pointer";
|
||||
let span = this.token.span;
|
||||
this.struct_span_err(span, msg)
|
||||
.span_label(span, msg)
|
||||
.emit();
|
||||
|
||||
Ok((SelfKind::Value(Mutability::Immutable), expect_self_ident(this), this.prev_span))
|
||||
};
|
||||
|
||||
// Parse optional `self` parameter of a method.
|
||||
// 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 {
|
||||
token::BinOp(token::And) => {
|
||||
let eself = if is_isolated_self(self, 1) {
|
||||
// `&self`
|
||||
self.bump();
|
||||
SelfKind::Region(None, Mutability::Immutable)
|
||||
} else if is_isolated_mut_self(self, 1) {
|
||||
// `&mut self`
|
||||
self.bump();
|
||||
self.bump();
|
||||
SelfKind::Region(None, Mutability::Mutable)
|
||||
} else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) {
|
||||
// `&'lt self`
|
||||
self.bump();
|
||||
let lt = self.expect_lifetime();
|
||||
SelfKind::Region(Some(lt), Mutability::Immutable)
|
||||
} else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) {
|
||||
// `&'lt mut self`
|
||||
self.bump();
|
||||
let lt = self.expect_lifetime();
|
||||
self.bump();
|
||||
SelfKind::Region(Some(lt), Mutability::Mutable)
|
||||
} else {
|
||||
// `¬_self`
|
||||
return Ok(None);
|
||||
};
|
||||
(eself, expect_self_ident(self), self.prev_span)
|
||||
}
|
||||
// `*self`
|
||||
token::BinOp(token::Star) if is_isolated_self(self, 1) => {
|
||||
self.bump();
|
||||
recover_self_ptr(self)?
|
||||
}
|
||||
// `*mut self` and `*const self`
|
||||
token::BinOp(token::Star) if
|
||||
self.look_ahead(1, |t| t.is_mutability())
|
||||
&& is_isolated_self(self, 2) =>
|
||||
{
|
||||
self.bump();
|
||||
self.bump();
|
||||
recover_self_ptr(self)?
|
||||
}
|
||||
// `self` and `self: TYPE`
|
||||
token::Ident(..) if is_isolated_self(self, 0) => {
|
||||
parse_self_possibly_typed(self, Mutability::Immutable)?
|
||||
}
|
||||
// `mut self` and `mut self: TYPE`
|
||||
token::Ident(..) if is_isolated_mut_self(self, 0) => {
|
||||
self.bump();
|
||||
parse_self_possibly_typed(self, Mutability::Mutable)?
|
||||
}
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
let eself = source_map::respan(eself_lo.to(eself_hi), eself);
|
||||
Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
|
||||
}
|
||||
|
||||
fn is_named_param(&self) -> bool {
|
||||
let offset = match self.token.kind {
|
||||
token::Interpolated(ref nt) => match **nt {
|
||||
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
|
||||
_ => 0,
|
||||
}
|
||||
token::BinOp(token::And) | token::AndAnd => 1,
|
||||
_ if self.token.is_keyword(kw::Mut) => 1,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
self.look_ahead(offset, |t| t.is_ident()) &&
|
||||
self.look_ahead(offset + 1, |t| t == &token::Colon)
|
||||
}
|
||||
|
||||
fn is_crate_vis(&self) -> bool {
|
||||
self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
|
||||
}
|
||||
|
|
@ -1423,100 +1420,107 @@ impl<'a> Parser<'a> {
|
|||
// `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`.
|
||||
// Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
|
||||
// by the following tokens.
|
||||
if self.is_keyword_ahead(1, &[kw::Crate]) &&
|
||||
self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)`
|
||||
if self.is_keyword_ahead(1, &[kw::Crate])
|
||||
&& self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)`
|
||||
{
|
||||
// `pub(crate)`
|
||||
// Parse `pub(crate)`.
|
||||
self.bump(); // `(`
|
||||
self.bump(); // `crate`
|
||||
self.expect(&token::CloseDelim(token::Paren))?; // `)`
|
||||
let vis = respan(
|
||||
lo.to(self.prev_span),
|
||||
VisibilityKind::Crate(CrateSugar::PubCrate),
|
||||
);
|
||||
return Ok(vis)
|
||||
let vis = VisibilityKind::Crate(CrateSugar::PubCrate);
|
||||
return Ok(respan(lo.to(self.prev_span), vis));
|
||||
} else if self.is_keyword_ahead(1, &[kw::In]) {
|
||||
// `pub(in path)`
|
||||
// Parse `pub(in path)`.
|
||||
self.bump(); // `(`
|
||||
self.bump(); // `in`
|
||||
let path = self.parse_path(PathStyle::Mod)?; // `path`
|
||||
self.expect(&token::CloseDelim(token::Paren))?; // `)`
|
||||
let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted {
|
||||
let vis = VisibilityKind::Restricted {
|
||||
path: P(path),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
});
|
||||
return Ok(vis)
|
||||
} else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) &&
|
||||
self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower])
|
||||
};
|
||||
return Ok(respan(lo.to(self.prev_span), vis));
|
||||
} else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren))
|
||||
&& self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower])
|
||||
{
|
||||
// `pub(self)` or `pub(super)`
|
||||
// Parse `pub(self)` or `pub(super)`.
|
||||
self.bump(); // `(`
|
||||
let path = self.parse_path(PathStyle::Mod)?; // `super`/`self`
|
||||
self.expect(&token::CloseDelim(token::Paren))?; // `)`
|
||||
let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted {
|
||||
let vis = VisibilityKind::Restricted {
|
||||
path: P(path),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
});
|
||||
return Ok(vis)
|
||||
} else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct
|
||||
// `pub(something) fn ...` or `struct X { pub(something) y: Z }`
|
||||
self.bump(); // `(`
|
||||
let msg = "incorrect visibility restriction";
|
||||
let suggestion = r##"some possible visibility restrictions are:
|
||||
`pub(crate)`: visible only on the current crate
|
||||
`pub(super)`: visible only in the current module's parent
|
||||
`pub(in path::to::module)`: visible only on the specified path"##;
|
||||
let path = self.parse_path(PathStyle::Mod)?;
|
||||
let sp = path.span;
|
||||
let help_msg = format!("make this visible only to module `{}` with `in`", path);
|
||||
self.expect(&token::CloseDelim(token::Paren))?; // `)`
|
||||
struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg)
|
||||
.help(suggestion)
|
||||
.span_suggestion(
|
||||
sp,
|
||||
&help_msg,
|
||||
format!("in {}", path),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit(); // Emit diagnostic, but continue with public visibility.
|
||||
};
|
||||
return Ok(respan(lo.to(self.prev_span), vis));
|
||||
} else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct.
|
||||
self.recover_incorrect_vis_restriction()?;
|
||||
// Emit diagnostic, but continue with public visibility.
|
||||
}
|
||||
}
|
||||
|
||||
Ok(respan(lo, VisibilityKind::Public))
|
||||
}
|
||||
|
||||
/// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }`
|
||||
fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> {
|
||||
self.bump(); // `(`
|
||||
let path = self.parse_path(PathStyle::Mod)?;
|
||||
self.expect(&token::CloseDelim(token::Paren))?; // `)`
|
||||
|
||||
let msg = "incorrect visibility restriction";
|
||||
let suggestion = r##"some possible visibility restrictions are:
|
||||
`pub(crate)`: visible only on the current crate
|
||||
`pub(super)`: visible only in the current module's parent
|
||||
`pub(in path::to::module)`: visible only on the specified path"##;
|
||||
|
||||
struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg)
|
||||
.help(suggestion)
|
||||
.span_suggestion(
|
||||
path.span,
|
||||
&format!("make this visible only to module `{}` with `in`", path),
|
||||
format!("in {}", path),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parses a string as an ABI spec on an extern type or module. Consumes
|
||||
/// the `extern` keyword, if one is found.
|
||||
fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> {
|
||||
match self.token.kind {
|
||||
token::Literal(token::Lit { kind: token::Str, symbol, suffix }) |
|
||||
token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => {
|
||||
let sp = self.token.span;
|
||||
self.expect_no_suffix(sp, "an ABI spec", suffix);
|
||||
self.expect_no_suffix(self.token.span, "an ABI spec", suffix);
|
||||
self.bump();
|
||||
match abi::lookup(&symbol.as_str()) {
|
||||
Some(abi) => Ok(Some(abi)),
|
||||
None => {
|
||||
let prev_span = self.prev_span;
|
||||
struct_span_err!(
|
||||
self.sess.span_diagnostic,
|
||||
prev_span,
|
||||
E0703,
|
||||
"invalid ABI: found `{}`",
|
||||
symbol
|
||||
)
|
||||
.span_label(prev_span, "invalid ABI")
|
||||
.help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
|
||||
.emit();
|
||||
self.error_on_invalid_abi(symbol);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit an error where `symbol` is an invalid ABI.
|
||||
fn error_on_invalid_abi(&self, symbol: Symbol) {
|
||||
let prev_span = self.prev_span;
|
||||
struct_span_err!(
|
||||
self.sess.span_diagnostic,
|
||||
prev_span,
|
||||
E0703,
|
||||
"invalid ABI: found `{}`",
|
||||
symbol
|
||||
)
|
||||
.span_label(prev_span, "invalid ABI")
|
||||
.help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
|
||||
.emit();
|
||||
}
|
||||
|
||||
/// We are parsing `async fn`. If we are on Rust 2015, emit an error.
|
||||
fn ban_async_in_2015(&self, async_span: Span) {
|
||||
if async_span.rust_2015() {
|
||||
|
|
@ -1530,9 +1534,10 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)>
|
||||
where F: FnOnce(&mut Self) -> PResult<'a, R>
|
||||
{
|
||||
fn collect_tokens<R>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut Self) -> PResult<'a, R>,
|
||||
) -> PResult<'a, (R, TokenStream)> {
|
||||
// Record all tokens we parse when parsing this item.
|
||||
let mut tokens = Vec::new();
|
||||
let prev_collecting = match self.token_cursor.frame.last_token {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::ast::{
|
|||
Item, ItemKind, ImplItem, TraitItem, TraitItemKind,
|
||||
UseTree, UseTreeKind, PathSegment,
|
||||
IsAuto, Constness, IsAsync, Unsafety, Defaultness,
|
||||
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader,
|
||||
Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block,
|
||||
ForeignItem, ForeignItemKind,
|
||||
Ty, TyKind, Generics, GenericBounds, TraitRef,
|
||||
EnumDef, VariantData, StructField, AnonConst,
|
||||
|
|
@ -18,7 +18,7 @@ use crate::parse::token;
|
|||
use crate::parse::parser::maybe_append;
|
||||
use crate::parse::diagnostics::Error;
|
||||
use crate::tokenstream::{TokenTree, TokenStream};
|
||||
use crate::source_map::{respan, Span, Spanned};
|
||||
use crate::source_map::{respan, Span};
|
||||
use crate::symbol::{kw, sym};
|
||||
|
||||
use std::mem;
|
||||
|
|
@ -122,19 +122,13 @@ impl<'a> Parser<'a> {
|
|||
if self.eat_keyword(kw::Fn) {
|
||||
// EXTERN FUNCTION ITEM
|
||||
let fn_span = self.prev_span;
|
||||
let abi = opt_abi.unwrap_or(Abi::C);
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(Unsafety::Normal,
|
||||
respan(fn_span, IsAsync::NotAsync),
|
||||
respan(fn_span, Constness::NotConst),
|
||||
abi)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let header = FnHeader {
|
||||
unsafety: Unsafety::Normal,
|
||||
asyncness: respan(fn_span, IsAsync::NotAsync),
|
||||
constness: respan(fn_span, Constness::NotConst),
|
||||
abi: opt_abi.unwrap_or(Abi::C),
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
} else if self.check(&token::OpenDelim(token::Brace)) {
|
||||
return Ok(Some(
|
||||
self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?,
|
||||
|
|
@ -149,13 +143,9 @@ impl<'a> Parser<'a> {
|
|||
// STATIC ITEM
|
||||
let m = self.parse_mutability();
|
||||
let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if self.eat_keyword(kw::Const) {
|
||||
let const_span = self.prev_span;
|
||||
|
|
@ -165,18 +155,13 @@ impl<'a> Parser<'a> {
|
|||
// CONST FUNCTION ITEM
|
||||
let unsafety = self.parse_unsafety();
|
||||
self.bump();
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(unsafety,
|
||||
respan(const_span, IsAsync::NotAsync),
|
||||
respan(const_span, Constness::Const),
|
||||
Abi::Rust)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let header = FnHeader {
|
||||
unsafety,
|
||||
asyncness: respan(const_span, IsAsync::NotAsync),
|
||||
constness: respan(const_span, Constness::Const),
|
||||
abi: Abi::Rust,
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
}
|
||||
|
||||
// CONST ITEM
|
||||
|
|
@ -193,13 +178,9 @@ impl<'a> Parser<'a> {
|
|||
.emit();
|
||||
}
|
||||
let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
|
||||
// Parses `async unsafe? fn`.
|
||||
|
|
@ -213,22 +194,18 @@ impl<'a> Parser<'a> {
|
|||
let unsafety = self.parse_unsafety(); // `unsafe`?
|
||||
self.expect_keyword(kw::Fn)?; // `fn`
|
||||
let fn_span = self.prev_span;
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(unsafety,
|
||||
respan(async_span, IsAsync::Async {
|
||||
closure_id: DUMMY_NODE_ID,
|
||||
return_impl_trait_id: DUMMY_NODE_ID,
|
||||
}),
|
||||
respan(fn_span, Constness::NotConst),
|
||||
Abi::Rust)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
let asyncness = respan(async_span, IsAsync::Async {
|
||||
closure_id: DUMMY_NODE_ID,
|
||||
return_impl_trait_id: DUMMY_NODE_ID,
|
||||
});
|
||||
self.ban_async_in_2015(async_span);
|
||||
return Ok(Some(item));
|
||||
let header = FnHeader {
|
||||
unsafety,
|
||||
asyncness,
|
||||
constness: respan(fn_span, Constness::NotConst),
|
||||
abi: Abi::Rust,
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
}
|
||||
}
|
||||
if self.check_keyword(kw::Unsafe) &&
|
||||
|
|
@ -243,15 +220,10 @@ impl<'a> Parser<'a> {
|
|||
self.expect_keyword(kw::Trait)?;
|
||||
IsAuto::Yes
|
||||
};
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_trait(is_auto, Unsafety::Unsafe)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Unsafe)?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if self.check_keyword(kw::Impl) ||
|
||||
self.check_keyword(kw::Unsafe) &&
|
||||
|
|
@ -262,27 +234,22 @@ impl<'a> Parser<'a> {
|
|||
let defaultness = self.parse_defaultness();
|
||||
let unsafety = self.parse_unsafety();
|
||||
self.expect_keyword(kw::Impl)?;
|
||||
let (ident, item, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?;
|
||||
let (ident, item_, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?;
|
||||
let span = lo.to(self.prev_span);
|
||||
return Ok(Some(self.mk_item(span, ident, item, visibility,
|
||||
maybe_append(attrs, extra_attrs))));
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if self.check_keyword(kw::Fn) {
|
||||
// FUNCTION ITEM
|
||||
self.bump();
|
||||
let fn_span = self.prev_span;
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(Unsafety::Normal,
|
||||
respan(fn_span, IsAsync::NotAsync),
|
||||
respan(fn_span, Constness::NotConst),
|
||||
Abi::Rust)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let header = FnHeader {
|
||||
unsafety: Unsafety::Normal,
|
||||
asyncness: respan(fn_span, IsAsync::NotAsync),
|
||||
constness: respan(fn_span, Constness::NotConst),
|
||||
abi: Abi::Rust,
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
}
|
||||
if self.check_keyword(kw::Unsafe)
|
||||
&& self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) {
|
||||
|
|
@ -297,30 +264,20 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
self.expect_keyword(kw::Fn)?;
|
||||
let fn_span = self.prev_span;
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_fn(Unsafety::Unsafe,
|
||||
respan(fn_span, IsAsync::NotAsync),
|
||||
respan(fn_span, Constness::NotConst),
|
||||
abi)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let header = FnHeader {
|
||||
unsafety: Unsafety::Unsafe,
|
||||
asyncness: respan(fn_span, IsAsync::NotAsync),
|
||||
constness: respan(fn_span, Constness::NotConst),
|
||||
abi,
|
||||
};
|
||||
return self.parse_item_fn(lo, visibility, attrs, header);
|
||||
}
|
||||
if self.eat_keyword(kw::Mod) {
|
||||
// MODULE ITEM
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_mod(&attrs[..])?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if let Some(type_) = self.eat_type() {
|
||||
let (ident, alias, generics) = type_?;
|
||||
|
|
@ -329,24 +286,15 @@ impl<'a> Parser<'a> {
|
|||
AliasKind::Weak(ty) => ItemKind::TyAlias(ty, generics),
|
||||
AliasKind::OpaqueTy(bounds) => ItemKind::OpaqueTy(bounds, generics),
|
||||
};
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
attrs);
|
||||
return Ok(Some(item));
|
||||
let span = lo.to(self.prev_span);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if self.eat_keyword(kw::Enum) {
|
||||
// ENUM ITEM
|
||||
let (ident, item_, extra_attrs) = self.parse_item_enum()?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if self.check_keyword(kw::Trait)
|
||||
|| (self.check_keyword(kw::Auto)
|
||||
|
|
@ -360,38 +308,25 @@ impl<'a> Parser<'a> {
|
|||
IsAuto::Yes
|
||||
};
|
||||
// TRAIT ITEM
|
||||
let (ident, item_, extra_attrs) =
|
||||
self.parse_item_trait(is_auto, Unsafety::Normal)?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Normal)?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if self.eat_keyword(kw::Struct) {
|
||||
// STRUCT ITEM
|
||||
let (ident, item_, extra_attrs) = self.parse_item_struct()?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if self.is_union_item() {
|
||||
// UNION ITEM
|
||||
self.bump();
|
||||
let (ident, item_, extra_attrs) = self.parse_item_union()?;
|
||||
let prev_span = self.prev_span;
|
||||
let item = self.mk_item(lo.to(prev_span),
|
||||
ident,
|
||||
item_,
|
||||
visibility,
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
let span = lo.to(self.prev_span);
|
||||
let attrs = maybe_append(attrs, extra_attrs);
|
||||
return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
|
||||
}
|
||||
if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? {
|
||||
return Ok(Some(macro_def));
|
||||
|
|
@ -848,29 +783,37 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Parses a method or a macro invocation in a trait impl.
|
||||
fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool)
|
||||
-> PResult<'a, (Ident, Vec<Attribute>, Generics, ast::ImplItemKind)> {
|
||||
fn parse_impl_method(
|
||||
&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!
|
||||
if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
|
||||
// method macro
|
||||
Ok((Ident::invalid(), vec![], Generics::default(),
|
||||
ast::ImplItemKind::Macro(mac)))
|
||||
Ok((Ident::invalid(), vec![], Generics::default(), ast::ImplItemKind::Macro(mac)))
|
||||
} else {
|
||||
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
|
||||
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()?;
|
||||
let (ident, sig, generics) = self.parse_method_sig(|_| true)?;
|
||||
*at_end = true;
|
||||
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(
|
||||
ast::MethodSig { header, decl },
|
||||
body
|
||||
)))
|
||||
Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, 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, mut generics) = self.parse_fn_header()?;
|
||||
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
|
||||
/// and including the `fn` keyword:
|
||||
///
|
||||
|
|
@ -879,14 +822,7 @@ impl<'a> Parser<'a> {
|
|||
/// - `const unsafe fn`
|
||||
/// - `extern fn`
|
||||
/// - etc.
|
||||
fn parse_fn_front_matter(&mut self)
|
||||
-> PResult<'a, (
|
||||
Spanned<Constness>,
|
||||
Unsafety,
|
||||
Spanned<IsAsync>,
|
||||
Abi
|
||||
)>
|
||||
{
|
||||
fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
|
||||
let is_const_fn = self.eat_keyword(kw::Const);
|
||||
let const_span = self.prev_span;
|
||||
let asyncness = self.parse_asyncness();
|
||||
|
|
@ -911,7 +847,7 @@ impl<'a> Parser<'a> {
|
|||
// account for this.
|
||||
if !self.expect_one_of(&[], &[])? { unreachable!() }
|
||||
}
|
||||
Ok((constness, unsafety, asyncness, abi))
|
||||
Ok(FnHeader { constness, unsafety, asyncness, abi })
|
||||
}
|
||||
|
||||
/// Parses `trait Foo { ... }` or `trait Foo = Bar;`.
|
||||
|
|
@ -1025,59 +961,12 @@ impl<'a> Parser<'a> {
|
|||
// trait item macro.
|
||||
(Ident::invalid(), ast::TraitItemKind::Macro(mac), Generics::default())
|
||||
} 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
|
||||
// argument names to be left off if there is a definition...
|
||||
//
|
||||
// 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())?;
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
|
||||
let sig = ast::MethodSig {
|
||||
header: FnHeader {
|
||||
unsafety,
|
||||
constness,
|
||||
abi,
|
||||
asyncness,
|
||||
},
|
||||
decl,
|
||||
};
|
||||
|
||||
let body = match self.token.kind {
|
||||
token::Semi => {
|
||||
self.bump();
|
||||
*at_end = true;
|
||||
debug!("parse_trait_methods(): parsing required method");
|
||||
None
|
||||
}
|
||||
token::OpenDelim(token::Brace) => {
|
||||
debug!("parse_trait_methods(): parsing provided method");
|
||||
*at_end = true;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(inner_attrs.iter().cloned());
|
||||
Some(body)
|
||||
}
|
||||
token::Interpolated(ref nt) => {
|
||||
match **nt {
|
||||
token::NtBlock(..) => {
|
||||
*at_end = true;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(inner_attrs.iter().cloned());
|
||||
Some(body)
|
||||
}
|
||||
_ => {
|
||||
return self.expected_semi_or_open_brace();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return self.expected_semi_or_open_brace();
|
||||
}
|
||||
};
|
||||
let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
|
||||
let body = self.parse_trait_method_body(at_end, &mut attrs)?;
|
||||
(ident, ast::TraitItemKind::Method(sig, body), generics)
|
||||
};
|
||||
|
||||
|
|
@ -1092,6 +981,43 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// 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 => {
|
||||
debug!("parse_trait_method_body(): parsing required method");
|
||||
self.bump();
|
||||
*at_end = true;
|
||||
None
|
||||
}
|
||||
token::OpenDelim(token::Brace) => {
|
||||
debug!("parse_trait_method_body(): parsing provided method");
|
||||
*at_end = true;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(inner_attrs.iter().cloned());
|
||||
Some(body)
|
||||
}
|
||||
token::Interpolated(ref nt) => {
|
||||
match **nt {
|
||||
token::NtBlock(..) => {
|
||||
*at_end = true;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
attrs.extend(inner_attrs.iter().cloned());
|
||||
Some(body)
|
||||
}
|
||||
_ => return self.expected_semi_or_open_brace(),
|
||||
}
|
||||
}
|
||||
_ => return self.expected_semi_or_open_brace(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses the following grammar:
|
||||
///
|
||||
/// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
|
||||
|
|
@ -1261,18 +1187,29 @@ impl<'a> Parser<'a> {
|
|||
/// Parses an item-position function declaration.
|
||||
fn parse_item_fn(
|
||||
&mut self,
|
||||
unsafety: Unsafety,
|
||||
asyncness: Spanned<IsAsync>,
|
||||
constness: Spanned<Constness>,
|
||||
abi: Abi
|
||||
) -> PResult<'a, ItemInfo> {
|
||||
lo: Span,
|
||||
vis: Visibility,
|
||||
attrs: Vec<Attribute>,
|
||||
header: FnHeader,
|
||||
) -> PResult<'a, Option<P<Item>>> {
|
||||
let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe;
|
||||
let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
let span = lo.to(self.prev_span);
|
||||
let kind = ItemKind::Fn(decl, header, generics, body);
|
||||
let attrs = maybe_append(attrs, Some(inner_attrs));
|
||||
Ok(Some(self.mk_item(span, ident, kind, vis, attrs)))
|
||||
}
|
||||
|
||||
/// Parse the "signature", including the identifier, parameters, and generics of a function.
|
||||
fn parse_fn_sig(
|
||||
&mut self,
|
||||
allow_c_variadic: bool,
|
||||
) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
|
||||
let (ident, mut generics) = self.parse_fn_header()?;
|
||||
let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe;
|
||||
let decl = self.parse_fn_decl(allow_c_variadic)?;
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
let header = FnHeader { unsafety, asyncness, constness, abi };
|
||||
Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
|
||||
Ok((ident, decl, generics))
|
||||
}
|
||||
|
||||
/// Parses the name and optional generic types of a function header.
|
||||
|
|
@ -1282,14 +1219,11 @@ impl<'a> Parser<'a> {
|
|||
Ok((id, generics))
|
||||
}
|
||||
|
||||
/// Parses the argument list and result type of a function declaration.
|
||||
/// Parses the parameter list and result type of a function declaration.
|
||||
fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> {
|
||||
let args = self.parse_fn_params(true, allow_c_variadic)?;
|
||||
let ret_ty = self.parse_ret_ty(true)?;
|
||||
|
||||
Ok(P(FnDecl {
|
||||
inputs: args,
|
||||
output: ret_ty,
|
||||
inputs: self.parse_fn_params(true, allow_c_variadic)?,
|
||||
output: self.parse_ret_ty(true)?,
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
@ -1397,18 +1331,15 @@ impl<'a> Parser<'a> {
|
|||
extern_sp: Span,
|
||||
) -> PResult<'a, ForeignItem> {
|
||||
self.expect_keyword(kw::Fn)?;
|
||||
|
||||
let (ident, mut generics) = self.parse_fn_header()?;
|
||||
let decl = self.parse_fn_decl(true)?;
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
let hi = self.token.span;
|
||||
let (ident, decl, generics) = self.parse_fn_sig(true)?;
|
||||
let span = lo.to(self.token.span);
|
||||
self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
|
||||
Ok(ast::ForeignItem {
|
||||
ident,
|
||||
attrs,
|
||||
kind: ForeignItemKind::Fn(decl, generics),
|
||||
id: DUMMY_NODE_ID,
|
||||
span: lo.to(hi),
|
||||
span,
|
||||
vis,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,11 +231,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
|
||||
let mutbl = if self.eat_keyword(kw::Mut) {
|
||||
Mutability::Mutable
|
||||
} else if self.eat_keyword(kw::Const) {
|
||||
Mutability::Immutable
|
||||
} else {
|
||||
let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
|
||||
let span = self.prev_span;
|
||||
let msg = "expected mut or const in raw pointer type";
|
||||
self.struct_span_err(span, msg)
|
||||
|
|
@ -243,7 +239,7 @@ impl<'a> Parser<'a> {
|
|||
.help("use `*mut T` or `*const T` as appropriate")
|
||||
.emit();
|
||||
Mutability::Immutable
|
||||
};
|
||||
});
|
||||
let t = self.parse_ty_no_plus()?;
|
||||
Ok(MutTy { ty: t, mutbl })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,18 +10,18 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
|
|||
LL | fn baz() { async fn foo() {} }
|
||||
| ^^^^^
|
||||
|
||||
error[E0670]: `async fn` is not permitted in the 2015 edition
|
||||
--> $DIR/edition-deny-async-fns-2015.rs:8:5
|
||||
|
|
||||
LL | async fn bar() {}
|
||||
| ^^^^^
|
||||
|
||||
error[E0670]: `async fn` is not permitted in the 2015 edition
|
||||
--> $DIR/edition-deny-async-fns-2015.rs:7:1
|
||||
|
|
||||
LL | async fn async_baz() {
|
||||
| ^^^^^
|
||||
|
||||
error[E0670]: `async fn` is not permitted in the 2015 edition
|
||||
--> $DIR/edition-deny-async-fns-2015.rs:8:5
|
||||
|
|
||||
LL | async fn bar() {}
|
||||
| ^^^^^
|
||||
|
||||
error[E0670]: `async fn` is not permitted in the 2015 edition
|
||||
--> $DIR/edition-deny-async-fns-2015.rs:14:5
|
||||
|
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue