Auto merge of #14576 - HKalbasi:dev2, r=HKalbasi

Fix explicit deref problems in closure capture

fix the `need-mut` part of #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.
This commit is contained in:
bors 2023-04-14 13:23:49 +00:00
commit b218009f46
4 changed files with 90 additions and 4 deletions

View File

@ -190,6 +190,16 @@ impl InferenceContext<'_> {
}
return Some(place);
}
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
if matches!(
self.expr_ty_after_adjustments(*expr).kind(Interner),
TyKind::Ref(..) | TyKind::Raw(..)
) {
let mut place = self.place_of_expr(*expr)?;
place.projections.push(ProjectionElem::Deref);
return Some(place);
}
}
_ => (),
}
None
@ -371,7 +381,12 @@ impl InferenceContext<'_> {
}
Expr::Field { expr, name: _ } => self.select_from_expr(*expr),
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
if let Some((f, _)) = self.result.method_resolution(tgt_expr) {
if matches!(
self.expr_ty_after_adjustments(*expr).kind(Interner),
TyKind::Ref(..) | TyKind::Raw(..)
) {
self.select_from_expr(*expr);
} else if let Some((f, _)) = self.result.method_resolution(tgt_expr) {
let mutability = 'b: {
if let Some(deref_trait) =
self.resolve_lang_item(LangItem::DerefMut).and_then(|x| x.as_trait())
@ -461,10 +476,20 @@ impl InferenceContext<'_> {
}
}
fn expr_ty(&mut self, expr: ExprId) -> Ty {
fn expr_ty(&self, expr: ExprId) -> Ty {
self.result[expr].clone()
}
fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty {
let mut ty = None;
if let Some(x) = self.result.expr_adjustments.get(&e) {
if let Some(x) = x.last() {
ty = Some(x.target.clone());
}
}
ty.unwrap_or_else(|| self.expr_ty(e))
}
fn is_upvar(&self, place: &HirPlace) -> bool {
let b = &self.body[place.local];
if let Some(c) = self.current_closure {
@ -701,7 +726,9 @@ impl InferenceContext<'_> {
};
self.consume_expr(*body);
for item in &self.current_captures {
if matches!(item.kind, CaptureKind::ByRef(BorrowKind::Mut { .. })) {
if matches!(item.kind, CaptureKind::ByRef(BorrowKind::Mut { .. }))
&& !item.place.projections.contains(&ProjectionElem::Deref)
{
// FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in
// MIR. I didn't do that due duplicate diagnostics.
self.result.mutated_bindings_in_closure.insert(item.place.local);

View File

@ -40,6 +40,15 @@ fn ref_simple() {
y
}
}
size_and_align_expr! {
minicore: copy, deref_mut;
stmts: [
let y: &mut i32 = &mut 5;
]
|x: i32| {
*y += x;
}
}
size_and_align_expr! {
minicore: copy;
stmts: [
@ -50,6 +59,16 @@ fn ref_simple() {
x
}
}
size_and_align_expr! {
minicore: copy, deref_mut;
stmts: [
struct X(i32, i64);
let x: &mut X = &mut X(2, 6);
]
|| {
(*x).0 as i64 + x.1
}
}
}
#[test]

View File

@ -1564,7 +1564,10 @@ impl DefWithBody {
}
(mir::MutabilityReason::Not, true) => {
if !infer.mutated_bindings_in_closure.contains(&binding_id) {
acc.push(UnusedMut { local }.into())
let should_ignore = matches!(body[binding_id].name.as_str(), Some(x) if x.starts_with("_"));
if !should_ignore {
acc.push(UnusedMut { local }.into())
}
}
}
}

View File

@ -851,6 +851,43 @@ fn f() {
}
"#,
);
check_diagnostics(
r#"
//- minicore: copy, fn, deref_mut
struct X(i32, i64);
fn f() {
let mut x = &mut 5;
//^^^^^ 💡 weak: variable does not need to be mutable
let closure1 = || { *x = 2; };
let _ = closure1();
//^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
let mut x = &mut 5;
//^^^^^ 💡 weak: variable does not need to be mutable
let closure1 = move || { *x = 2; };
let _ = closure1();
//^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
let mut x = &mut X(1, 2);
//^^^^^ 💡 weak: variable does not need to be mutable
let closure1 = || { x.0 = 2; };
let _ = closure1();
//^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
}
"#,
);
}
#[test]
fn allow_unused_mut_for_identifiers_starting_with_underline() {
check_diagnostics(
r#"
fn f(_: i32) {}
fn main() {
let mut _x = 2;
f(_x);
}
"#,
);
}
#[test]