From 2537a8aa7a44d76b3345b98f394f6d2744f3a9cc Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 1 Oct 2019 15:17:50 +0100 Subject: [PATCH] syntax: improve parameter without type suggestions This commit improves the suggestions provided when function parameters do not have types: - A new suggestion is added for arbitrary self types, which suggests adding `self: ` before the type. - Existing suggestions are now provided when a `<` is found where a `:` was expected (previously only `,` and `)` or trait items), this gives suggestions in the case where the unnamed parameter type is generic in a free function. - The suggestion that a type name be provided (e.g. `fn foo(HashMap)` -> `fn foo(HashMap: TypeName)`) will no longer occur when a `<` was found instead of `:`. - The ident will not be used for recovery when a `<` was found instead of `:`. Signed-off-by: David Wood --- src/libsyntax/parse/diagnostics.rs | 32 ++++++++++++++----- src/libsyntax/parse/parser.rs | 1 + src/test/ui/anon-params-denied-2018.stderr | 8 +++++ src/test/ui/parser/pat-lt-bracket-2.stderr | 6 ++++ .../param-attrs-2018.stderr | 4 +++ src/test/ui/span/issue-34264.stderr | 6 ++++ .../ui/suggestions/issue-64252-self-type.rs | 14 ++++++++ .../suggestions/issue-64252-self-type.stderr | 30 +++++++++++++++++ 8 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/suggestions/issue-64252-self-type.rs create mode 100644 src/test/ui/suggestions/issue-64252-self-type.stderr diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index e8d7b7663ed52..4ad0bd06d99ae 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1220,6 +1220,7 @@ impl<'a> Parser<'a> { err: &mut DiagnosticBuilder<'_>, pat: P, require_name: bool, + is_self_allowed: bool, is_trait_item: bool, ) -> Option { // If we find a pattern followed by an identifier, it could be an (incorrect) @@ -1241,14 +1242,27 @@ impl<'a> Parser<'a> { if require_name && ( is_trait_item || self.token == token::Comma || + self.token == token::Lt || 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, - ); + ) { // `fn foo(a, b) {}`, `fn foo(a, b) {}` or `fn foo(usize, usize) {}` + if is_self_allowed { + err.span_suggestion( + pat.span, + "if this is a `self` type, give it a parameter name", + format!("self: {}", ident), + Applicability::MaybeIncorrect, + ); + } + // Avoid suggesting that `fn foo(HashMap)` is fixed with a change to + // `fn foo(HashMap: TypeName)`. + if self.token != token::Lt { + 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, "if this is a type, explicitly ignore the parameter name", @@ -1256,7 +1270,9 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); - return Some(ident); + + // Don't attempt to recover by using the `X` in `X` as the parameter name. + return if self.token == token::Lt { None } else { Some(ident) }; } } None diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 95f84d5cb3314..d4a6e9f6c6bc8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1212,6 +1212,7 @@ impl<'a> Parser<'a> { &mut err, pat, is_name_required, + is_self_allowed, is_trait_item, ) { err.emit(); diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params-denied-2018.stderr index a58998e4891e0..3fcf41a9a60a2 100644 --- a/src/test/ui/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params-denied-2018.stderr @@ -5,6 +5,10 @@ LL | fn foo(i32); | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | fn foo(self: i32); + | ^^^^^^^^^ help: if this was a parameter name, give it a type | LL | fn foo(i32: TypeName); @@ -21,6 +25,10 @@ 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 is a `self` type, give it a parameter name + | +LL | fn bar_with_default_impl(self: String, String) {} + | ^^^^^^^^^^^^ help: if this was a parameter name, give it a type | LL | fn bar_with_default_impl(String: TypeName, String) {} diff --git a/src/test/ui/parser/pat-lt-bracket-2.stderr b/src/test/ui/parser/pat-lt-bracket-2.stderr index dbc8d0f5865c6..2191e31ad1ff2 100644 --- a/src/test/ui/parser/pat-lt-bracket-2.stderr +++ b/src/test/ui/parser/pat-lt-bracket-2.stderr @@ -3,6 +3,12 @@ error: expected one of `:`, `@`, or `|`, found `<` | LL | fn a(B<) {} | ^ expected one of `:`, `@`, or `|` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a type, explicitly ignore the parameter name + | +LL | fn a(_: B<) {} + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr index 9860e9805b2ed..e4248f3b974b9 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -5,6 +5,10 @@ LL | trait Trait2015 { fn foo(#[allow(C)] i32); } | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | trait Trait2015 { fn foo(#[allow(C)] self: i32); } + | ^^^^^^^^^ help: if this was a parameter name, give it a type | LL | trait Trait2015 { fn foo(#[allow(C)] i32: TypeName); } diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index cc0eccd37a26f..8d4a66f142d2c 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -3,6 +3,12 @@ error: expected one of `:`, `@`, or `|`, found `<` | LL | fn foo(Option, String) {} | ^ expected one of `:`, `@`, or `|` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a type, explicitly ignore the parameter name + | +LL | fn foo(_: Option, String) {} + | ^^^^^^^^^ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/issue-34264.rs:1:27 diff --git a/src/test/ui/suggestions/issue-64252-self-type.rs b/src/test/ui/suggestions/issue-64252-self-type.rs new file mode 100644 index 0000000000000..128d5e85c22c8 --- /dev/null +++ b/src/test/ui/suggestions/issue-64252-self-type.rs @@ -0,0 +1,14 @@ +// This test checks that a suggestion to add a `self: ` parameter name is provided +// to functions where this is applicable. + +pub fn foo(Box) { } +//~^ ERROR expected one of `:`, `@`, or `|`, found `<` + +struct Bar; + +impl Bar { + fn bar(Box) { } + //~^ ERROR expected one of `:`, `@`, or `|`, found `<` +} + +fn main() { } diff --git a/src/test/ui/suggestions/issue-64252-self-type.stderr b/src/test/ui/suggestions/issue-64252-self-type.stderr new file mode 100644 index 0000000000000..fa28a0d684e5e --- /dev/null +++ b/src/test/ui/suggestions/issue-64252-self-type.stderr @@ -0,0 +1,30 @@ +error: expected one of `:`, `@`, or `|`, found `<` + --> $DIR/issue-64252-self-type.rs:4:15 + | +LL | pub fn foo(Box) { } + | ^ expected one of `:`, `@`, or `|` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a type, explicitly ignore the parameter name + | +LL | pub fn foo(_: Box) { } + | ^^^^^^ + +error: expected one of `:`, `@`, or `|`, found `<` + --> $DIR/issue-64252-self-type.rs:10:15 + | +LL | fn bar(Box) { } + | ^ expected one of `:`, `@`, or `|` here + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | fn bar(self: Box) { } + | ^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn bar(_: Box) { } + | ^^^^^^ + +error: aborting due to 2 previous errors +