Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22145 from ada4a/diag-E0735
feat: add diagnostic for E0735
| -rw-r--r-- | crates/hir-ty/src/lower/diagnostics.rs | 5 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower/path.rs | 6 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests.rs | 11 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/diagnostics.rs | 4 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 12 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/generic_default_refers_to_self.rs | 43 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 2 |
7 files changed, 71 insertions, 12 deletions
diff --git a/crates/hir-ty/src/lower/diagnostics.rs b/crates/hir-ty/src/lower/diagnostics.rs index 009f047109..2565fb46ce 100644 --- a/crates/hir-ty/src/lower/diagnostics.rs +++ b/crates/hir-ty/src/lower/diagnostics.rs @@ -81,6 +81,11 @@ pub enum PathLoweringDiagnostic { def: GenericDefId, expected_count: u32, }, + /// Generic defaults are not allowed to refer to `Self`. + GenericDefaultRefersToSelf { + /// Index of the `Self` segment. + segment: u32, + }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs index 4f70732178..a364894539 100644 --- a/crates/hir-ty/src/lower/path.rs +++ b/crates/hir-ty/src/lower/path.rs @@ -300,8 +300,10 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy); if self.ctx.lowering_param_default.is_some() { - // Generic defaults are not allowed to refer to `Self`. - // FIXME: Emit an error. + let segment = self.current_segment_u32(); + self.on_diagnostic(PathLoweringDiagnostic::GenericDefaultRefersToSelf { + segment, + }); return false; } } diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 430a570444..83767c42ea 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -88,15 +88,12 @@ fn check_impl( let file_range = FileRange { file_id, range }; if only_types { types.insert(file_range, expected); - } else if expected.starts_with("type: ") { - types.insert(file_range, expected.trim_start_matches("type: ").to_owned()); + } else if let Some(ty) = expected.strip_prefix("type: ") { + types.insert(file_range, ty.to_owned()); } else if expected.starts_with("expected") { mismatches.insert(file_range, expected); - } else if expected.starts_with("adjustments:") { - adjustments.insert( - file_range, - expected.trim_start_matches("adjustments:").trim().to_owned(), - ); + } else if let Some(adjs) = expected.strip_prefix("adjustments:") { + adjustments.insert(file_range, adjs.trim().to_owned()); } else { panic!("unexpected annotation: {expected} @ {range:?}"); } diff --git a/crates/hir-ty/src/tests/diagnostics.rs b/crates/hir-ty/src/tests/diagnostics.rs index f257aa1b6e..94ca88088d 100644 --- a/crates/hir-ty/src/tests/diagnostics.rs +++ b/crates/hir-ty/src/tests/diagnostics.rs @@ -1,6 +1,4 @@ -use crate::tests::check_no_mismatches; - -use super::check; +use super::{check, check_no_mismatches}; #[test] fn function_return_type_mismatch_1() { diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index b14bf64266..110cc19cf1 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -57,6 +57,7 @@ diagnostics![AnyDiagnostic<'db> -> BreakOutsideOfLoop, CastToUnsized<'db>, ExpectedFunction<'db>, + GenericDefaultRefersToSelf, InactiveCode, IncoherentImpl, IncorrectCase, @@ -465,6 +466,12 @@ pub struct IncorrectGenericsOrder { pub expected_kind: GenericArgKind, } +#[derive(Debug)] +pub struct GenericDefaultRefersToSelf { + /// The `Self` segment. + pub segment: InFile<AstPtr<ast::PathSegment>>, +} + impl<'db> AnyDiagnostic<'db> { pub(crate) fn body_validation_diagnostic( db: &'db dyn HirDatabase, @@ -888,6 +895,11 @@ impl<'db> AnyDiagnostic<'db> { } .into() } + PathLoweringDiagnostic::GenericDefaultRefersToSelf { segment } => { + let segment = hir_segment_to_ast_segment(&path.value, segment)?; + let segment = path.with_value(AstPtr::new(&segment)); + GenericDefaultRefersToSelf { segment }.into() + } }) } diff --git a/crates/ide-diagnostics/src/handlers/generic_default_refers_to_self.rs b/crates/ide-diagnostics/src/handlers/generic_default_refers_to_self.rs new file mode 100644 index 0000000000..3d38159c4f --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/generic_default_refers_to_self.rs @@ -0,0 +1,43 @@ +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: generic-default-refers-to-self +// +// This diagnostic is shown when a generic default refers to `Self` +pub(crate) fn generic_default_refers_to_self( + ctx: &DiagnosticsContext<'_>, + d: &hir::GenericDefaultRefersToSelf, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0735"), + "generic parameters cannot use `Self` in their defaults", + d.segment.map(Into::into), + ) + .stable() +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn plain_self() { + check_diagnostics( + r#" +struct Foo<T = Self>(T); + // ^^^^ error: generic parameters cannot use `Self` in their defaults +"#, + ); + } + + #[test] + fn self_as_generic() { + check_diagnostics( + r#" +struct Wrapper<T>(T); +struct Foo<T = Wrapper<Self>>(T); + // ^^^^ error: generic parameters cannot use `Self` in their defaults +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 09c9f8eab0..54af3a35f4 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -35,6 +35,7 @@ mod handlers { pub(crate) mod elided_lifetimes_in_path; pub(crate) mod expected_function; pub(crate) mod generic_args_prohibited; + pub(crate) mod generic_default_refers_to_self; pub(crate) mod inactive_code; pub(crate) mod incoherent_impl; pub(crate) mod incorrect_case; @@ -477,6 +478,7 @@ pub fn semantic_diagnostics( AnyDiagnostic::IncorrectGenericsOrder(d) => handlers::incorrect_generics_order::incorrect_generics_order(&ctx, &d), AnyDiagnostic::MissingLifetime(d) => handlers::missing_lifetime::missing_lifetime(&ctx, &d), AnyDiagnostic::ElidedLifetimesInPath(d) => handlers::elided_lifetimes_in_path::elided_lifetimes_in_path(&ctx, &d), + AnyDiagnostic::GenericDefaultRefersToSelf(d) => handlers::generic_default_refers_to_self::generic_default_refers_to_self(&ctx, &d), }; res.push(d) } |