Recover gracefully from argument with missing type or param name

This commit is contained in:
Esteban Küber
2019-05-29 15:25:46 -07:00
parent aee7012fab
commit b3ac88ad92
11 changed files with 161 additions and 28 deletions

View File

@@ -51,6 +51,7 @@ use crate::parse::diagnostics::Error;
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
use rustc_target::spec::abi::{self, Abi};
use rustc_data_structures::fx::FxHashSet;
use syntax_pos::{Span, BytePos, DUMMY_SP, FileName, hygiene::CompilerDesugaringKind};
use log::debug;
@@ -452,19 +453,18 @@ impl From<P<Expr>> for LhsExpr {
}
/// Creates a placeholder argument.
fn dummy_arg(span: Span) -> Arg {
let ident = Ident::new(kw::Invalid, span);
fn dummy_arg(ident: Ident) -> Arg {
let pat = P(Pat {
id: ast::DUMMY_NODE_ID,
node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None),
span,
span: ident.span,
});
let ty = Ty {
node: TyKind::Err,
span,
span: ident.span,
id: ast::DUMMY_NODE_ID
};
Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal }
Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Recovery }
}
#[derive(Copy, Clone, Debug)]
@@ -1528,8 +1528,17 @@ impl<'a> Parser<'a> {
let pat = self.parse_pat(Some("argument name"))?;
if let Err(mut err) = self.expect(&token::Colon) {
self.argument_without_type(&mut err, pat, require_name, is_trait_item);
return Err(err);
if let Some(ident) = self.argument_without_type(
&mut err,
pat,
require_name,
is_trait_item,
) {
err.emit();
return Ok(dummy_arg(ident));
} else {
return Err(err);
}
}
self.eat_incorrect_doc_comment("a method argument's type");
@@ -5431,7 +5440,7 @@ impl<'a> Parser<'a> {
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
// Create a placeholder argument for proper arg count (issue #34264).
let span = lo.to(p.prev_span);
Ok(Some(dummy_arg(span)))
Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
}
}
}
@@ -5584,7 +5593,7 @@ impl<'a> Parser<'a> {
// Parse the rest of the function parameter list.
let sep = SeqSep::trailing_allowed(token::Comma);
let (fn_inputs, recovered) = if let Some(self_arg) = self_arg {
let (mut fn_inputs, recovered) = if let Some(self_arg) = self_arg {
if self.check(&token::CloseDelim(token::Paren)) {
(vec![self_arg], false)
} else if self.eat(&token::Comma) {
@@ -5607,6 +5616,24 @@ impl<'a> Parser<'a> {
// Parse closing paren and return type.
self.expect(&token::CloseDelim(token::Paren))?;
}
// Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors.
let mut seen_inputs = FxHashSet::default();
for input in fn_inputs.iter_mut() {
let opt_ident = if let (PatKind::Ident(_, ident, _), ast::ArgSource::Recovery) = (
&input.pat.node, &input.source,
) {
Some(*ident)
} else {
None
};
if let Some(ident) = opt_ident {
if seen_inputs.contains(&ident) {
input.pat.node = PatKind::Wild;
}
seen_inputs.insert(ident);
}
}
Ok(P(FnDecl {
inputs: fn_inputs,
output: self.parse_ret_ty(true)?,