diff options
| author | Yuki Okushi <huyuumi.dev@gmail.com> | 2021-03-17 15:20:48 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-17 15:20:48 +0900 |
| commit | a16db3dcda83dec3e7a46f2e6028a5b8eb7cec80 (patch) | |
| tree | aa4aec9d3b87b15b3bb5379543114e79e369dabb | |
| parent | e655fb62216b6ba64a094b30f116d7988d19322d (diff) | |
| parent | 55bdf7f188f1a6ded58b2e28bc2c783ee75b1a60 (diff) | |
| download | rust-a16db3dcda83dec3e7a46f2e6028a5b8eb7cec80.tar.gz rust-a16db3dcda83dec3e7a46f2e6028a5b8eb7cec80.zip | |
Rollup merge of #82774 - JohnTitor:bad-diag-for-anon-params-with-ref, r=estebank
Fix bad diagnostics for anon params with ref and/or qualified paths Fixes #82729 It's easier to review with hiding whitespace changes.
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 104 | ||||
| -rw-r--r-- | src/test/ui/anon-params/anon-params-denied-2018.rs | 14 | ||||
| -rw-r--r-- | src/test/ui/anon-params/anon-params-denied-2018.stderr | 76 | ||||
| -rw-r--r-- | src/test/ui/parser/lifetime-in-pattern.stderr | 14 |
4 files changed, 172 insertions, 36 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f4ab3260d1a..77e85c06ff5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -640,7 +640,7 @@ impl<'a> Parser<'a> { } } Err(mut err) => { - // We could't parse generic parameters, unlikely to be a turbofish. Rely on + // We couldn't parse generic parameters, unlikely to be a turbofish. Rely on // generic parse error instead. err.cancel(); *self = snapshot; @@ -1242,7 +1242,7 @@ impl<'a> Parser<'a> { let is_question = self.eat(&token::Question); // Handle `await? <expr>`. let expr = if self.token == token::OpenDelim(token::Brace) { // Handle `await { <expr> }`. - // This needs to be handled separatedly from the next arm to avoid + // This needs to be handled separately from the next arm to avoid // interpreting `await { <expr> }?` as `<expr>?.await`. self.parse_block_expr(None, self.token.span, BlockCheckMode::Default, AttrVec::new()) } else { @@ -1613,42 +1613,82 @@ impl<'a> Parser<'a> { Applicability::HasPlaceholders, ); return Some(ident); - } else if let PatKind::Ident(_, ident, _) = pat.kind { - if require_name - && (self.token == token::Comma - || self.token == token::Lt - || self.token == token::CloseDelim(token::Paren)) - { - // `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}` - if first_param { - err.span_suggestion( - pat.span, - "if this is a `self` type, give it a parameter name", - format!("self: {}", ident), - Applicability::MaybeIncorrect, - ); + } else if require_name + && (self.token == token::Comma + || self.token == token::Lt + || self.token == token::CloseDelim(token::Paren)) + { + let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)"; + + let (ident, self_sugg, param_sugg, type_sugg) = match pat.kind { + PatKind::Ident(_, ident, _) => ( + ident, + format!("self: {}", ident), + format!("{}: TypeName", ident), + format!("_: {}", ident), + ), + // Also catches `fn foo(&a)`. + PatKind::Ref(ref pat, mutab) + if matches!(pat.clone().into_inner().kind, PatKind::Ident(..)) => + { + match pat.clone().into_inner().kind { + PatKind::Ident(_, ident, _) => { + let mutab = mutab.prefix_str(); + ( + ident, + format!("self: &{}{}", mutab, ident), + format!("{}: &{}TypeName", ident, mutab), + format!("_: &{}{}", mutab, ident), + ) + } + _ => unreachable!(), + } } - // Avoid suggesting that `fn foo(HashMap<u32>)` is fixed with a change to - // `fn foo(HashMap: TypeName<u32>)`. - if self.token != token::Lt { - err.span_suggestion( - pat.span, - "if this is a parameter name, give it a type", - format!("{}: TypeName", ident), - Applicability::HasPlaceholders, - ); + _ => { + // Otherwise, try to get a type and emit a suggestion. + if let Some(ty) = pat.to_ty() { + err.span_suggestion_verbose( + pat.span, + "explicitly ignore the parameter name", + format!("_: {}", pprust::ty_to_string(&ty)), + Applicability::MachineApplicable, + ); + err.note(rfc_note); + } + + return None; } + }; + + // `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}` + if first_param { err.span_suggestion( pat.span, - "if this is a type, explicitly ignore the parameter name", - format!("_: {}", ident), - Applicability::MachineApplicable, + "if this is a `self` type, give it a parameter name", + self_sugg, + Applicability::MaybeIncorrect, ); - err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); - - // Don't attempt to recover by using the `X` in `X<Y>` as the parameter name. - return if self.token == token::Lt { None } else { Some(ident) }; } + // Avoid suggesting that `fn foo(HashMap<u32>)` is fixed with a change to + // `fn foo(HashMap: TypeName<u32>)`. + if self.token != token::Lt { + err.span_suggestion( + pat.span, + "if this is a parameter name, give it a type", + param_sugg, + Applicability::HasPlaceholders, + ); + } + err.span_suggestion( + pat.span, + "if this is a type, explicitly ignore the parameter name", + type_sugg, + Applicability::MachineApplicable, + ); + err.note(rfc_note); + + // Don't attempt to recover by using the `X` in `X<Y>` as the parameter name. + return if self.token == token::Lt { None } else { Some(ident) }; } None } diff --git a/src/test/ui/anon-params/anon-params-denied-2018.rs b/src/test/ui/anon-params/anon-params-denied-2018.rs index 5721f5d2357..95533cf3dfb 100644 --- a/src/test/ui/anon-params/anon-params-denied-2018.rs +++ b/src/test/ui/anon-params/anon-params-denied-2018.rs @@ -5,6 +5,20 @@ trait T { fn foo(i32); //~ expected one of `:`, `@`, or `|`, found `)` + // Also checks with `&` + fn foo_with_ref(&mut i32); + //~^ ERROR expected one of `:`, `@`, or `|`, found `)` + + fn foo_with_qualified_path(<Bar as T>::Baz); + //~^ ERROR expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + + fn foo_with_qualified_path_and_ref(&<Bar as T>::Baz); + //~^ ERROR expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + + fn foo_with_multiple_qualified_paths(<Bar as T>::Baz, <Bar as T>::Baz); + //~^ ERROR expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `,` + //~| ERROR expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + fn bar_with_default_impl(String, String) {} //~^ ERROR expected one of `:` //~| ERROR expected one of `:` diff --git a/src/test/ui/anon-params/anon-params-denied-2018.stderr b/src/test/ui/anon-params/anon-params-denied-2018.stderr index 840294db083..b53640cd65b 100644 --- a/src/test/ui/anon-params/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params/anon-params-denied-2018.stderr @@ -18,8 +18,76 @@ 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:9:29 + | +LL | fn foo_with_ref(&mut i32); + | ^ expected one of `:`, `@`, or `|` + | + = 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_with_ref(self: &mut i32); + | ^^^^^^^^^^^^^^ +help: if this is a parameter name, give it a type + | +LL | fn foo_with_ref(i32: &mut TypeName); + | ^^^^^^^^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn foo_with_ref(_: &mut i32); + | ^^^^^^^^^^^ + +error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/anon-params-denied-2018.rs:12:47 + | +LL | fn foo_with_qualified_path(<Bar as T>::Baz); + | ^ expected one of 8 possible tokens + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: explicitly ignore the parameter name + | +LL | fn foo_with_qualified_path(_: <Bar as T>::Baz); + | ^^^^^^^^^^^^^^^^^^ + +error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/anon-params-denied-2018.rs:15:56 + | +LL | fn foo_with_qualified_path_and_ref(&<Bar as T>::Baz); + | ^ expected one of 8 possible tokens + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: explicitly ignore the parameter name + | +LL | fn foo_with_qualified_path_and_ref(_: &<Bar as T>::Baz); + | ^^^^^^^^^^^^^^^^^^^ + +error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `,` + --> $DIR/anon-params-denied-2018.rs:18:57 + | +LL | fn foo_with_multiple_qualified_paths(<Bar as T>::Baz, <Bar as T>::Baz); + | ^ expected one of 8 possible tokens + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: explicitly ignore the parameter name + | +LL | fn foo_with_multiple_qualified_paths(_: <Bar as T>::Baz, <Bar as T>::Baz); + | ^^^^^^^^^^^^^^^^^^ + +error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/anon-params-denied-2018.rs:18:74 + | +LL | fn foo_with_multiple_qualified_paths(<Bar as T>::Baz, <Bar as T>::Baz); + | ^ expected one of 8 possible tokens + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: explicitly ignore the parameter name + | +LL | fn foo_with_multiple_qualified_paths(<Bar as T>::Baz, _: <Bar as T>::Baz); + | ^^^^^^^^^^^^^^^^^^ + error: expected one of `:`, `@`, or `|`, found `,` - --> $DIR/anon-params-denied-2018.rs:8:36 + --> $DIR/anon-params-denied-2018.rs:22:36 | LL | fn bar_with_default_impl(String, String) {} | ^ expected one of `:`, `@`, or `|` @@ -39,7 +107,7 @@ LL | fn bar_with_default_impl(_: String, String) {} | ^^^^^^^^^ error: expected one of `:`, `@`, or `|`, found `)` - --> $DIR/anon-params-denied-2018.rs:8:44 + --> $DIR/anon-params-denied-2018.rs:22:44 | LL | fn bar_with_default_impl(String, String) {} | ^ expected one of `:`, `@`, or `|` @@ -55,7 +123,7 @@ LL | fn bar_with_default_impl(String, _: String) {} | ^^^^^^^^^ error: expected one of `:`, `@`, or `|`, found `,` - --> $DIR/anon-params-denied-2018.rs:13:22 + --> $DIR/anon-params-denied-2018.rs:27:22 | LL | fn baz(a:usize, b, c: usize) -> usize { | ^ expected one of `:`, `@`, or `|` @@ -70,5 +138,5 @@ help: if this is a type, explicitly ignore the parameter name LL | fn baz(a:usize, _: b, c: usize) -> usize { | ^^^^ -error: aborting due to 4 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/parser/lifetime-in-pattern.stderr b/src/test/ui/parser/lifetime-in-pattern.stderr index 71fd3cdf723..4ffee657cab 100644 --- a/src/test/ui/parser/lifetime-in-pattern.stderr +++ b/src/test/ui/parser/lifetime-in-pattern.stderr @@ -9,6 +9,20 @@ error: expected one of `:`, `@`, or `|`, found `)` | LL | fn test(&'a str) { | ^ expected one of `:`, `@`, or `|` + | + = 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 test(self: &str) { + | ^^^^^^^^^^ +help: if this is a parameter name, give it a type + | +LL | fn test(str: &TypeName) { + | ^^^^^^^^^^^^^^ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn test(_: &str) { + | ^^^^^^^ error: aborting due to 2 previous errors |
