From 976541884f674127c33e08aaaf15c99b735701f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 May 2019 12:54:27 -0700 Subject: [PATCH] Tweak `self` arg not as first argument of a method diagnostic Mention that `self` is only valid on "associated functions" ``` error: unexpected `self` argument in function --> $DIR/self-in-function-arg.rs:1:15 | LL | fn foo(x:i32, self: i32) -> i32 { self } | ^^^^ not valid as function argument | = note: `self` is only valid as the first argument of an associated function ``` When it is a method, mention it must be first ``` error: unexpected `self` argument in function --> $DIR/trait-fn.rs:4:20 | LL | fn c(foo: u32, self) {} | ^^^^ must be the first associated function argument ``` --- src/libsyntax/parse/diagnostics.rs | 45 ++++++++++++++++++ src/libsyntax/parse/parser.rs | 47 ++++--------------- .../ui/invalid-self-argument/bare-fn-start.rs | 1 + .../bare-fn-start.stderr | 6 ++- src/test/ui/invalid-self-argument/bare-fn.rs | 1 + .../ui/invalid-self-argument/bare-fn.stderr | 6 ++- src/test/ui/invalid-self-argument/trait-fn.rs | 2 +- .../ui/invalid-self-argument/trait-fn.stderr | 2 +- src/test/ui/parser/self-in-function-arg.rs | 3 ++ .../ui/parser/self-in-function-arg.stderr | 10 ++++ 10 files changed, 80 insertions(+), 43 deletions(-) create mode 100644 src/test/ui/parser/self-in-function-arg.rs create mode 100644 src/test/ui/parser/self-in-function-arg.stderr diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 810acc9cc92..11f8eba033e 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -594,6 +594,51 @@ impl<'a> Parser<'a> { } } + crate fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { + let pat = self.parse_pat(Some("argument name"))?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + + let mut err = self.diagnostic().struct_span_err_with_code( + pat.span, + "patterns aren't allowed in methods without bodies", + DiagnosticId::Error("E0642".into()), + ); + err.span_suggestion_short( + pat.span, + "give this argument a name or use an underscore to ignore it", + "_".to_owned(), + Applicability::MachineApplicable, + ); + err.emit(); + + // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. + let pat = P(Pat { + node: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID + }); + Ok((pat, ty)) + } + + crate fn recover_bad_self_arg( + &mut self, + mut arg: ast::Arg, + is_trait_item: bool, + ) -> PResult<'a, ast::Arg> { + let sp = arg.pat.span; + arg.ty.node = TyKind::Err; + let mut err = self.struct_span_err(sp, "unexpected `self` argument in function"); + if is_trait_item { + err.span_label(sp, "must be the first associated function argument"); + } else { + err.span_label(sp, "not valid as function argument"); + err.note("`self` is only valid as the first argument of an associated function"); + } + err.emit(); + Ok(arg) + } + crate fn consume_block(&mut self, delim: token::DelimToken) { let mut brace_depth = 0; loop { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 56951ae0801..b4b45fd9eff 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1805,50 +1805,23 @@ impl<'a> Parser<'a> { } /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool, - allow_c_variadic: bool) -> PResult<'a, Arg> { - if let Ok(Some(_)) = self.parse_self_arg() { - let mut err = self.struct_span_err(self.prev_span, - "unexpected `self` argument in function"); - err.span_label(self.prev_span, - "`self` is only valid as the first argument of an associated function"); - return Err(err); + fn parse_arg_general( + &mut self, + require_name: bool, + is_trait_item: bool, + allow_c_variadic: bool, + ) -> PResult<'a, Arg> { + if let Ok(Some(arg)) = self.parse_self_arg() { + return self.recover_bad_self_arg(arg, is_trait_item); } let (pat, ty) = if require_name || self.is_named_argument() { - debug!("parse_arg_general parse_pat (require_name:{})", - require_name); + debug!("parse_arg_general parse_pat (require_name:{})", require_name); self.eat_incorrect_doc_comment("method arguments"); let pat = self.parse_pat(Some("argument name"))?; if let Err(mut err) = self.expect(&token::Colon) { - // 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) - }) { - let ident = self.parse_ident().unwrap(); - let span = pat.span.with_hi(ident.span.hi()); - - err.span_suggestion( - span, - "declare the type after the parameter binding", - String::from(": "), - Applicability::HasPlaceholders, - ); - } else if require_name && is_trait_item { - if let PatKind::Ident(_, ident, _) = pat.node { - err.span_suggestion( - pat.span, - "explicitly ignore parameter", - format!("_: {}", ident), - Applicability::MachineApplicable, - ); - } - - err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); - } - + self.argument_without_type(&mut err, pat, require_name, is_trait_item); return Err(err); } diff --git a/src/test/ui/invalid-self-argument/bare-fn-start.rs b/src/test/ui/invalid-self-argument/bare-fn-start.rs index 741ba5f41ce..95a2b69c05c 100644 --- a/src/test/ui/invalid-self-argument/bare-fn-start.rs +++ b/src/test/ui/invalid-self-argument/bare-fn-start.rs @@ -1,5 +1,6 @@ fn a(&self) { } //~^ ERROR unexpected `self` argument in function +//~| NOTE not valid as function argument //~| NOTE `self` is only valid as the first argument of an associated function fn main() { } diff --git a/src/test/ui/invalid-self-argument/bare-fn-start.stderr b/src/test/ui/invalid-self-argument/bare-fn-start.stderr index 6a878b619d8..ba1092ca377 100644 --- a/src/test/ui/invalid-self-argument/bare-fn-start.stderr +++ b/src/test/ui/invalid-self-argument/bare-fn-start.stderr @@ -1,8 +1,10 @@ error: unexpected `self` argument in function - --> $DIR/bare-fn-start.rs:1:7 + --> $DIR/bare-fn-start.rs:1:6 | LL | fn a(&self) { } - | ^^^^ `self` is only valid as the first argument of an associated function + | ^^^^^ not valid as function argument + | + = note: `self` is only valid as the first argument of an associated function error: aborting due to previous error diff --git a/src/test/ui/invalid-self-argument/bare-fn.rs b/src/test/ui/invalid-self-argument/bare-fn.rs index 704fa996ca6..43c87fb79d8 100644 --- a/src/test/ui/invalid-self-argument/bare-fn.rs +++ b/src/test/ui/invalid-self-argument/bare-fn.rs @@ -1,5 +1,6 @@ fn b(foo: u32, &mut self) { } //~^ ERROR unexpected `self` argument in function +//~| NOTE not valid as function argument //~| NOTE `self` is only valid as the first argument of an associated function fn main() { } diff --git a/src/test/ui/invalid-self-argument/bare-fn.stderr b/src/test/ui/invalid-self-argument/bare-fn.stderr index b13f746a4ec..16a2d4b4b37 100644 --- a/src/test/ui/invalid-self-argument/bare-fn.stderr +++ b/src/test/ui/invalid-self-argument/bare-fn.stderr @@ -1,8 +1,10 @@ error: unexpected `self` argument in function - --> $DIR/bare-fn.rs:1:21 + --> $DIR/bare-fn.rs:1:16 | LL | fn b(foo: u32, &mut self) { } - | ^^^^ `self` is only valid as the first argument of an associated function + | ^^^^^^^^^ not valid as function argument + | + = note: `self` is only valid as the first argument of an associated function error: aborting due to previous error diff --git a/src/test/ui/invalid-self-argument/trait-fn.rs b/src/test/ui/invalid-self-argument/trait-fn.rs index 31e867bc764..620a06db557 100644 --- a/src/test/ui/invalid-self-argument/trait-fn.rs +++ b/src/test/ui/invalid-self-argument/trait-fn.rs @@ -3,7 +3,7 @@ struct Foo {} impl Foo { fn c(foo: u32, self) {} //~^ ERROR unexpected `self` argument in function - //~| NOTE `self` is only valid as the first argument of an associated function + //~| NOTE must be the first associated function argument fn good(&mut self, foo: u32) {} } diff --git a/src/test/ui/invalid-self-argument/trait-fn.stderr b/src/test/ui/invalid-self-argument/trait-fn.stderr index b3c2cc5b5eb..00fedea3fea 100644 --- a/src/test/ui/invalid-self-argument/trait-fn.stderr +++ b/src/test/ui/invalid-self-argument/trait-fn.stderr @@ -2,7 +2,7 @@ error: unexpected `self` argument in function --> $DIR/trait-fn.rs:4:20 | LL | fn c(foo: u32, self) {} - | ^^^^ `self` is only valid as the first argument of an associated function + | ^^^^ must be the first associated function argument error: aborting due to previous error diff --git a/src/test/ui/parser/self-in-function-arg.rs b/src/test/ui/parser/self-in-function-arg.rs new file mode 100644 index 00000000000..502c2c0b74a --- /dev/null +++ b/src/test/ui/parser/self-in-function-arg.rs @@ -0,0 +1,3 @@ +fn foo(x:i32, self: i32) -> i32 { self } //~ ERROR unexpected `self` argument in function + +fn main() {} diff --git a/src/test/ui/parser/self-in-function-arg.stderr b/src/test/ui/parser/self-in-function-arg.stderr new file mode 100644 index 00000000000..e1fc10306cc --- /dev/null +++ b/src/test/ui/parser/self-in-function-arg.stderr @@ -0,0 +1,10 @@ +error: unexpected `self` argument in function + --> $DIR/self-in-function-arg.rs:1:15 + | +LL | fn foo(x:i32, self: i32) -> i32 { self } + | ^^^^ not valid as function argument + | + = note: `self` is only valid as the first argument of an associated function + +error: aborting due to previous error +