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
```
This commit is contained in:
Esteban Küber 2019-05-23 12:54:27 -07:00
parent 02f5786a32
commit 976541884f
10 changed files with 80 additions and 43 deletions

View File

@ -594,6 +594,51 @@ impl<'a> Parser<'a> {
} }
} }
crate fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
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) { crate fn consume_block(&mut self, delim: token::DelimToken) {
let mut brace_depth = 0; let mut brace_depth = 0;
loop { loop {

View File

@ -1805,50 +1805,23 @@ impl<'a> Parser<'a> {
} }
/// This version of parse arg doesn't necessarily require identifier names. /// This version of parse arg doesn't necessarily require identifier names.
fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool, fn parse_arg_general(
allow_c_variadic: bool) -> PResult<'a, Arg> { &mut self,
if let Ok(Some(_)) = self.parse_self_arg() { require_name: bool,
let mut err = self.struct_span_err(self.prev_span, is_trait_item: bool,
"unexpected `self` argument in function"); allow_c_variadic: bool,
err.span_label(self.prev_span, ) -> PResult<'a, Arg> {
"`self` is only valid as the first argument of an associated function"); if let Ok(Some(arg)) = self.parse_self_arg() {
return Err(err); return self.recover_bad_self_arg(arg, is_trait_item);
} }
let (pat, ty) = if require_name || self.is_named_argument() { let (pat, ty) = if require_name || self.is_named_argument() {
debug!("parse_arg_general parse_pat (require_name:{})", debug!("parse_arg_general parse_pat (require_name:{})", require_name);
require_name);
self.eat_incorrect_doc_comment("method arguments"); self.eat_incorrect_doc_comment("method arguments");
let pat = self.parse_pat(Some("argument name"))?; let pat = self.parse_pat(Some("argument name"))?;
if let Err(mut err) = self.expect(&token::Colon) { if let Err(mut err) = self.expect(&token::Colon) {
// If we find a pattern followed by an identifier, it could be an (incorrect) self.argument_without_type(&mut err, pat, require_name, is_trait_item);
// 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("<identifier>: <type>"),
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)");
}
return Err(err); return Err(err);
} }

View File

@ -1,5 +1,6 @@
fn a(&self) { } fn a(&self) { }
//~^ ERROR unexpected `self` argument in function //~^ 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 //~| NOTE `self` is only valid as the first argument of an associated function
fn main() { } fn main() { }

View File

@ -1,8 +1,10 @@
error: unexpected `self` argument in function error: unexpected `self` argument in function
--> $DIR/bare-fn-start.rs:1:7 --> $DIR/bare-fn-start.rs:1:6
| |
LL | fn a(&self) { } 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 error: aborting due to previous error

View File

@ -1,5 +1,6 @@
fn b(foo: u32, &mut self) { } fn b(foo: u32, &mut self) { }
//~^ ERROR unexpected `self` argument in function //~^ 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 //~| NOTE `self` is only valid as the first argument of an associated function
fn main() { } fn main() { }

View File

@ -1,8 +1,10 @@
error: unexpected `self` argument in function 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) { } 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 error: aborting due to previous error

View File

@ -3,7 +3,7 @@ struct Foo {}
impl Foo { impl Foo {
fn c(foo: u32, self) {} fn c(foo: u32, self) {}
//~^ ERROR unexpected `self` argument in function //~^ 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) {} fn good(&mut self, foo: u32) {}
} }

View File

@ -2,7 +2,7 @@ error: unexpected `self` argument in function
--> $DIR/trait-fn.rs:4:20 --> $DIR/trait-fn.rs:4:20
| |
LL | fn c(foo: u32, self) {} 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 error: aborting due to previous error

View File

@ -0,0 +1,3 @@
fn foo(x:i32, self: i32) -> i32 { self } //~ ERROR unexpected `self` argument in function
fn main() {}

View File

@ -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