Recover gracefully from argument with missing type or param name
This commit is contained in:
parent
aee7012fab
commit
b3ac88ad92
11 changed files with 161 additions and 28 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use crate::ast;
|
||||
use crate::ast::{
|
||||
BlockCheckMode, BinOpKind, Expr, ExprKind, Item, ItemKind, Pat, PatKind, PathSegment, QSelf,
|
||||
Ty, TyKind, VariantData,
|
||||
Ty, TyKind, VariantData, Ident,
|
||||
};
|
||||
use crate::parse::{SeqSep, token, PResult, Parser};
|
||||
use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType};
|
||||
|
|
@ -1092,12 +1092,12 @@ impl<'a> Parser<'a> {
|
|||
pat: P<ast::Pat>,
|
||||
require_name: bool,
|
||||
is_trait_item: bool,
|
||||
) {
|
||||
) -> Option<Ident> {
|
||||
// If we find a pattern followed by an identifier, it could be an (incorrect)
|
||||
// C-style parameter declaration.
|
||||
if self.check_ident() && self.look_ahead(1, |t| {
|
||||
*t == token::Comma || *t == token::CloseDelim(token::Paren)
|
||||
}) {
|
||||
}) { // `fn foo(String s) {}`
|
||||
let ident = self.parse_ident().unwrap();
|
||||
let span = pat.span.with_hi(ident.span.hi());
|
||||
|
||||
|
|
@ -1107,18 +1107,30 @@ impl<'a> Parser<'a> {
|
|||
String::from("<identifier>: <type>"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else if require_name && is_trait_item {
|
||||
if let PatKind::Ident(_, ident, _) = pat.node {
|
||||
return Some(ident);
|
||||
} else if let PatKind::Ident(_, ident, _) = pat.node {
|
||||
if require_name && (
|
||||
is_trait_item ||
|
||||
self.token == token::Comma ||
|
||||
self.token == token::CloseDelim(token::Paren)
|
||||
) { // `fn foo(a, b) {}` or `fn foo(usize, usize) {}`
|
||||
err.span_suggestion(
|
||||
pat.span,
|
||||
"explicitly ignore parameter",
|
||||
"if this was a parameter name, give it a type",
|
||||
format!("{}: TypeName", ident),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
err.span_suggestion(
|
||||
pat.span,
|
||||
"if this is a type, explicitly ignore the parameter name",
|
||||
format!("_: {}", ident),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
|
||||
return Some(ident);
|
||||
}
|
||||
|
||||
err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
crate fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
|
||||
|
|
|
|||
|
|
@ -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)?,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue