diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 1b91c33742d8b..5f1726f7f0aa8 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -37,11 +37,11 @@ ast_lowering_bad_return_type_notation_inputs = .suggestion = remove the input types 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 = 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 diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index f31e2db051d81..d402c5abc194e 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -372,24 +372,39 @@ pub(crate) struct InclusiveRangeWithNoEnd { pub span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + ast_lowering_bad_return_type_notation_output_suggestion, + applicability = "machine-applicable", + style = "verbose" +)] +/// Given `T: Tr Ret>` or `T: Tr Ret>`, suggest `T: Tr`. +pub(crate) struct RTNSuggestion { + #[suggestion_part(code = "")] + pub output: Span, + #[suggestion_part(code = "(..)")] + pub input: Span, +} + #[derive(Diagnostic)] pub(crate) enum BadReturnTypeNotation { #[diag(ast_lowering_bad_return_type_notation_inputs)] Inputs { #[primary_span] - #[suggestion(code = "()", applicability = "maybe-incorrect")] + #[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")] span: Span, }, #[diag(ast_lowering_bad_return_type_notation_output)] Output { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] span: Span, + #[subdiagnostic] + suggestion: RTNSuggestion, }, #[diag(ast_lowering_bad_return_type_notation_needs_dots)] NeedsDots { #[primary_span] - #[suggestion(code = "(..)", applicability = "maybe-incorrect")] + #[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")] span: Span, }, #[diag(ast_lowering_bad_return_type_notation_position)] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1c69937eed07a..13edcc10c9e2a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -926,19 +926,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if let Some(first_char) = constraint.ident.as_str().chars().next() && first_char.is_ascii_lowercase() { - let mut err = if !data.inputs.is_empty() { - self.dcx().create_err(errors::BadReturnTypeNotation::Inputs { - span: data.inputs_span, - }) - } else if let FnRetTy::Ty(ty) = &data.output { - self.dcx().create_err(errors::BadReturnTypeNotation::Output { - span: data.inputs_span.shrink_to_hi().to(ty.span), - }) - } else { - self.dcx().create_err(errors::BadReturnTypeNotation::NeedsDots { - span: data.inputs_span, - }) + tracing::info!(?data, ?data.inputs); + let err = match (&data.inputs[..], &data.output) { + ([_, ..], FnRetTy::Default(_)) => { + errors::BadReturnTypeNotation::Inputs { span: data.inputs_span } + } + ([], FnRetTy::Default(_)) => { + errors::BadReturnTypeNotation::NeedsDots { span: data.inputs_span } + } + // The case `T: Trait Ret>` is handled in the parser. + (_, FnRetTy::Ty(ty)) => { + 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() && self.tcx.sess.is_nightly_build() { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 55d0647731324..6b6244b05aa9b 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -13,7 +13,7 @@ use tracing::{debug, instrument}; use super::errors::{ AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation, - GenericTypeWithParentheses, UseAngleBrackets, + GenericTypeWithParentheses, RTNSuggestion, UseAngleBrackets, }; use super::{ AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition, @@ -268,19 +268,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArgs::Parenthesized(data) => match generic_args_mode { GenericArgsMode::ReturnTypeNotation => { - let mut err = if !data.inputs.is_empty() { - self.dcx().create_err(BadReturnTypeNotation::Inputs { - span: data.inputs_span, - }) - } else if let FnRetTy::Ty(ty) = &data.output { - self.dcx().create_err(BadReturnTypeNotation::Output { - span: data.inputs_span.shrink_to_hi().to(ty.span), - }) - } else { - self.dcx().create_err(BadReturnTypeNotation::NeedsDots { - span: data.inputs_span, - }) + tracing::info!(?data, ?data.inputs); + let err = match (&data.inputs[..], &data.output) { + ([_, ..], FnRetTy::Default(_)) => { + BadReturnTypeNotation::Inputs { span: data.inputs_span } + } + ([], FnRetTy::Default(_)) => { + BadReturnTypeNotation::NeedsDots { span: data.inputs_span } + } + // The case `T: Trait Ret>` is handled in the parser. + (_, FnRetTy::Ty(ty)) => { + 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() && self.tcx.sess.is_nightly_build() { diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 173c68b3a7224..5bf1a11954ed3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2922,8 +2922,9 @@ pub(crate) struct AddBoxNew { #[diag(parse_bad_return_type_notation_output)] pub(crate) struct BadReturnTypeNotationOutput { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c24305ea9a866..7698df3b5546c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -378,11 +378,14 @@ impl<'a> Parser<'a> { 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) { let lo = self.prev_token.span; let ty = self.parse_ty()?; + let span = lo.to(ty.span); + let suggestion = prev_lo.to(ty.span); self.dcx() - .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) }); + .emit_err(errors::BadReturnTypeNotationOutput { span, suggestion }); } P(ast::GenericArgs::ParenthesizedElided(span)) diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index f00aaec1a8c2c..90fd2c2b4f326 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -21,6 +21,9 @@ fn foo_path() where T::method(i32): Send {} fn bar_path() where T::method() -> (): Send {} //~^ ERROR return type not allowed with return type notation +fn bay_path() where T::method(..) -> (): Send {} +//~^ ERROR return type not allowed with return type notation + fn baz_path() where T::method(): Send {} //~^ ERROR return type notation arguments must be elided with `..` diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index c6b9f3eff90ec..bd02b7d6534a9 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -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() where T::method(..) -> (): Send {} + | ^^^^^ + | +help: remove the return type + | +LL - fn bay_path() where T::method(..) -> (): Send {} +LL + fn bay_path() where T::method(..): Send {} + | + 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() where ::method(i32): Send {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type 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() where ::method() -> (): Send {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type 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() where ::method(): Send {} | ^^^^^^^^^^^^^^^^^^^^^^ 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 | LL | fn foo>() {} - | ^^^^^ help: remove the input types: `()` + | ^^^^^ + | +help: remove the input types + | +LL - fn foo>() {} +LL + fn foo>() {} + | error: return type not allowed with return type notation --> $DIR/bad-inputs-and-output.rs:12:25 | LL | fn bar (): Send>>() {} - | ^^^^^^ help: remove the return type + | ^^^^^^ + | +help: use the right argument notation and remove the return type + | +LL - fn bar (): Send>>() {} +LL + fn bar>() {} + | error: return type notation arguments must be elided with `..` --> $DIR/bad-inputs-and-output.rs:15:23 | LL | fn baz>() {} - | ^^ help: add `..`: `(..)` + | ^^ + | +help: use the correct syntax by adding `..` to the arguments + | +LL | fn baz>() {} + | ++ error: argument types not allowed with return type notation --> $DIR/bad-inputs-and-output.rs:18:40 | LL | fn foo_path() where T::method(i32): Send {} - | ^^^^^ help: remove the input types: `()` + | ^^^^^ + | +help: remove the input types + | +LL - fn foo_path() where T::method(i32): Send {} +LL + fn foo_path() where T::method(..): Send {} + | error: return type not allowed with return type notation --> $DIR/bad-inputs-and-output.rs:21:42 | LL | fn bar_path() where T::method() -> (): Send {} - | ^^^^^^ help: remove the return type + | ^^^^^^ + | +help: use the right argument notation and remove the return type + | +LL - fn bar_path() where T::method() -> (): Send {} +LL + fn bar_path() where T::method(..): Send {} + | 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() where T::method(): Send {} - | ^^ help: add `..`: `(..)` + | ^^ + | +help: use the correct syntax by adding `..` to the arguments + | +LL | fn baz_path() 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`. diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr index 83a5441e3c0c6..19a0e4b17d029 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr @@ -10,11 +10,16 @@ error: argument types not allowed with return type notation --> $DIR/let-binding-init-expr-as-ty.rs:2:26 | LL | let foo: i32::from_be(num); - | ^^^^^ help: remove the input types: `()` + | ^^^^^ | = note: see issue #109417 for more information = 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 +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 --> $DIR/let-binding-init-expr-as-ty.rs:2:14