@@ -24,6 +24,7 @@ use super::{
2424pub enum MutabilityReason {
2525 Mut { spans : Vec < MirSpan > } ,
2626 Not ,
27+ Unused ,
2728}
2829
2930#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -144,7 +145,8 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
144145 }
145146 }
146147 } ,
147- StatementKind :: Deinit ( _)
148+ StatementKind :: FakeRead ( _)
149+ | StatementKind :: Deinit ( _)
148150 | StatementKind :: StorageLive ( _)
149151 | StatementKind :: StorageDead ( _)
150152 | StatementKind :: Nop => ( ) ,
@@ -264,7 +266,10 @@ fn ever_initialized_map(
264266 is_ever_initialized = false ;
265267 }
266268 }
267- StatementKind :: Deinit ( _) | StatementKind :: Nop | StatementKind :: StorageLive ( _) => ( ) ,
269+ StatementKind :: Deinit ( _)
270+ | StatementKind :: FakeRead ( _)
271+ | StatementKind :: Nop
272+ | StatementKind :: StorageLive ( _) => ( ) ,
268273 }
269274 }
270275 let Some ( terminator) = & block. terminator else {
@@ -331,16 +336,37 @@ fn ever_initialized_map(
331336 result
332337}
333338
339+ fn push_mut_span ( local : LocalId , span : MirSpan , result : & mut ArenaMap < LocalId , MutabilityReason > ) {
340+ match & mut result[ local] {
341+ MutabilityReason :: Mut { spans } => spans. push ( span) ,
342+ it @ ( MutabilityReason :: Not | MutabilityReason :: Unused ) => {
343+ * it = MutabilityReason :: Mut { spans : vec ! [ span] }
344+ }
345+ } ;
346+ }
347+
348+ fn record_usage ( local : LocalId , result : & mut ArenaMap < LocalId , MutabilityReason > ) {
349+ match & mut result[ local] {
350+ it @ MutabilityReason :: Unused => {
351+ * it = MutabilityReason :: Not ;
352+ }
353+ _ => ( ) ,
354+ } ;
355+ }
356+
357+ fn record_usage_for_operand ( arg : & Operand , result : & mut ArenaMap < LocalId , MutabilityReason > ) {
358+ if let Operand :: Copy ( p) | Operand :: Move ( p) = arg {
359+ record_usage ( p. local , result) ;
360+ }
361+ }
362+
334363fn mutability_of_locals (
335364 db : & dyn HirDatabase ,
336365 body : & MirBody ,
337366) -> ArenaMap < LocalId , MutabilityReason > {
338367 let mut result: ArenaMap < LocalId , MutabilityReason > =
339- body. locals . iter ( ) . map ( |it| ( it. 0 , MutabilityReason :: Not ) ) . collect ( ) ;
340- let mut push_mut_span = |local, span| match & mut result[ local] {
341- MutabilityReason :: Mut { spans } => spans. push ( span) ,
342- it @ MutabilityReason :: Not => * it = MutabilityReason :: Mut { spans : vec ! [ span] } ,
343- } ;
368+ body. locals . iter ( ) . map ( |it| ( it. 0 , MutabilityReason :: Unused ) ) . collect ( ) ;
369+
344370 let ever_init_maps = ever_initialized_map ( db, body) ;
345371 for ( block_id, mut ever_init_map) in ever_init_maps. into_iter ( ) {
346372 let block = & body. basic_blocks [ block_id] ;
@@ -350,23 +376,51 @@ fn mutability_of_locals(
350376 match place_case ( db, body, place) {
351377 ProjectionCase :: Direct => {
352378 if ever_init_map. get ( place. local ) . copied ( ) . unwrap_or_default ( ) {
353- push_mut_span ( place. local , statement. span ) ;
379+ push_mut_span ( place. local , statement. span , & mut result ) ;
354380 } else {
355381 ever_init_map. insert ( place. local , true ) ;
356382 }
357383 }
358384 ProjectionCase :: DirectPart => {
359385 // Partial initialization is not supported, so it is definitely `mut`
360- push_mut_span ( place. local , statement. span ) ;
386+ push_mut_span ( place. local , statement. span , & mut result) ;
387+ }
388+ ProjectionCase :: Indirect => {
389+ record_usage ( place. local , & mut result) ;
361390 }
362- ProjectionCase :: Indirect => ( ) ,
391+ }
392+ match value {
393+ Rvalue :: CopyForDeref ( p)
394+ | Rvalue :: Discriminant ( p)
395+ | Rvalue :: Len ( p)
396+ | Rvalue :: Ref ( _, p) => {
397+ record_usage ( p. local , & mut result) ;
398+ }
399+ Rvalue :: Use ( o)
400+ | Rvalue :: Repeat ( o, _)
401+ | Rvalue :: Cast ( _, o, _)
402+ | Rvalue :: UnaryOp ( _, o) => record_usage_for_operand ( o, & mut result) ,
403+ Rvalue :: CheckedBinaryOp ( _, o1, o2) => {
404+ for o in [ o1, o2] {
405+ record_usage_for_operand ( o, & mut result) ;
406+ }
407+ }
408+ Rvalue :: Aggregate ( _, args) => {
409+ for arg in args. iter ( ) {
410+ record_usage_for_operand ( arg, & mut result) ;
411+ }
412+ }
413+ Rvalue :: ShallowInitBox ( _, _) | Rvalue :: ShallowInitBoxWithAlloc ( _) => ( ) ,
363414 }
364415 if let Rvalue :: Ref ( BorrowKind :: Mut { .. } , p) = value {
365416 if place_case ( db, body, p) != ProjectionCase :: Indirect {
366- push_mut_span ( p. local , statement. span ) ;
417+ push_mut_span ( p. local , statement. span , & mut result ) ;
367418 }
368419 }
369420 }
421+ StatementKind :: FakeRead ( p) => {
422+ record_usage ( p. local , & mut result) ;
423+ }
370424 StatementKind :: StorageDead ( p) => {
371425 ever_init_map. insert ( * p, false ) ;
372426 }
@@ -386,15 +440,21 @@ fn mutability_of_locals(
386440 | TerminatorKind :: FalseEdge { .. }
387441 | TerminatorKind :: FalseUnwind { .. }
388442 | TerminatorKind :: GeneratorDrop
389- | TerminatorKind :: SwitchInt { .. }
390443 | TerminatorKind :: Drop { .. }
391444 | TerminatorKind :: DropAndReplace { .. }
392445 | TerminatorKind :: Assert { .. }
393446 | TerminatorKind :: Yield { .. } => ( ) ,
394- TerminatorKind :: Call { destination, .. } => {
447+ TerminatorKind :: SwitchInt { discr, targets : _ } => {
448+ record_usage_for_operand ( discr, & mut result) ;
449+ }
450+ TerminatorKind :: Call { destination, args, func, .. } => {
451+ record_usage_for_operand ( func, & mut result) ;
452+ for arg in args. iter ( ) {
453+ record_usage_for_operand ( arg, & mut result) ;
454+ }
395455 if destination. projection . lookup ( & body. projection_store ) . len ( ) == 0 {
396456 if ever_init_map. get ( destination. local ) . copied ( ) . unwrap_or_default ( ) {
397- push_mut_span ( destination. local , MirSpan :: Unknown ) ;
457+ push_mut_span ( destination. local , MirSpan :: Unknown , & mut result ) ;
398458 } else {
399459 ever_init_map. insert ( destination. local , true ) ;
400460 }
0 commit comments