fn lower_arg_source(&mut self, source: &ArgSource) -> hir::ArgSource {
match source {
- ArgSource::Normal => hir::ArgSource::Normal,
+ ArgSource::Normal | ArgSource::Recovery => hir::ArgSource::Normal,
ArgSource::AsyncFn(pat) => hir::ArgSource::AsyncFn(self.lower_pat(pat)),
}
}
Normal,
/// Argument from `async fn` lowering, contains the original binding pattern.
AsyncFn(P<Pat>),
+ /// Placeholder argument caused by incorrect syntax. Used to silence unecessary errors.
+ Recovery,
}
/// Alternative representation for `Arg`s describing `self` parameter of methods.
pub fn noop_visit_arg_source<T: MutVisitor>(source: &mut ArgSource, vis: &mut T) {
match source {
- ArgSource::Normal => {},
+ ArgSource::Normal | ArgSource::Recovery => {},
ArgSource::AsyncFn(pat) => vis.visit_pat(pat),
}
}
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};
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());
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,
+ "if this was a parameter name, give it a type",
+ format!("{}: TypeName", ident),
+ Applicability::HasPlaceholders,
+ );
err.span_suggestion(
pat.span,
- "explicitly ignore parameter",
+ "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>)> {
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;
}
/// 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)]
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");
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))))
}
}
}
// 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) {
// 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)?,
fn foo(i32); //~ expected one of `:` or `@`, found `)`
fn bar_with_default_impl(String, String) {}
- //~^ ERROR expected one of `:` or `@`, found `,`
+ //~^ ERROR expected one of `:`
+ //~| ERROR expected one of `:`
+
+ // do not complain about missing `b`
+ fn baz(a:usize, b, c: usize) -> usize { //~ ERROR expected one of `:`
+ a + b + c
+ }
}
fn main() {}
--> $DIR/anon-params-denied-2018.rs:6:15
|
LL | fn foo(i32);
- | ---^ expected one of `:` or `@` here
- | |
- | help: explicitly ignore parameter: `_: i32`
+ | ^ expected one of `:` or `@` here
|
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn foo(i32: TypeName);
+ | ^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn foo(_: i32);
+ | ^^^^^^
error: expected one of `:` or `@`, found `,`
--> $DIR/anon-params-denied-2018.rs:8:36
|
LL | fn bar_with_default_impl(String, String) {}
- | ------^ expected one of `:` or `@` here
- | |
- | help: explicitly ignore parameter: `_: String`
+ | ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn bar_with_default_impl(String: TypeName, String) {}
+ | ^^^^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn bar_with_default_impl(_: String, String) {}
+ | ^^^^^^^^^
+
+error: expected one of `:` or `@`, found `)`
+ --> $DIR/anon-params-denied-2018.rs:8:44
+ |
+LL | fn bar_with_default_impl(String, String) {}
+ | ^ expected one of `:` or `@` here
|
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn bar_with_default_impl(String, String: TypeName) {}
+ | ^^^^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn bar_with_default_impl(String, _: String) {}
+ | ^^^^^^^^^
+
+error: expected one of `:` or `@`, found `,`
+ --> $DIR/anon-params-denied-2018.rs:13:22
+ |
+LL | fn baz(a:usize, b, c: usize) -> usize {
+ | ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn baz(a:usize, b: TypeName, c: usize) -> usize {
+ | ^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn baz(a:usize, _: b, c: usize) -> usize {
+ | ^^^^
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
fn fizz(i32) {}
//~^ ERROR expected one of `:` or `@`
+//~| HELP if this was a parameter name, give it a type
+//~| HELP if this is a type, explicitly ignore the parameter name
fn missing_colon(quux S) {}
//~^ ERROR expected one of `:` or `@`
|
LL | fn fizz(i32) {}
| ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn fizz(i32: TypeName) {}
+ | ^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn fizz(_: i32) {}
+ | ^^^^^^
error: expected one of `:` or `@`, found `S`
- --> $DIR/inverted-parameters.rs:24:23
+ --> $DIR/inverted-parameters.rs:26:23
|
LL | fn missing_colon(quux S) {}
| -----^
|
LL | fn foo(x) {
| ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn foo(x: TypeName) {
+ | ^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn foo(_: x) {
+ | ^^^^
error: aborting due to previous error
|
LL | fn foo(Option<i32>, String) {}
| ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn foo(Option<i32>, String: TypeName) {}
+ | ^^^^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn foo(Option<i32>, _: String) {}
+ | ^^^^^^^^^
error: expected one of `:` or `@`, found `,`
--> $DIR/issue-34264.rs:3:9
|
LL | fn bar(x, y: usize) {}
| ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn bar(x: TypeName, y: usize) {}
+ | ^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn bar(_: x, y: usize) {}
+ | ^^^^
error[E0061]: this function takes 2 parameters but 3 parameters were supplied
--> $DIR/issue-34264.rs:7:5