refactor(clippy_utils::mir::visit_local_usage): use const generics

encodes the direct relationship between the lengths of `locals` and the
returned list, making the code more type-safe
This commit is contained in:
Ada Alakbarova
2026-02-25 16:14:05 +01:00
parent 625bd5539e
commit c91298aaa0
3 changed files with 38 additions and 34 deletions
@@ -38,15 +38,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver
.local_decls
.iter_enumerated()
.find(|(_, decl)| local.span.contains(decl.source_info.span))
&& let Some(usages) = visit_local_usage(
&[local],
&& let Some([usage]) = visit_local_usage(
[local],
mir,
Location {
block: START_BLOCK,
statement_index: 0,
},
)
&& let [usage] = usages.as_slice()
{
let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty();
+14 -14
View File
@@ -368,25 +368,25 @@ struct CloneUsage {
}
fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, bb: mir::BasicBlock) -> CloneUsage {
if let Some((
LocalUsage {
local_use_locs: cloned_use_locs,
local_consume_or_mutate_locs: cloned_consume_or_mutate_locs,
},
LocalUsage {
local_use_locs: _,
local_consume_or_mutate_locs: clone_consume_or_mutate_locs,
},
)) = visit_local_usage(
&[cloned, clone],
if let Some(
[
LocalUsage {
local_use_locs: cloned_use_locs,
local_consume_or_mutate_locs: cloned_consume_or_mutate_locs,
},
LocalUsage {
local_use_locs: _,
local_consume_or_mutate_locs: clone_consume_or_mutate_locs,
},
],
) = visit_local_usage(
[cloned, clone],
mir,
mir::Location {
block: bb,
statement_index: mir.basic_blocks[bb].statements.len(),
},
)
.map(|mut vec| (vec.remove(0), vec.remove(0)))
{
) {
CloneUsage {
cloned_use_loc: cloned_use_locs.first().copied().into(),
cloned_consume_or_mutate_loc: cloned_consume_or_mutate_locs.first().copied(),
+22 -17
View File
@@ -1,3 +1,5 @@
use std::iter;
use rustc_data_structures::either::Either;
use rustc_hir::{Expr, HirId};
use rustc_index::bit_set::DenseBitSet;
@@ -22,14 +24,17 @@ pub struct LocalUsage {
pub local_consume_or_mutate_locs: Vec<Location>,
}
pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -> Option<Vec<LocalUsage>> {
let init = vec![
pub fn visit_local_usage<const N: usize>(
locals: [Local; N],
mir: &Body<'_>,
location: Location,
) -> Option<[LocalUsage; N]> {
let init = [const {
LocalUsage {
local_use_locs: Vec::new(),
local_consume_or_mutate_locs: Vec::new(),
};
locals.len()
];
}
}; N];
traversal::Postorder::new(&mir.basic_blocks, location.block, None)
.collect::<Vec<_>>()
@@ -44,7 +49,7 @@ pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -
}
let mut v = V {
locals,
locals: &locals,
location,
results: usage,
};
@@ -53,13 +58,13 @@ pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -
})
}
struct V<'a> {
locals: &'a [Local],
struct V<'a, const N: usize> {
locals: &'a [Local; N],
location: Location,
results: Vec<LocalUsage>,
results: [LocalUsage; N],
}
impl<'tcx> Visitor<'tcx> for V<'_> {
impl<'tcx, const N: usize> Visitor<'tcx> for V<'_, N> {
fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location) {
if loc.block == self.location.block && loc.statement_index <= self.location.statement_index {
return;
@@ -67,20 +72,20 @@ fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location)
let local = place.local;
for (i, self_local) in self.locals.iter().enumerate() {
for (self_local, result) in iter::zip(self.locals, &mut self.results) {
if local == *self_local {
if !matches!(
ctx,
PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)
) {
self.results[i].local_use_locs.push(loc);
result.local_use_locs.push(loc);
}
if matches!(
ctx,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move | NonMutatingUseContext::Inspect)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow)
) {
self.results[i].local_consume_or_mutate_locs.push(loc);
result.local_consume_or_mutate_locs.push(loc);
}
}
}
@@ -114,16 +119,16 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool {
/// Convenience wrapper around `visit_local_usage`.
pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option<bool> {
visit_local_usage(
&[local],
[local],
mir,
Location {
block: START_BLOCK,
statement_index: 0,
},
)
.map(|mut vec| {
let LocalUsage { local_use_locs, .. } = vec.remove(0);
let mut locations = local_use_locs
.map(|[local_usage]| {
let mut locations = local_usage
.local_use_locs
.into_iter()
.filter(|&location| !is_local_assignment(mir, local, location));
if let Some(location) = locations.next() {