mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 05:53:45 +00:00
Fix unused-mut
false positive for Box
This commit is contained in:
parent
71f3e4b08c
commit
0408af6453
2 changed files with 83 additions and 12 deletions
|
@ -78,7 +78,7 @@ pub fn borrowck_query(
|
||||||
.map(|body| {
|
.map(|body| {
|
||||||
let body = body?;
|
let body = body?;
|
||||||
Ok(BorrowckResult {
|
Ok(BorrowckResult {
|
||||||
mutability_of_locals: mutability_of_locals(&body),
|
mutability_of_locals: mutability_of_locals(db, &body),
|
||||||
moved_out_of_ref: moved_out_of_ref(db, &body),
|
moved_out_of_ref: moved_out_of_ref(db, &body),
|
||||||
mir_body: body,
|
mir_body: body,
|
||||||
})
|
})
|
||||||
|
@ -186,10 +186,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_place_direct(lvalue: &Place) -> bool {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
!lvalue.projection.iter().any(|x| *x == ProjectionElem::Deref)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ProjectionCase {
|
enum ProjectionCase {
|
||||||
/// Projection is a local
|
/// Projection is a local
|
||||||
Direct,
|
Direct,
|
||||||
|
@ -199,12 +196,14 @@ enum ProjectionCase {
|
||||||
Indirect,
|
Indirect,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn place_case(lvalue: &Place) -> ProjectionCase {
|
fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase {
|
||||||
let mut is_part_of = false;
|
let mut is_part_of = false;
|
||||||
for proj in lvalue.projection.iter().rev() {
|
let mut ty = body.locals[lvalue.local].ty.clone();
|
||||||
|
for proj in lvalue.projection.iter() {
|
||||||
match proj {
|
match proj {
|
||||||
ProjectionElem::Deref => return ProjectionCase::Indirect, // It's indirect
|
ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw
|
||||||
ProjectionElem::ConstantIndex { .. }
|
ProjectionElem::Deref // It's direct in case of `Box<T>`
|
||||||
|
| ProjectionElem::ConstantIndex { .. }
|
||||||
| ProjectionElem::Subslice { .. }
|
| ProjectionElem::Subslice { .. }
|
||||||
| ProjectionElem::Field(_)
|
| ProjectionElem::Field(_)
|
||||||
| ProjectionElem::TupleOrClosureField(_)
|
| ProjectionElem::TupleOrClosureField(_)
|
||||||
|
@ -213,6 +212,23 @@ fn place_case(lvalue: &Place) -> ProjectionCase {
|
||||||
}
|
}
|
||||||
ProjectionElem::OpaqueCast(_) => (),
|
ProjectionElem::OpaqueCast(_) => (),
|
||||||
}
|
}
|
||||||
|
ty = proj.projected_ty(
|
||||||
|
ty,
|
||||||
|
db,
|
||||||
|
|c, subst, f| {
|
||||||
|
let (def, _) = db.lookup_intern_closure(c.into());
|
||||||
|
let infer = db.infer(def);
|
||||||
|
let (captures, _) = infer.closure_info(&c);
|
||||||
|
let parent_subst = ClosureSubst(subst).parent_subst();
|
||||||
|
captures
|
||||||
|
.get(f)
|
||||||
|
.expect("broken closure field")
|
||||||
|
.ty
|
||||||
|
.clone()
|
||||||
|
.substitute(Interner, parent_subst)
|
||||||
|
},
|
||||||
|
body.owner.module(db.upcast()).krate(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if is_part_of {
|
if is_part_of {
|
||||||
ProjectionCase::DirectPart
|
ProjectionCase::DirectPart
|
||||||
|
@ -300,7 +316,10 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap<BasicBlockId, ArenaMap<Local
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, MutabilityReason> {
|
fn mutability_of_locals(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
body: &MirBody,
|
||||||
|
) -> ArenaMap<LocalId, MutabilityReason> {
|
||||||
let mut result: ArenaMap<LocalId, MutabilityReason> =
|
let mut result: ArenaMap<LocalId, MutabilityReason> =
|
||||||
body.locals.iter().map(|x| (x.0, MutabilityReason::Not)).collect();
|
body.locals.iter().map(|x| (x.0, MutabilityReason::Not)).collect();
|
||||||
let mut push_mut_span = |local, span| match &mut result[local] {
|
let mut push_mut_span = |local, span| match &mut result[local] {
|
||||||
|
@ -313,7 +332,7 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, MutabilityReason> {
|
||||||
for statement in &block.statements {
|
for statement in &block.statements {
|
||||||
match &statement.kind {
|
match &statement.kind {
|
||||||
StatementKind::Assign(place, value) => {
|
StatementKind::Assign(place, value) => {
|
||||||
match place_case(place) {
|
match place_case(db, body, place) {
|
||||||
ProjectionCase::Direct => {
|
ProjectionCase::Direct => {
|
||||||
if ever_init_map.get(place.local).copied().unwrap_or_default() {
|
if ever_init_map.get(place.local).copied().unwrap_or_default() {
|
||||||
push_mut_span(place.local, statement.span);
|
push_mut_span(place.local, statement.span);
|
||||||
|
@ -328,7 +347,7 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, MutabilityReason> {
|
||||||
ProjectionCase::Indirect => (),
|
ProjectionCase::Indirect => (),
|
||||||
}
|
}
|
||||||
if let Rvalue::Ref(BorrowKind::Mut { .. }, p) = value {
|
if let Rvalue::Ref(BorrowKind::Mut { .. }, p) = value {
|
||||||
if is_place_direct(p) {
|
if place_case(db, body, p) != ProjectionCase::Indirect {
|
||||||
push_mut_span(p.local, statement.span);
|
push_mut_span(p.local, statement.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -993,6 +993,58 @@ fn f() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn boxes() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
//- minicore: coerce_unsized, deref_mut, slice
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
use core::{marker::Unsize, ops::CoerceUnsized};
|
||||||
|
|
||||||
|
#[lang = "owned_box"]
|
||||||
|
pub struct Box<T: ?Sized> {
|
||||||
|
inner: *mut T,
|
||||||
|
}
|
||||||
|
impl<T> Box<T> {
|
||||||
|
fn new(t: T) -> Self {
|
||||||
|
#[rustc_box]
|
||||||
|
Box::new(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Deref for Box<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&**self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> DerefMut for Box<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
&mut **self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
let x = Box::new(5);
|
||||||
|
x = Box::new(7);
|
||||||
|
//^^^^^^^^^^^^^^^ 💡 error: cannot mutate immutable variable `x`
|
||||||
|
let x = Box::new(5);
|
||||||
|
*x = 7;
|
||||||
|
//^^^^^^ 💡 error: cannot mutate immutable variable `x`
|
||||||
|
let mut y = Box::new(5);
|
||||||
|
//^^^^^ 💡 weak: variable does not need to be mutable
|
||||||
|
*x = *y;
|
||||||
|
//^^^^^^^ 💡 error: cannot mutate immutable variable `x`
|
||||||
|
let x = Box::new(5);
|
||||||
|
let closure = || *x = 2;
|
||||||
|
//^ 💡 error: cannot mutate immutable variable `x`
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn allow_unused_mut_for_identifiers_starting_with_underline() {
|
fn allow_unused_mut_for_identifiers_starting_with_underline() {
|
||||||
check_diagnostics(
|
check_diagnostics(
|
||||||
|
|
Loading…
Reference in a new issue