@@ -19,8 +19,8 @@ use rustc_data_structures::fx::FxHashSet;
1919use  rustc_data_structures:: graph:: implementation:: { 
2020    Direction ,  Graph ,  NodeIndex ,  INCOMING ,  OUTGOING , 
2121} ; 
22+ use  rustc_index:: bit_set:: BitSet ; 
2223use  rustc_index:: vec:: { Idx ,  IndexVec } ; 
23- use  smallvec:: SmallVec ; 
2424use  std:: fmt; 
2525use  syntax_pos:: Span ; 
2626
@@ -304,8 +304,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
304304    } 
305305
306306    fn  expansion ( & self ,  var_values :  & mut  LexicalRegionResolutions < ' tcx > )  { 
307-         self . iterate_until_fixed_point ( |constraint| { 
308-             debug ! ( "expansion: constraint={:?}" ,  constraint) ; 
307+         let  mut  process_constraint = |constraint :  & Constraint < ' tcx > | { 
309308            let  ( a_region,  b_vid,  b_data,  retain)  = match  * constraint { 
310309                Constraint :: RegSubVar ( a_region,  b_vid)  => { 
311310                    let  b_data = var_values. value_mut ( b_vid) ; 
@@ -331,7 +330,33 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
331330
332331            let  changed = self . expand_node ( a_region,  b_vid,  b_data) ; 
333332            ( changed,  retain) 
334-         } ) 
333+         } ; 
334+ 
335+         // Using bitsets to track the remaining elements is faster than using a 
336+         // `Vec` by itself (which requires removing elements, which requires 
337+         // element shuffling, which is slow). 
338+         let  constraints:  Vec < _ >  = self . data . constraints . keys ( ) . collect ( ) ; 
339+         let  mut  live_indices:  BitSet < usize >  = BitSet :: new_filled ( constraints. len ( ) ) ; 
340+         let  mut  killed_indices:  BitSet < usize >  = BitSet :: new_empty ( constraints. len ( ) ) ; 
341+         let  mut  changed = true ; 
342+         while  changed { 
343+             changed = false ; 
344+             for  index in  live_indices. iter ( )  { 
345+                 let  constraint = constraints[ index] ; 
346+                 let  ( edge_changed,  retain)  = process_constraint ( constraint) ; 
347+                 if  edge_changed { 
348+                     changed = true ; 
349+                 } 
350+                 if  !retain { 
351+                     let  changed = killed_indices. insert ( index) ; 
352+                     debug_assert ! ( changed) ; 
353+                 } 
354+             } 
355+             live_indices. subtract ( & killed_indices) ; 
356+ 
357+             // We could clear `killed_indices` here, but we don't need to and 
358+             // it's cheaper not to. 
359+         } 
335360    } 
336361
337362    // This function is very hot in some workloads. There's a single callsite 
@@ -866,29 +891,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
866891        } 
867892    } 
868893
869-     fn  iterate_until_fixed_point < F > ( & self ,  mut  body :  F ) 
870-     where 
871-         F :  FnMut ( & Constraint < ' tcx > )  -> ( bool ,  bool ) , 
872-     { 
873-         let  mut  constraints:  SmallVec < [ _ ;  16 ] >  = self . data . constraints . keys ( ) . collect ( ) ; 
874-         let  mut  iteration = 0 ; 
875-         let  mut  changed = true ; 
876-         while  changed { 
877-             changed = false ; 
878-             iteration += 1 ; 
879-             debug ! ( "---- Expansion iteration {}" ,  iteration) ; 
880-             constraints. retain ( |constraint| { 
881-                 let  ( edge_changed,  retain)  = body ( constraint) ; 
882-                 if  edge_changed { 
883-                     debug ! ( "updated due to constraint {:?}" ,  constraint) ; 
884-                     changed = true ; 
885-                 } 
886-                 retain
887-             } ) ; 
888-         } 
889-         debug ! ( "---- Expansion complete after {} iteration(s)" ,  iteration) ; 
890-     } 
891- 
892894    fn  bound_is_met ( 
893895        & self , 
894896        bound :  & VerifyBound < ' tcx > , 
0 commit comments