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:
commit
b218009f46
@ -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);
|
||||
|
@ -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]
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
Loading…
x
Reference in New Issue
Block a user