Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 5 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 5 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/unify.rs | 3 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 11 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/cannot_be_dereferenced.rs | 74 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 2 |
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), |