diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index b0b09fcd53..c5d843d9eb 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -263,12 +263,14 @@ impl Evaluator<'_> { for proj in &p.projection { match proj { ProjectionElem::Deref => { - match &ty.data(Interner).kind { - TyKind::Ref(_, _, inner) => { - ty = inner.clone(); + ty = match &ty.data(Interner).kind { + TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(), + _ => { + return Err(MirEvalError::TypeError( + "Overloaded deref in MIR is disallowed", + )) } - _ => not_supported!("dereferencing smart pointers"), - } + }; let x = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?); addr = Address::from_usize(x); } diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index f9a66286b2..8e7fb091c0 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -129,6 +129,12 @@ impl MirLowerCtx<'_> { } Expr::UnaryOp { expr, op } => match op { hir_def::expr::UnaryOp::Deref => { + if !matches!( + self.expr_ty(*expr).kind(Interner), + TyKind::Ref(..) | TyKind::Raw(..) + ) { + return None; + } let mut r = self.lower_expr_as_place(*expr)?; r.projection.push(ProjectionElem::Deref); Some(r) @@ -210,7 +216,7 @@ impl MirLowerCtx<'_> { Adjust::Deref(None) => { r.projection.push(ProjectionElem::Deref); } - Adjust::Deref(Some(_)) => not_supported!("overloaded dereference"), + Adjust::Deref(Some(_)) => not_supported!("implicit overloaded dereference"), Adjust::Borrow(AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) => { let tmp = self.temp(adjustment.target.clone())?; self.push_assignment( @@ -757,6 +763,9 @@ impl MirLowerCtx<'_> { Expr::Box { .. } => not_supported!("box expression"), Expr::UnaryOp { expr, op } => match op { hir_def::expr::UnaryOp::Deref => { + if !matches!(self.expr_ty(*expr).kind(Interner), TyKind::Ref(..) | TyKind::Raw(..)) { + not_supported!("explicit overloaded deref"); + } let (mut tmp, Some(current)) = self.lower_expr_to_some_place(*expr, current)? else { return Ok(None); }; diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index a6aa069e27..1203a96124 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -523,6 +523,34 @@ fn f(x: [(i32, u8); 10]) { //^^^^^ 💡 error: cannot mutate immutable variable `a` } } +"#, + ); + } + + #[test] + fn overloaded_deref() { + check_diagnostics( + r#" +//- minicore: deref_mut +use core::ops::{Deref, DerefMut}; + +struct Foo; +impl Deref for Foo { + type Target = i32; + fn deref(&self) -> &i32 { + &5 + } +} +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut i32 { + &mut 5 + } +} +fn f() { + // FIXME: remove this mut and detect error + let mut x = Foo; + let y = &mut *x; +} "#, ); }