fix: Do not consider mutable usage of deref to *mut T as deref_mut

This commit is contained in:
Shoyu Vanilla 2024-10-07 01:49:14 +09:00
parent 5982d9c420
commit d3446a78a0
2 changed files with 37 additions and 1 deletions

View file

@ -180,6 +180,7 @@ impl InferenceContext<'_> {
self.infer_mut_expr(index, Mutability::Not); self.infer_mut_expr(index, Mutability::Not);
} }
Expr::UnaryOp { expr, op: UnaryOp::Deref } => { Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
let mut mutability = mutability;
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
if mutability == Mutability::Mut { if mutability == Mutability::Mut {
if let Some(deref_trait) = self if let Some(deref_trait) = self
@ -187,7 +188,17 @@ impl InferenceContext<'_> {
.lang_item(self.table.trait_env.krate, LangItem::DerefMut) .lang_item(self.table.trait_env.krate, LangItem::DerefMut)
.and_then(|l| l.as_trait()) .and_then(|l| l.as_trait())
{ {
if let Some(deref_fn) = self let ty = self.result.type_of_expr.get(*expr);
let is_mut_ptr = ty.is_some_and(|ty| {
let ty = self.table.resolve_ty_shallow(ty);
matches!(
ty.kind(Interner),
chalk_ir::TyKind::Raw(Mutability::Mut, _)
)
});
if is_mut_ptr {
mutability = Mutability::Not;
} else if let Some(deref_fn) = self
.db .db
.trait_data(deref_trait) .trait_data(deref_trait)
.method_by_name(&Name::new_symbol_root(sym::deref_mut.clone())) .method_by_name(&Name::new_symbol_root(sym::deref_mut.clone()))

View file

@ -1255,6 +1255,31 @@ pub unsafe fn foo(a: *mut A) {
//^^^^^ 💡 warn: variable does not need to be mutable //^^^^^ 💡 warn: variable does not need to be mutable
let _ = b(); let _ = b();
} }
"#,
);
}
#[test]
fn regression_15799() {
check_diagnostics(
r#"
//- minicore: deref_mut
struct WrapPtr(*mut u32);
impl core::ops::Deref for WrapPtr {
type Target = *mut u32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let mut x = 0u32;
let wrap = WrapPtr(&mut x);
unsafe {
**wrap = 6;
}
}
"#, "#,
); );
} }