Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22380 from WaterWhisperer/diag-E0614
feat: add diagnostic for E0614
Chayim Refael Friedman 3 weeks ago
parent 1a68212 · parent d67d862 · commit f05800d
-rw-r--r--crates/hir-ty/src/infer.rs5
-rw-r--r--crates/hir-ty/src/infer/expr.rs5
-rw-r--r--crates/hir-ty/src/infer/unify.rs3
-rw-r--r--crates/hir/src/diagnostics.rs11
-rw-r--r--crates/ide-diagnostics/src/handlers/cannot_be_dereferenced.rs74
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
6 files changed, 98 insertions, 2 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 3f90a78cc2..51e9435c80 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -396,6 +396,11 @@ pub enum InferenceDiagnostic {
call_expr: ExprId,
found: StoredTy,
},
+ CannotBeDereferenced {
+ #[type_visitable(ignore)]
+ expr: ExprId,
+ found: StoredTy,
+ },
TypedHole {
#[type_visitable(ignore)]
expr: ExprId,
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 90ecfbd7e9..3cff0ea896 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -1295,7 +1295,10 @@ impl<'db> InferenceContext<'_, 'db> {
if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
oprnd_t = ty;
} else {
- // FIXME: Report an error.
+ self.push_diagnostic(InferenceDiagnostic::CannotBeDereferenced {
+ expr,
+ found: oprnd_t.store(),
+ });
oprnd_t = self.types.types.error;
}
}
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index f9ad76b0c1..6500eb213c 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -577,7 +577,8 @@ pub(super) mod resolve_completely {
diagnostics.retain_mut(|diagnostic| {
self.resolve_completely(diagnostic);
- if let InferenceDiagnostic::ExpectedFunction { found: ty, .. }
+ if let InferenceDiagnostic::CannotBeDereferenced { found: ty, .. }
+ | InferenceDiagnostic::ExpectedFunction { found: ty, .. }
| InferenceDiagnostic::ExpectedArrayOrSlicePat { found: ty, .. }
| InferenceDiagnostic::UnresolvedField { receiver: ty, .. }
| InferenceDiagnostic::UnresolvedMethodCall { receiver: ty, .. } = diagnostic
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 7e4853539d..7c128d6bce 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -102,6 +102,7 @@ macro_rules! diagnostics {
diagnostics![AnyDiagnostic<'db> ->
AwaitOutsideOfAsync,
BreakOutsideOfLoop,
+ CannotBeDereferenced<'db>,
CastToUnsized<'db>,
ExpectedArrayOrSlicePat<'db>,
ExpectedFunction<'db>,
@@ -318,6 +319,12 @@ pub struct ExpectedFunction<'db> {
}
#[derive(Debug)]
+pub struct CannotBeDereferenced<'db> {
+ pub expr: InFile<ExprOrPatPtr>,
+ pub found: Type<'db>,
+}
+
+#[derive(Debug)]
pub struct FunctionalRecordUpdateOnNonStruct {
pub base_expr: InFile<ExprOrPatPtr>,
}
@@ -923,6 +930,10 @@ impl<'db> AnyDiagnostic<'db> {
let cast_ty = Type::new(db, def, cast_ty.as_ref());
InvalidCast { expr, error: *error, expr_ty, cast_ty }.into()
}
+ InferenceDiagnostic::CannotBeDereferenced { expr, found } => {
+ let expr = expr_syntax(*expr)?;
+ CannotBeDereferenced { expr, found: Type::new(db, def, found.as_ref()) }.into()
+ }
InferenceDiagnostic::TyDiagnostic { source, diag } => {
let source_map = match source {
InferenceTyDiagnosticSource::Body => source_map,
diff --git a/crates/ide-diagnostics/src/handlers/cannot_be_dereferenced.rs b/crates/ide-diagnostics/src/handlers/cannot_be_dereferenced.rs
new file mode 100644
index 0000000000..6c9726f8af
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/cannot_be_dereferenced.rs
@@ -0,0 +1,74 @@
+use hir::HirDisplay;
+
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: cannot-be-dereferenced
+//
+// This diagnostic is triggered if the operand of a dereference expression
+// cannot be dereferenced.
+pub(crate) fn cannot_be_dereferenced(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::CannotBeDereferenced<'_>,
+) -> Diagnostic {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0614"),
+ format!(
+ "type `{}` cannot be dereferenced",
+ d.found.display(ctx.sema.db, ctx.display_target)
+ ),
+ d.expr.map(Into::into),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn cannot_be_dereferenced() {
+ check_diagnostics(
+ r#"
+fn f() {
+ let x = 1i32;
+ let _ = *x;
+ //^^ error: type `i32` cannot be dereferenced
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn allows_reference_deref() {
+ check_diagnostics(
+ r#"
+fn f(x: &i32) {
+ let _ = *x;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn allows_overloaded_deref() {
+ check_diagnostics(
+ r#"
+//- minicore: deref
+struct Wrapper(i32);
+
+impl core::ops::Deref for Wrapper {
+ type Target = i32;
+
+ fn deref(&self) -> &i32 {
+ &self.0
+ }
+}
+
+fn f(x: Wrapper) {
+ let _ = *x;
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 0880002cba..459728592f 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -32,6 +32,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 cannot_be_dereferenced;
pub(crate) mod duplicate_field;
pub(crate) mod elided_lifetimes_in_path;
pub(crate) mod expected_array_or_slice_pat;
@@ -429,6 +430,7 @@ pub fn semantic_diagnostics(
for diag in diags {
let d = match diag {
AnyDiagnostic::AwaitOutsideOfAsync(d) => handlers::await_outside_of_async::await_outside_of_async(&ctx, &d),
+ AnyDiagnostic::CannotBeDereferenced(d) => handlers::cannot_be_dereferenced::cannot_be_dereferenced(&ctx, &d),
AnyDiagnostic::CastToUnsized(d) => handlers::invalid_cast::cast_to_unsized(&ctx, &d),
AnyDiagnostic::ExpectedArrayOrSlicePat(d) => handlers::expected_array_or_slice_pat::expected_array_or_slice_pat(&ctx, &d),
AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d),