Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #15860 - HKalbasi:fix-capture-raw-pointer, r=HKalbasi
Truncate closure capture place for raw pointer
fix https://github.com/rust-lang/rust-analyzer/issues/15670#issuecomment-1804070623
| -rw-r--r-- | crates/hir-ty/src/chalk_ext.rs | 5 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/closure.rs | 27 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/mutability_errors.rs | 16 |
3 files changed, 48 insertions, 0 deletions
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index c0b243ea24..c9ab356854 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -28,6 +28,7 @@ pub trait TyExt { fn is_unknown(&self) -> bool; fn contains_unknown(&self) -> bool; fn is_ty_var(&self) -> bool; + fn is_union(&self) -> bool; fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; fn as_builtin(&self) -> Option<BuiltinType>; @@ -96,6 +97,10 @@ impl TyExt for Ty { matches!(self.kind(Interner), TyKind::InferenceVar(_, _)) } + fn is_union(&self) -> bool { + matches!(self.adt_id(Interner), Some(AdtId(hir_def::AdtId::UnionId(_)))) + } + fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { match self.kind(Interner) { TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 0805e20447..af74df1032 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -735,6 +735,32 @@ impl InferenceContext<'_> { self.walk_expr(expr); } + fn restrict_precision_for_unsafe(&mut self) { + for capture in &mut self.current_captures { + let mut ty = self.table.resolve_completely(self.result[capture.place.local].clone()); + if ty.as_raw_ptr().is_some() || ty.is_union() { + capture.kind = CaptureKind::ByRef(BorrowKind::Shared); + capture.place.projections.truncate(0); + continue; + } + for (i, p) in capture.place.projections.iter().enumerate() { + ty = p.projected_ty( + ty, + self.db, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + self.owner.module(self.db.upcast()).krate(), + ); + if ty.as_raw_ptr().is_some() || ty.is_union() { + capture.kind = CaptureKind::ByRef(BorrowKind::Shared); + capture.place.projections.truncate(i + 1); + break; + } + } + } + } + fn adjust_for_move_closure(&mut self) { for capture in &mut self.current_captures { if let Some(first_deref) = @@ -924,6 +950,7 @@ impl InferenceContext<'_> { self.result.mutated_bindings_in_closure.insert(item.place.local); } } + self.restrict_precision_for_unsafe(); // closure_kind should be done before adjust_for_move_closure let closure_kind = self.closure_kind(); match capture_by { diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index ee096a100a..1875111492 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -1228,4 +1228,20 @@ fn foo(mut foo: Foo) { "#, ); } + + #[test] + fn regression_15670() { + check_diagnostics( + r#" +//- minicore: fn + +pub struct A {} +pub unsafe fn foo(a: *mut A) { + let mut b = || -> *mut A { &mut *a }; + //^^^^^ 💡 warn: variable does not need to be mutable + let _ = b(); +} +"#, + ); + } } |