Tweak invalid fn header and body parsing

* Recover empty `fn` bodies when encountering `}`
* Recover trailing `>` in return types
* Recover from non-type in array type `[<BAD TOKEN>; LEN]`
This commit is contained in:
Esteban Küber 2020-10-25 14:20:44 -07:00
parent 040f568815
commit ff61949860
7 changed files with 53 additions and 27 deletions

View file

@ -1538,7 +1538,7 @@ impl<'a> Parser<'a> {
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, &mut sig_hi)?; // `;` or `{ ... }`.
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`.
let fn_sig_span = sig_lo.to(sig_hi);
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
}
@ -1549,6 +1549,7 @@ impl<'a> Parser<'a> {
fn parse_fn_body(
&mut self,
attrs: &mut Vec<Attribute>,
ident: &Ident,
sig_hi: &mut Span,
) -> PResult<'a, Option<P<Block>>> {
let (inner_attrs, body) = if self.eat(&token::Semi) {
@ -1573,9 +1574,21 @@ impl<'a> Parser<'a> {
.emit();
(Vec::new(), Some(self.mk_block_err(span)))
} else {
return self
.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
.map(|_| None);
if let Err(mut err) =
self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
{
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.
err.span_label(ident.span, "while parsing this `fn`");
err.emit();
(Vec::new(), None)
} else {
return Err(err);
}
} else {
unreachable!()
}
};
attrs.extend(inner_attrs);
Ok(body)
@ -1653,10 +1666,19 @@ impl<'a> Parser<'a> {
req_name: ReqName,
ret_allow_plus: AllowPlus,
) -> PResult<'a, P<FnDecl>> {
Ok(P(FnDecl {
inputs: self.parse_fn_params(req_name)?,
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
}))
let inputs = self.parse_fn_params(req_name)?;
let output = self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?;
if let ast::FnRetTy::Ty(ty) = &output {
if let TyKind::Path(_, Path { segments, .. }) = &ty.kind {
if let [.., last] = &segments[..] {
// Detect and recover `fn foo() -> Vec<i32>> {}`
self.check_trailing_angle_brackets(last, &[&token::OpenDelim(token::Brace)]);
}
}
}
Ok(P(FnDecl { inputs, output }))
}
/// Parses the parameter list of a function, including the `(` and `)` delimiters.

View file

@ -265,7 +265,19 @@ impl<'a> Parser<'a> {
/// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type.
/// The opening `[` bracket is already eaten.
fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
let elt_ty = self.parse_ty()?;
let elt_ty = match self.parse_ty() {
Ok(ty) => ty,
Err(mut err)
if self.look_ahead(1, |t| t.kind == token::CloseDelim(token::Bracket))
| self.look_ahead(1, |t| t.kind == token::Semi) =>
{
// Recover from `[LIT; EXPR]` and `[LIT]`
self.bump();
err.emit();
self.mk_ty(self.prev_token.span, TyKind::Err)
}
Err(err) => return Err(err),
};
let ty = if self.eat(&token::Semi) {
TyKind::Array(elt_ty, self.parse_anon_const_expr()?)
} else {