Skip to content

Commit b218009

Browse files
committed
Auto merge of rust-lang#14576 - HKalbasi:dev2, r=HKalbasi
Fix explicit deref problems in closure capture fix the `need-mut` part of rust-lang#14562 Perhaps surprisingly, it wasn't unique immutable borrow. The code still doesn't emit any of them, and I think those won't happen in edition 2021 (which is currently the only thing implemented), since we always capture `&mut *x` instead of `&mut x`. But I'm not very sure about it.
2 parents 57c4ee2 + 7cb4318 commit b218009

File tree

4 files changed

+90
-4
lines changed

4 files changed

+90
-4
lines changed

crates/hir-ty/src/infer/closure.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ impl InferenceContext<'_> {
190190
}
191191
return Some(place);
192192
}
193+
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
194+
if matches!(
195+
self.expr_ty_after_adjustments(*expr).kind(Interner),
196+
TyKind::Ref(..) | TyKind::Raw(..)
197+
) {
198+
let mut place = self.place_of_expr(*expr)?;
199+
place.projections.push(ProjectionElem::Deref);
200+
return Some(place);
201+
}
202+
}
193203
_ => (),
194204
}
195205
None
@@ -371,7 +381,12 @@ impl InferenceContext<'_> {
371381
}
372382
Expr::Field { expr, name: _ } => self.select_from_expr(*expr),
373383
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
374-
if let Some((f, _)) = self.result.method_resolution(tgt_expr) {
384+
if matches!(
385+
self.expr_ty_after_adjustments(*expr).kind(Interner),
386+
TyKind::Ref(..) | TyKind::Raw(..)
387+
) {
388+
self.select_from_expr(*expr);
389+
} else if let Some((f, _)) = self.result.method_resolution(tgt_expr) {
375390
let mutability = 'b: {
376391
if let Some(deref_trait) =
377392
self.resolve_lang_item(LangItem::DerefMut).and_then(|x| x.as_trait())
@@ -461,10 +476,20 @@ impl InferenceContext<'_> {
461476
}
462477
}
463478

464-
fn expr_ty(&mut self, expr: ExprId) -> Ty {
479+
fn expr_ty(&self, expr: ExprId) -> Ty {
465480
self.result[expr].clone()
466481
}
467482

483+
fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty {
484+
let mut ty = None;
485+
if let Some(x) = self.result.expr_adjustments.get(&e) {
486+
if let Some(x) = x.last() {
487+
ty = Some(x.target.clone());
488+
}
489+
}
490+
ty.unwrap_or_else(|| self.expr_ty(e))
491+
}
492+
468493
fn is_upvar(&self, place: &HirPlace) -> bool {
469494
let b = &self.body[place.local];
470495
if let Some(c) = self.current_closure {
@@ -701,7 +726,9 @@ impl InferenceContext<'_> {
701726
};
702727
self.consume_expr(*body);
703728
for item in &self.current_captures {
704-
if matches!(item.kind, CaptureKind::ByRef(BorrowKind::Mut { .. })) {
729+
if matches!(item.kind, CaptureKind::ByRef(BorrowKind::Mut { .. }))
730+
&& !item.place.projections.contains(&ProjectionElem::Deref)
731+
{
705732
// FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in
706733
// MIR. I didn't do that due duplicate diagnostics.
707734
self.result.mutated_bindings_in_closure.insert(item.place.local);

crates/hir-ty/src/layout/tests/closure.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ fn ref_simple() {
4040
y
4141
}
4242
}
43+
size_and_align_expr! {
44+
minicore: copy, deref_mut;
45+
stmts: [
46+
let y: &mut i32 = &mut 5;
47+
]
48+
|x: i32| {
49+
*y += x;
50+
}
51+
}
4352
size_and_align_expr! {
4453
minicore: copy;
4554
stmts: [
@@ -50,6 +59,16 @@ fn ref_simple() {
5059
x
5160
}
5261
}
62+
size_and_align_expr! {
63+
minicore: copy, deref_mut;
64+
stmts: [
65+
struct X(i32, i64);
66+
let x: &mut X = &mut X(2, 6);
67+
]
68+
|| {
69+
(*x).0 as i64 + x.1
70+
}
71+
}
5372
}
5473

5574
#[test]

crates/hir/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,10 @@ impl DefWithBody {
15641564
}
15651565
(mir::MutabilityReason::Not, true) => {
15661566
if !infer.mutated_bindings_in_closure.contains(&binding_id) {
1567-
acc.push(UnusedMut { local }.into())
1567+
let should_ignore = matches!(body[binding_id].name.as_str(), Some(x) if x.starts_with("_"));
1568+
if !should_ignore {
1569+
acc.push(UnusedMut { local }.into())
1570+
}
15681571
}
15691572
}
15701573
}

crates/ide-diagnostics/src/handlers/mutability_errors.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,43 @@ fn f() {
851851
}
852852
"#,
853853
);
854+
check_diagnostics(
855+
r#"
856+
//- minicore: copy, fn, deref_mut
857+
struct X(i32, i64);
858+
859+
fn f() {
860+
let mut x = &mut 5;
861+
//^^^^^ 💡 weak: variable does not need to be mutable
862+
let closure1 = || { *x = 2; };
863+
let _ = closure1();
864+
//^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
865+
let mut x = &mut 5;
866+
//^^^^^ 💡 weak: variable does not need to be mutable
867+
let closure1 = move || { *x = 2; };
868+
let _ = closure1();
869+
//^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
870+
let mut x = &mut X(1, 2);
871+
//^^^^^ 💡 weak: variable does not need to be mutable
872+
let closure1 = || { x.0 = 2; };
873+
let _ = closure1();
874+
//^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
875+
}
876+
"#,
877+
);
878+
}
879+
880+
#[test]
881+
fn allow_unused_mut_for_identifiers_starting_with_underline() {
882+
check_diagnostics(
883+
r#"
884+
fn f(_: i32) {}
885+
fn main() {
886+
let mut _x = 2;
887+
f(_x);
888+
}
889+
"#,
890+
);
854891
}
855892

856893
#[test]

0 commit comments

Comments
 (0)