Skip to content

Commit 2537a8a

Browse files
committed
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<u32>)` -> `fn foo(HashMap: TypeName<u32>)`) 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 <david@davidtw.co>
1 parent ff191b5 commit 2537a8a

File tree

8 files changed

+93
-8
lines changed

8 files changed

+93
-8
lines changed

src/libsyntax/parse/diagnostics.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,7 @@ impl<'a> Parser<'a> {
12201220
err: &mut DiagnosticBuilder<'_>,
12211221
pat: P<ast::Pat>,
12221222
require_name: bool,
1223+
is_self_allowed: bool,
12231224
is_trait_item: bool,
12241225
) -> Option<Ident> {
12251226
// If we find a pattern followed by an identifier, it could be an (incorrect)
@@ -1241,22 +1242,37 @@ impl<'a> Parser<'a> {
12411242
if require_name && (
12421243
is_trait_item ||
12431244
self.token == token::Comma ||
1245+
self.token == token::Lt ||
12441246
self.token == token::CloseDelim(token::Paren)
1245-
) { // `fn foo(a, b) {}` or `fn foo(usize, usize) {}`
1246-
err.span_suggestion(
1247-
pat.span,
1248-
"if this was a parameter name, give it a type",
1249-
format!("{}: TypeName", ident),
1250-
Applicability::HasPlaceholders,
1251-
);
1247+
) { // `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}`
1248+
if is_self_allowed {
1249+
err.span_suggestion(
1250+
pat.span,
1251+
"if this is a `self` type, give it a parameter name",
1252+
format!("self: {}", ident),
1253+
Applicability::MaybeIncorrect,
1254+
);
1255+
}
1256+
// Avoid suggesting that `fn foo(HashMap<u32>)` is fixed with a change to
1257+
// `fn foo(HashMap: TypeName<u32>)`.
1258+
if self.token != token::Lt {
1259+
err.span_suggestion(
1260+
pat.span,
1261+
"if this was a parameter name, give it a type",
1262+
format!("{}: TypeName", ident),
1263+
Applicability::HasPlaceholders,
1264+
);
1265+
}
12521266
err.span_suggestion(
12531267
pat.span,
12541268
"if this is a type, explicitly ignore the parameter name",
12551269
format!("_: {}", ident),
12561270
Applicability::MachineApplicable,
12571271
);
12581272
err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
1259-
return Some(ident);
1273+
1274+
// Don't attempt to recover by using the `X` in `X<Y>` as the parameter name.
1275+
return if self.token == token::Lt { None } else { Some(ident) };
12601276
}
12611277
}
12621278
None

src/libsyntax/parse/parser.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,7 @@ impl<'a> Parser<'a> {
12121212
&mut err,
12131213
pat,
12141214
is_name_required,
1215+
is_self_allowed,
12151216
is_trait_item,
12161217
) {
12171218
err.emit();

src/test/ui/anon-params-denied-2018.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ LL | fn foo(i32);
55
| ^ expected one of `:`, `@`, or `|` here
66
|
77
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
8+
help: if this is a `self` type, give it a parameter name
9+
|
10+
LL | fn foo(self: i32);
11+
| ^^^^^^^^^
812
help: if this was a parameter name, give it a type
913
|
1014
LL | fn foo(i32: TypeName);
@@ -21,6 +25,10 @@ LL | fn bar_with_default_impl(String, String) {}
2125
| ^ expected one of `:`, `@`, or `|` here
2226
|
2327
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
28+
help: if this is a `self` type, give it a parameter name
29+
|
30+
LL | fn bar_with_default_impl(self: String, String) {}
31+
| ^^^^^^^^^^^^
2432
help: if this was a parameter name, give it a type
2533
|
2634
LL | fn bar_with_default_impl(String: TypeName, String) {}

src/test/ui/parser/pat-lt-bracket-2.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ error: expected one of `:`, `@`, or `|`, found `<`
33
|
44
LL | fn a(B<) {}
55
| ^ expected one of `:`, `@`, or `|` here
6+
|
7+
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
8+
help: if this is a type, explicitly ignore the parameter name
9+
|
10+
LL | fn a(_: B<) {}
11+
| ^^^^
612

713
error: aborting due to previous error
814

src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ LL | trait Trait2015 { fn foo(#[allow(C)] i32); }
55
| ^ expected one of `:`, `@`, or `|` here
66
|
77
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
8+
help: if this is a `self` type, give it a parameter name
9+
|
10+
LL | trait Trait2015 { fn foo(#[allow(C)] self: i32); }
11+
| ^^^^^^^^^
812
help: if this was a parameter name, give it a type
913
|
1014
LL | trait Trait2015 { fn foo(#[allow(C)] i32: TypeName); }

src/test/ui/span/issue-34264.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ error: expected one of `:`, `@`, or `|`, found `<`
33
|
44
LL | fn foo(Option<i32>, String) {}
55
| ^ expected one of `:`, `@`, or `|` here
6+
|
7+
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
8+
help: if this is a type, explicitly ignore the parameter name
9+
|
10+
LL | fn foo(_: Option<i32>, String) {}
11+
| ^^^^^^^^^
612

713
error: expected one of `:`, `@`, or `|`, found `)`
814
--> $DIR/issue-34264.rs:1:27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// This test checks that a suggestion to add a `self: ` parameter name is provided
2+
// to functions where this is applicable.
3+
4+
pub fn foo(Box<Self>) { }
5+
//~^ ERROR expected one of `:`, `@`, or `|`, found `<`
6+
7+
struct Bar;
8+
9+
impl Bar {
10+
fn bar(Box<Self>) { }
11+
//~^ ERROR expected one of `:`, `@`, or `|`, found `<`
12+
}
13+
14+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: expected one of `:`, `@`, or `|`, found `<`
2+
--> $DIR/issue-64252-self-type.rs:4:15
3+
|
4+
LL | pub fn foo(Box<Self>) { }
5+
| ^ expected one of `:`, `@`, or `|` here
6+
|
7+
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
8+
help: if this is a type, explicitly ignore the parameter name
9+
|
10+
LL | pub fn foo(_: Box<Self>) { }
11+
| ^^^^^^
12+
13+
error: expected one of `:`, `@`, or `|`, found `<`
14+
--> $DIR/issue-64252-self-type.rs:10:15
15+
|
16+
LL | fn bar(Box<Self>) { }
17+
| ^ expected one of `:`, `@`, or `|` here
18+
|
19+
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
20+
help: if this is a `self` type, give it a parameter name
21+
|
22+
LL | fn bar(self: Box<Self>) { }
23+
| ^^^^^^^^^
24+
help: if this is a type, explicitly ignore the parameter name
25+
|
26+
LL | fn bar(_: Box<Self>) { }
27+
| ^^^^^^
28+
29+
error: aborting due to 2 previous errors
30+

0 commit comments

Comments
 (0)