diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs index 58b143e84e..e237009eba 100644 --- a/crates/hir-ty/src/lower/path.rs +++ b/crates/hir-ty/src/lower/path.rs @@ -607,8 +607,14 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { ) -> Substitution { let prohibit_parens = match def { GenericDefId::TraitId(trait_) => { - let trait_data = self.ctx.db.trait_data(trait_); - !trait_data.flags.contains(TraitFlags::RUSTC_PAREN_SUGAR) + // RTN is prohibited anyways if we got here. + let is_rtn = + self.current_or_prev_segment.args_and_bindings.is_some_and(|generics| { + generics.parenthesized == GenericArgsParentheses::ReturnTypeNotation + }); + let is_fn_trait = + !self.ctx.db.trait_data(trait_).flags.contains(TraitFlags::RUSTC_PAREN_SUGAR); + is_rtn || is_fn_trait } _ => true, }; diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 1ed0daa375..b383fa625e 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -113,6 +113,7 @@ diagnostics![ UnusedVariable, GenericArgsProhibited, ParenthesizedGenericArgsWithoutFnTrait, + BadRtn, ]; #[derive(Debug)] @@ -420,6 +421,11 @@ pub struct ParenthesizedGenericArgsWithoutFnTrait { pub args: InFile>, } +#[derive(Debug)] +pub struct BadRtn { + pub rtn: InFile>, +} + impl AnyDiagnostic { pub(crate) fn body_validation_diagnostic( db: &dyn HirDatabase, @@ -712,6 +718,12 @@ impl AnyDiagnostic { Some(match *diag { PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => { let segment = hir_segment_to_ast_segment(&path.value, segment)?; + + if let Some(rtn) = segment.return_type_syntax() { + // RTN errors are emitted as `GenericArgsProhibited` or `ParenthesizedGenericArgsWithoutFnTrait`. + return Some(BadRtn { rtn: path.with_value(AstPtr::new(&rtn)) }.into()); + } + let args = if let Some(generics) = segment.generic_arg_list() { AstPtr::new(&generics).wrap_left() } else { @@ -722,6 +734,12 @@ impl AnyDiagnostic { } PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment } => { let segment = hir_segment_to_ast_segment(&path.value, segment)?; + + if let Some(rtn) = segment.return_type_syntax() { + // RTN errors are emitted as `GenericArgsProhibited` or `ParenthesizedGenericArgsWithoutFnTrait`. + return Some(BadRtn { rtn: path.with_value(AstPtr::new(&rtn)) }.into()); + } + let args = AstPtr::new(&segment.parenthesized_arg_list()?); let args = path.with_value(args); ParenthesizedGenericArgsWithoutFnTrait { args }.into() diff --git a/crates/ide-diagnostics/src/handlers/bad_rtn.rs b/crates/ide-diagnostics/src/handlers/bad_rtn.rs new file mode 100644 index 0000000000..9ed85f9f20 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/bad_rtn.rs @@ -0,0 +1,52 @@ +use ide_db::Severity; + +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: bad-rtn +// +// This diagnostic is shown when a RTN (Return Type Notation, `Type::method(..): Send`) is written in an improper place. +pub(crate) fn bad_rtn(ctx: &DiagnosticsContext<'_>, d: &hir::BadRtn) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::Ra("bad-rtn", Severity::Error), + "return type notation not allowed in this position yet", + d.rtn.map(Into::into), + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn fn_traits_also_emit() { + check_diagnostics( + r#" +//- minicore: fn +fn foo< + A: Fn(..), + // ^^^^ error: return type notation not allowed in this position yet +>() {} + "#, + ); + } + + #[test] + fn bad_rtn() { + check_diagnostics( + r#" +mod module { + pub struct Type; +} +trait Trait {} + +fn foo() +where + module(..)::Type: Trait + // ^^^^ error: return type notation not allowed in this position yet +{ +} + "#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index f4ced736b3..d1d852faf0 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -25,6 +25,7 @@ mod handlers { pub(crate) mod await_outside_of_async; + pub(crate) mod bad_rtn; pub(crate) mod break_outside_of_loop; pub(crate) mod expected_function; pub(crate) mod generic_args_prohibited; @@ -493,6 +494,7 @@ pub fn semantic_diagnostics( AnyDiagnostic::ParenthesizedGenericArgsWithoutFnTrait(d) => { handlers::parenthesized_generic_args_without_fn_trait::parenthesized_generic_args_without_fn_trait(&ctx, &d) } + AnyDiagnostic::BadRtn(d) => handlers::bad_rtn::bad_rtn(&ctx, &d), }; res.push(d) }