1
Fork 0

Tweak invalid RTN errors

Make suggestions verbose.

When encountering `method(type)` bound, suggest `method(..)` instead of `method()`.

```
error: argument types not allowed with return type notation
  --> $DIR/bad-inputs-and-output.rs:9:23
   |
LL | fn foo<T: Trait<method(i32): Send>>() {}
   |                       ^^^^^
   |
help: remove the input types
   |
LL - fn foo<T: Trait<method(i32): Send>>() {}
LL + fn foo<T: Trait<method(..): Send>>() {}
   |
```

When encountering both return type and arg list that isn't `..`, suggest replacing both.

```
error: return type not allowed with return type notation
  --> $DIR/bad-inputs-and-output.rs:12:25
   |
LL | fn bar<T: Trait<method() -> (): Send>>() {}
   |                         ^^^^^^
   |
help: use the right argument notation and remove the return type
   |
LL - fn bar<T: Trait<method() -> (): Send>>() {}
LL + fn bar<T: Trait<method(..): Send>>() {}
   |
```

When encountering a return type, suggest removing it including the leading whitespace.

```
error: return type not allowed with return type notation
  --> $DIR/bad-inputs-and-output.rs:24:45
   |
LL | fn bay_path<T: Trait>() where T::method(..) -> (): Send {}
   |                                             ^^^^^
   |
help: remove the return type
   |
LL - fn bay_path<T: Trait>() where T::method(..) -> (): Send {}
LL + fn bay_path<T: Trait>() where T::method(..): Send {}
   |
```
This commit is contained in:
Esteban Küber 2025-02-28 20:05:43 +00:00
parent f45d4acf1b
commit adb5ecabdb
9 changed files with 133 additions and 44 deletions

View file

@ -37,11 +37,11 @@ ast_lowering_bad_return_type_notation_inputs =
.suggestion = remove the input types .suggestion = remove the input types
ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..` ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..`
.suggestion = add `..` .suggestion = use the correct syntax by adding `..` to the arguments
ast_lowering_bad_return_type_notation_output = ast_lowering_bad_return_type_notation_output =
return type not allowed with return type notation return type not allowed with return type notation
.suggestion = remove the return type ast_lowering_bad_return_type_notation_output_suggestion = use the right argument notation and remove the return type
ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet

View file

@ -372,24 +372,39 @@ pub(crate) struct InclusiveRangeWithNoEnd {
pub span: Span, pub span: Span,
} }
#[derive(Subdiagnostic)]
#[multipart_suggestion(
ast_lowering_bad_return_type_notation_output_suggestion,
applicability = "machine-applicable",
style = "verbose"
)]
/// Given `T: Tr<m() -> Ret>` or `T: Tr<m(Ty) -> Ret>`, suggest `T: Tr<m(..)>`.
pub(crate) struct RTNSuggestion {
#[suggestion_part(code = "")]
pub output: Span,
#[suggestion_part(code = "(..)")]
pub input: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
pub(crate) enum BadReturnTypeNotation { pub(crate) enum BadReturnTypeNotation {
#[diag(ast_lowering_bad_return_type_notation_inputs)] #[diag(ast_lowering_bad_return_type_notation_inputs)]
Inputs { Inputs {
#[primary_span] #[primary_span]
#[suggestion(code = "()", applicability = "maybe-incorrect")] #[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
span: Span, span: Span,
}, },
#[diag(ast_lowering_bad_return_type_notation_output)] #[diag(ast_lowering_bad_return_type_notation_output)]
Output { Output {
#[primary_span] #[primary_span]
#[suggestion(code = "", applicability = "maybe-incorrect")]
span: Span, span: Span,
#[subdiagnostic]
suggestion: RTNSuggestion,
}, },
#[diag(ast_lowering_bad_return_type_notation_needs_dots)] #[diag(ast_lowering_bad_return_type_notation_needs_dots)]
NeedsDots { NeedsDots {
#[primary_span] #[primary_span]
#[suggestion(code = "(..)", applicability = "maybe-incorrect")] #[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
span: Span, span: Span,
}, },
#[diag(ast_lowering_bad_return_type_notation_position)] #[diag(ast_lowering_bad_return_type_notation_position)]

View file

@ -926,19 +926,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
if let Some(first_char) = constraint.ident.as_str().chars().next() if let Some(first_char) = constraint.ident.as_str().chars().next()
&& first_char.is_ascii_lowercase() && first_char.is_ascii_lowercase()
{ {
let mut err = if !data.inputs.is_empty() { tracing::info!(?data, ?data.inputs);
self.dcx().create_err(errors::BadReturnTypeNotation::Inputs { let err = match (&data.inputs[..], &data.output) {
span: data.inputs_span, ([_, ..], FnRetTy::Default(_)) => {
}) errors::BadReturnTypeNotation::Inputs { span: data.inputs_span }
} else if let FnRetTy::Ty(ty) = &data.output { }
self.dcx().create_err(errors::BadReturnTypeNotation::Output { ([], FnRetTy::Default(_)) => {
span: data.inputs_span.shrink_to_hi().to(ty.span), errors::BadReturnTypeNotation::NeedsDots { span: data.inputs_span }
}) }
} else { // The case `T: Trait<method(..) -> Ret>` is handled in the parser.
self.dcx().create_err(errors::BadReturnTypeNotation::NeedsDots { (_, FnRetTy::Ty(ty)) => {
span: data.inputs_span, let span = data.inputs_span.shrink_to_hi().to(ty.span);
}) errors::BadReturnTypeNotation::Output {
span,
suggestion: errors::RTNSuggestion {
output: span,
input: data.inputs_span,
},
}
}
}; };
let mut err = self.dcx().create_err(err);
if !self.tcx.features().return_type_notation() if !self.tcx.features().return_type_notation()
&& self.tcx.sess.is_nightly_build() && self.tcx.sess.is_nightly_build()
{ {

View file

@ -13,7 +13,7 @@ use tracing::{debug, instrument};
use super::errors::{ use super::errors::{
AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation, AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation,
GenericTypeWithParentheses, UseAngleBrackets, GenericTypeWithParentheses, RTNSuggestion, UseAngleBrackets,
}; };
use super::{ use super::{
AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition, AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition,
@ -268,19 +268,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
GenericArgs::Parenthesized(data) => match generic_args_mode { GenericArgs::Parenthesized(data) => match generic_args_mode {
GenericArgsMode::ReturnTypeNotation => { GenericArgsMode::ReturnTypeNotation => {
let mut err = if !data.inputs.is_empty() { tracing::info!(?data, ?data.inputs);
self.dcx().create_err(BadReturnTypeNotation::Inputs { let err = match (&data.inputs[..], &data.output) {
span: data.inputs_span, ([_, ..], FnRetTy::Default(_)) => {
}) BadReturnTypeNotation::Inputs { span: data.inputs_span }
} else if let FnRetTy::Ty(ty) = &data.output { }
self.dcx().create_err(BadReturnTypeNotation::Output { ([], FnRetTy::Default(_)) => {
span: data.inputs_span.shrink_to_hi().to(ty.span), BadReturnTypeNotation::NeedsDots { span: data.inputs_span }
}) }
} else { // The case `T: Trait<method(..) -> Ret>` is handled in the parser.
self.dcx().create_err(BadReturnTypeNotation::NeedsDots { (_, FnRetTy::Ty(ty)) => {
span: data.inputs_span, let span = data.inputs_span.shrink_to_hi().to(ty.span);
}) BadReturnTypeNotation::Output {
span,
suggestion: RTNSuggestion {
output: span,
input: data.inputs_span,
},
}
}
}; };
let mut err = self.dcx().create_err(err);
if !self.tcx.features().return_type_notation() if !self.tcx.features().return_type_notation()
&& self.tcx.sess.is_nightly_build() && self.tcx.sess.is_nightly_build()
{ {

View file

@ -2922,8 +2922,9 @@ pub(crate) struct AddBoxNew {
#[diag(parse_bad_return_type_notation_output)] #[diag(parse_bad_return_type_notation_output)]
pub(crate) struct BadReturnTypeNotationOutput { pub(crate) struct BadReturnTypeNotationOutput {
#[primary_span] #[primary_span]
#[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
pub span: Span, pub span: Span,
#[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
pub suggestion: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]

View file

@ -378,11 +378,14 @@ impl<'a> Parser<'a> {
self.psess.gated_spans.gate(sym::return_type_notation, span); self.psess.gated_spans.gate(sym::return_type_notation, span);
let prev_lo = self.prev_token.span.shrink_to_hi();
if self.eat_noexpect(&token::RArrow) { if self.eat_noexpect(&token::RArrow) {
let lo = self.prev_token.span; let lo = self.prev_token.span;
let ty = self.parse_ty()?; let ty = self.parse_ty()?;
let span = lo.to(ty.span);
let suggestion = prev_lo.to(ty.span);
self.dcx() self.dcx()
.emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) }); .emit_err(errors::BadReturnTypeNotationOutput { span, suggestion });
} }
P(ast::GenericArgs::ParenthesizedElided(span)) P(ast::GenericArgs::ParenthesizedElided(span))

View file

@ -21,6 +21,9 @@ fn foo_path<T: Trait>() where T::method(i32): Send {}
fn bar_path<T: Trait>() where T::method() -> (): Send {} fn bar_path<T: Trait>() where T::method() -> (): Send {}
//~^ ERROR return type not allowed with return type notation //~^ ERROR return type not allowed with return type notation
fn bay_path<T: Trait>() where T::method(..) -> (): Send {}
//~^ ERROR return type not allowed with return type notation
fn baz_path<T: Trait>() where T::method(): Send {} fn baz_path<T: Trait>() where T::method(): Send {}
//~^ ERROR return type notation arguments must be elided with `..` //~^ ERROR return type notation arguments must be elided with `..`

View file

@ -1,17 +1,29 @@
error: return type not allowed with return type notation
--> $DIR/bad-inputs-and-output.rs:24:45
|
LL | fn bay_path<T: Trait>() where T::method(..) -> (): Send {}
| ^^^^^
|
help: remove the return type
|
LL - fn bay_path<T: Trait>() where T::method(..) -> (): Send {}
LL + fn bay_path<T: Trait>() where T::method(..): Send {}
|
error[E0575]: expected associated type, found associated function `Trait::method` error[E0575]: expected associated type, found associated function `Trait::method`
--> $DIR/bad-inputs-and-output.rs:27:36 --> $DIR/bad-inputs-and-output.rs:30:36
| |
LL | fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {} LL | fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
error[E0575]: expected associated type, found associated function `Trait::method` error[E0575]: expected associated type, found associated function `Trait::method`
--> $DIR/bad-inputs-and-output.rs:30:36 --> $DIR/bad-inputs-and-output.rs:33:36
| |
LL | fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {} LL | fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
error[E0575]: expected associated type, found associated function `Trait::method` error[E0575]: expected associated type, found associated function `Trait::method`
--> $DIR/bad-inputs-and-output.rs:33:36 --> $DIR/bad-inputs-and-output.rs:36:36
| |
LL | fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {} LL | fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
| ^^^^^^^^^^^^^^^^^^^^^^ not a associated type | ^^^^^^^^^^^^^^^^^^^^^^ not a associated type
@ -20,38 +32,72 @@ error: argument types not allowed with return type notation
--> $DIR/bad-inputs-and-output.rs:9:23 --> $DIR/bad-inputs-and-output.rs:9:23
| |
LL | fn foo<T: Trait<method(i32): Send>>() {} LL | fn foo<T: Trait<method(i32): Send>>() {}
| ^^^^^ help: remove the input types: `()` | ^^^^^
|
help: remove the input types
|
LL - fn foo<T: Trait<method(i32): Send>>() {}
LL + fn foo<T: Trait<method(..): Send>>() {}
|
error: return type not allowed with return type notation error: return type not allowed with return type notation
--> $DIR/bad-inputs-and-output.rs:12:25 --> $DIR/bad-inputs-and-output.rs:12:25
| |
LL | fn bar<T: Trait<method() -> (): Send>>() {} LL | fn bar<T: Trait<method() -> (): Send>>() {}
| ^^^^^^ help: remove the return type | ^^^^^^
|
help: use the right argument notation and remove the return type
|
LL - fn bar<T: Trait<method() -> (): Send>>() {}
LL + fn bar<T: Trait<method(..): Send>>() {}
|
error: return type notation arguments must be elided with `..` error: return type notation arguments must be elided with `..`
--> $DIR/bad-inputs-and-output.rs:15:23 --> $DIR/bad-inputs-and-output.rs:15:23
| |
LL | fn baz<T: Trait<method(): Send>>() {} LL | fn baz<T: Trait<method(): Send>>() {}
| ^^ help: add `..`: `(..)` | ^^
|
help: use the correct syntax by adding `..` to the arguments
|
LL | fn baz<T: Trait<method(..): Send>>() {}
| ++
error: argument types not allowed with return type notation error: argument types not allowed with return type notation
--> $DIR/bad-inputs-and-output.rs:18:40 --> $DIR/bad-inputs-and-output.rs:18:40
| |
LL | fn foo_path<T: Trait>() where T::method(i32): Send {} LL | fn foo_path<T: Trait>() where T::method(i32): Send {}
| ^^^^^ help: remove the input types: `()` | ^^^^^
|
help: remove the input types
|
LL - fn foo_path<T: Trait>() where T::method(i32): Send {}
LL + fn foo_path<T: Trait>() where T::method(..): Send {}
|
error: return type not allowed with return type notation error: return type not allowed with return type notation
--> $DIR/bad-inputs-and-output.rs:21:42 --> $DIR/bad-inputs-and-output.rs:21:42
| |
LL | fn bar_path<T: Trait>() where T::method() -> (): Send {} LL | fn bar_path<T: Trait>() where T::method() -> (): Send {}
| ^^^^^^ help: remove the return type | ^^^^^^
|
help: use the right argument notation and remove the return type
|
LL - fn bar_path<T: Trait>() where T::method() -> (): Send {}
LL + fn bar_path<T: Trait>() where T::method(..): Send {}
|
error: return type notation arguments must be elided with `..` error: return type notation arguments must be elided with `..`
--> $DIR/bad-inputs-and-output.rs:24:40 --> $DIR/bad-inputs-and-output.rs:27:40
| |
LL | fn baz_path<T: Trait>() where T::method(): Send {} LL | fn baz_path<T: Trait>() where T::method(): Send {}
| ^^ help: add `..`: `(..)` | ^^
|
help: use the correct syntax by adding `..` to the arguments
|
LL | fn baz_path<T: Trait>() where T::method(..): Send {}
| ++
error: aborting due to 9 previous errors error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0575`. For more information about this error, try `rustc --explain E0575`.

View file

@ -10,11 +10,16 @@ error: argument types not allowed with return type notation
--> $DIR/let-binding-init-expr-as-ty.rs:2:26 --> $DIR/let-binding-init-expr-as-ty.rs:2:26
| |
LL | let foo: i32::from_be(num); LL | let foo: i32::from_be(num);
| ^^^^^ help: remove the input types: `()` | ^^^^^
| |
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= help: add `#![feature(return_type_notation)]` to the crate attributes to enable = help: add `#![feature(return_type_notation)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
help: remove the input types
|
LL - let foo: i32::from_be(num);
LL + let foo: i32::from_be(..);
|
error: return type notation not allowed in this position yet error: return type notation not allowed in this position yet
--> $DIR/let-binding-init-expr-as-ty.rs:2:14 --> $DIR/let-binding-init-expr-as-ty.rs:2:14