@@ -24,6 +24,7 @@ use super::{
24
24
pub enum MutabilityReason {
25
25
Mut { spans : Vec < MirSpan > } ,
26
26
Not ,
27
+ Unused ,
27
28
}
28
29
29
30
#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -144,7 +145,8 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
144
145
}
145
146
}
146
147
} ,
147
- StatementKind :: Deinit ( _)
148
+ StatementKind :: FakeRead ( _)
149
+ | StatementKind :: Deinit ( _)
148
150
| StatementKind :: StorageLive ( _)
149
151
| StatementKind :: StorageDead ( _)
150
152
| StatementKind :: Nop => ( ) ,
@@ -264,7 +266,10 @@ fn ever_initialized_map(
264
266
is_ever_initialized = false ;
265
267
}
266
268
}
267
- StatementKind :: Deinit ( _) | StatementKind :: Nop | StatementKind :: StorageLive ( _) => ( ) ,
269
+ StatementKind :: Deinit ( _)
270
+ | StatementKind :: FakeRead ( _)
271
+ | StatementKind :: Nop
272
+ | StatementKind :: StorageLive ( _) => ( ) ,
268
273
}
269
274
}
270
275
let Some ( terminator) = & block. terminator else {
@@ -331,16 +336,37 @@ fn ever_initialized_map(
331
336
result
332
337
}
333
338
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
+
334
363
fn mutability_of_locals (
335
364
db : & dyn HirDatabase ,
336
365
body : & MirBody ,
337
366
) -> ArenaMap < LocalId , MutabilityReason > {
338
367
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
+
344
370
let ever_init_maps = ever_initialized_map ( db, body) ;
345
371
for ( block_id, mut ever_init_map) in ever_init_maps. into_iter ( ) {
346
372
let block = & body. basic_blocks [ block_id] ;
@@ -350,23 +376,51 @@ fn mutability_of_locals(
350
376
match place_case ( db, body, place) {
351
377
ProjectionCase :: Direct => {
352
378
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 ) ;
354
380
} else {
355
381
ever_init_map. insert ( place. local , true ) ;
356
382
}
357
383
}
358
384
ProjectionCase :: DirectPart => {
359
385
// 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) ;
361
390
}
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 ( _) => ( ) ,
363
414
}
364
415
if let Rvalue :: Ref ( BorrowKind :: Mut { .. } , p) = value {
365
416
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 ) ;
367
418
}
368
419
}
369
420
}
421
+ StatementKind :: FakeRead ( p) => {
422
+ record_usage ( p. local , & mut result) ;
423
+ }
370
424
StatementKind :: StorageDead ( p) => {
371
425
ever_init_map. insert ( * p, false ) ;
372
426
}
@@ -386,15 +440,21 @@ fn mutability_of_locals(
386
440
| TerminatorKind :: FalseEdge { .. }
387
441
| TerminatorKind :: FalseUnwind { .. }
388
442
| TerminatorKind :: GeneratorDrop
389
- | TerminatorKind :: SwitchInt { .. }
390
443
| TerminatorKind :: Drop { .. }
391
444
| TerminatorKind :: DropAndReplace { .. }
392
445
| TerminatorKind :: Assert { .. }
393
446
| 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
+ }
395
455
if destination. projection . lookup ( & body. projection_store ) . len ( ) == 0 {
396
456
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 ) ;
398
458
} else {
399
459
ever_init_map. insert ( destination. local , true ) ;
400
460
}
0 commit comments