@@ -386,82 +386,91 @@ fn ever_initialized_map(
386
386
fn dfs (
387
387
db : & dyn HirDatabase ,
388
388
body : & MirBody ,
389
- b : BasicBlockId ,
390
389
l : LocalId ,
390
+ stack : & mut Vec < BasicBlockId > ,
391
391
result : & mut ArenaMap < BasicBlockId , ArenaMap < LocalId , bool > > ,
392
392
) {
393
- let mut is_ever_initialized = result[ b] [ l] ; // It must be filled, as we use it as mark for dfs
394
- let block = & body. basic_blocks [ b] ;
395
- for statement in & block. statements {
396
- match & statement. kind {
397
- StatementKind :: Assign ( p, _) => {
398
- if p. projection . lookup ( & body. projection_store ) . is_empty ( ) && p. local == l {
399
- is_ever_initialized = true ;
393
+ while let Some ( b) = stack. pop ( ) {
394
+ let mut is_ever_initialized = result[ b] [ l] ; // It must be filled, as we use it as mark for dfs
395
+ let block = & body. basic_blocks [ b] ;
396
+ for statement in & block. statements {
397
+ match & statement. kind {
398
+ StatementKind :: Assign ( p, _) => {
399
+ if p. projection . lookup ( & body. projection_store ) . is_empty ( ) && p. local == l {
400
+ is_ever_initialized = true ;
401
+ }
400
402
}
401
- }
402
- StatementKind :: StorageDead ( p ) => {
403
- if * p == l {
404
- is_ever_initialized = false ;
403
+ StatementKind :: StorageDead ( p ) => {
404
+ if * p == l {
405
+ is_ever_initialized = false ;
406
+ }
405
407
}
408
+ StatementKind :: Deinit ( _)
409
+ | StatementKind :: FakeRead ( _)
410
+ | StatementKind :: Nop
411
+ | StatementKind :: StorageLive ( _) => ( ) ,
406
412
}
407
- StatementKind :: Deinit ( _)
408
- | StatementKind :: FakeRead ( _)
409
- | StatementKind :: Nop
410
- | StatementKind :: StorageLive ( _) => ( ) ,
411
- }
412
- }
413
- let Some ( terminator) = & block. terminator else {
414
- never ! (
415
- "Terminator should be none only in construction.\n The body:\n {}" ,
416
- body. pretty_print( db)
417
- ) ;
418
- return ;
419
- } ;
420
- let mut process = |target, is_ever_initialized| {
421
- if !result[ target] . contains_idx ( l) || !result[ target] [ l] && is_ever_initialized {
422
- result[ target] . insert ( l, is_ever_initialized) ;
423
- dfs ( db, body, target, l, result) ;
424
- }
425
- } ;
426
- match & terminator. kind {
427
- TerminatorKind :: Goto { target } => process ( * target, is_ever_initialized) ,
428
- TerminatorKind :: SwitchInt { targets, .. } => {
429
- targets. all_targets ( ) . iter ( ) . for_each ( |& it| process ( it, is_ever_initialized) ) ;
430
413
}
431
- TerminatorKind :: UnwindResume
432
- | TerminatorKind :: Abort
433
- | TerminatorKind :: Return
434
- | TerminatorKind :: Unreachable => ( ) ,
435
- TerminatorKind :: Call { target, cleanup, destination, .. } => {
436
- if destination. projection . lookup ( & body. projection_store ) . is_empty ( )
437
- && destination. local == l
438
- {
439
- is_ever_initialized = true ;
414
+ let Some ( terminator) = & block. terminator else {
415
+ never ! (
416
+ "Terminator should be none only in construction.\n The body:\n {}" ,
417
+ body. pretty_print( db)
418
+ ) ;
419
+ return ;
420
+ } ;
421
+ let mut process = |target, is_ever_initialized| {
422
+ if !result[ target] . contains_idx ( l) || !result[ target] [ l] && is_ever_initialized {
423
+ result[ target] . insert ( l, is_ever_initialized) ;
424
+ stack. push ( target) ;
425
+ }
426
+ } ;
427
+ match & terminator. kind {
428
+ TerminatorKind :: Goto { target } => process ( * target, is_ever_initialized) ,
429
+ TerminatorKind :: SwitchInt { targets, .. } => {
430
+ targets. all_targets ( ) . iter ( ) . for_each ( |& it| process ( it, is_ever_initialized) ) ;
431
+ }
432
+ TerminatorKind :: UnwindResume
433
+ | TerminatorKind :: Abort
434
+ | TerminatorKind :: Return
435
+ | TerminatorKind :: Unreachable => ( ) ,
436
+ TerminatorKind :: Call { target, cleanup, destination, .. } => {
437
+ if destination. projection . lookup ( & body. projection_store ) . is_empty ( )
438
+ && destination. local == l
439
+ {
440
+ is_ever_initialized = true ;
441
+ }
442
+ target. iter ( ) . chain ( cleanup) . for_each ( |& it| process ( it, is_ever_initialized) ) ;
443
+ }
444
+ TerminatorKind :: Drop { target, unwind, place : _ } => {
445
+ iter:: once ( target)
446
+ . chain ( unwind)
447
+ . for_each ( |& it| process ( it, is_ever_initialized) ) ;
448
+ }
449
+ TerminatorKind :: DropAndReplace { .. }
450
+ | TerminatorKind :: Assert { .. }
451
+ | TerminatorKind :: Yield { .. }
452
+ | TerminatorKind :: CoroutineDrop
453
+ | TerminatorKind :: FalseEdge { .. }
454
+ | TerminatorKind :: FalseUnwind { .. } => {
455
+ never ! ( "We don't emit these MIR terminators yet" ) ;
440
456
}
441
- target. iter ( ) . chain ( cleanup) . for_each ( |& it| process ( it, is_ever_initialized) ) ;
442
- }
443
- TerminatorKind :: Drop { target, unwind, place : _ } => {
444
- iter:: once ( target) . chain ( unwind) . for_each ( |& it| process ( it, is_ever_initialized) ) ;
445
- }
446
- TerminatorKind :: DropAndReplace { .. }
447
- | TerminatorKind :: Assert { .. }
448
- | TerminatorKind :: Yield { .. }
449
- | TerminatorKind :: CoroutineDrop
450
- | TerminatorKind :: FalseEdge { .. }
451
- | TerminatorKind :: FalseUnwind { .. } => {
452
- never ! ( "We don't emit these MIR terminators yet" ) ;
453
457
}
454
458
}
455
459
}
460
+ let mut stack = Vec :: new ( ) ;
456
461
for & l in & body. param_locals {
457
462
result[ body. start_block ] . insert ( l, true ) ;
458
- dfs ( db, body, body. start_block , l, & mut result) ;
463
+ stack. clear ( ) ;
464
+ stack. push ( body. start_block ) ;
465
+ dfs ( db, body, l, & mut stack, & mut result) ;
459
466
}
460
467
for l in body. locals . iter ( ) . map ( |it| it. 0 ) {
461
468
db. unwind_if_cancelled ( ) ;
462
469
if !result[ body. start_block ] . contains_idx ( l) {
463
470
result[ body. start_block ] . insert ( l, false ) ;
464
- dfs ( db, body, body. start_block , l, & mut result) ;
471
+ stack. clear ( ) ;
472
+ stack. push ( body. start_block ) ;
473
+ dfs ( db, body, l, & mut stack, & mut result) ;
465
474
}
466
475
}
467
476
result
0 commit comments