Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/lower/diagnostics.rs5
-rw-r--r--crates/hir-ty/src/lower/path.rs6
-rw-r--r--crates/hir-ty/src/tests.rs11
-rw-r--r--crates/hir-ty/src/tests/diagnostics.rs4
-rw-r--r--crates/hir/src/diagnostics.rs12
-rw-r--r--crates/ide-diagnostics/src/handlers/generic_default_refers_to_self.rs43
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
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)
}