@@ -542,18 +542,6 @@ impl<'tcx> ScopeTree {
542542 assert ! ( previous. is_none( ) ) ;
543543 }
544544
545- fn closure_is_enclosed_by ( & self ,
546- mut sub_closure : hir:: ItemLocalId ,
547- sup_closure : hir:: ItemLocalId ) -> bool {
548- loop {
549- if sub_closure == sup_closure { return true ; }
550- match self . closure_tree . get ( & sub_closure) {
551- Some ( & s) => { sub_closure = s; }
552- None => { return false ; }
553- }
554- }
555- }
556-
557545 fn record_var_scope ( & mut self , var : hir:: ItemLocalId , lifetime : Scope ) {
558546 debug ! ( "record_var_scope(sub={:?}, sup={:?})" , var, lifetime) ;
559547 assert ! ( var != lifetime. item_local_id( ) ) ;
@@ -688,65 +676,37 @@ impl<'tcx> ScopeTree {
688676 // requires a hash table lookup, and we often have very long scope
689677 // chains (10s or 100s of scopes) that only differ by a few elements at
690678 // the start. So this algorithm is faster.
691- let mut ma = Some ( scope_a) ;
692- let mut mb = Some ( scope_b) ;
693- let mut seen_a: SmallVec < [ Scope ; 32 ] > = SmallVec :: new ( ) ;
694- let mut seen_b: SmallVec < [ Scope ; 32 ] > = SmallVec :: new ( ) ;
679+
680+ let mut ma = Some ( & scope_a) ;
681+ let mut mb = Some ( & scope_b) ;
682+
683+ // A HashSet<Scope> is a more obvious choice for these, but SmallVec is
684+ // faster because the set size is normally small so linear search is
685+ // as good or better than a hash table lookup, plus the size is usually
686+ // small enough to avoid a heap allocation.
687+ let mut seen_a: SmallVec < [ & Scope ; 32 ] > = SmallVec :: new ( ) ;
688+ let mut seen_b: SmallVec < [ & Scope ; 32 ] > = SmallVec :: new ( ) ;
689+
695690 loop {
696691 if let Some ( a) = ma {
697- if seen_b. iter ( ) . position ( |s| * s == a) . is_some ( ) {
698- return a;
692+ if seen_b. iter ( ) . any ( |s| * s == a) {
693+ return * a;
699694 }
700695 seen_a. push ( a) ;
701- ma = self . parent_map . get ( & a) . map ( |s| * s ) ;
696+ ma = self . parent_map . get ( & a) ;
702697 }
703698
704699 if let Some ( b) = mb {
705- if seen_a. iter ( ) . position ( |s| * s == b) . is_some ( ) {
706- return b;
700+ if seen_a. iter ( ) . any ( |s| * s == b) {
701+ return * b;
707702 }
708703 seen_b. push ( b) ;
709- mb = self . parent_map . get ( & b) . map ( |s| * s ) ;
704+ mb = self . parent_map . get ( & b) ;
710705 }
711706
712707 if ma. is_none ( ) && mb. is_none ( ) {
713- break ;
714- }
715- } ;
716-
717- fn outermost_scope ( parent_map : & FxHashMap < Scope , Scope > , scope : Scope ) -> Scope {
718- let mut scope = scope;
719- loop {
720- match parent_map. get ( & scope) {
721- Some ( & superscope) => scope = superscope,
722- None => break scope,
723- }
724- }
725- }
726-
727- // In this (rare) case, the two regions belong to completely different
728- // functions. Compare those fn for lexical nesting. The reasoning
729- // behind this is subtle. See the "Modeling closures" section of the
730- // README in infer::region_constraints for more details.
731- let a_root_scope = outermost_scope ( & self . parent_map , scope_a) ;
732- let b_root_scope = outermost_scope ( & self . parent_map , scope_b) ;
733- match ( a_root_scope. data ( ) , b_root_scope. data ( ) ) {
734- ( ScopeData :: Destruction ( a_root_id) ,
735- ScopeData :: Destruction ( b_root_id) ) => {
736- if self . closure_is_enclosed_by ( a_root_id, b_root_id) {
737- // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
738- scope_b
739- } else if self . closure_is_enclosed_by ( b_root_id, a_root_id) {
740- // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
741- scope_a
742- } else {
743- // neither fn encloses the other
744- bug ! ( )
745- }
746- }
747- _ => {
748- // root ids are always Node right now
749- bug ! ( )
708+ // No nearest common ancestor found.
709+ bug ! ( ) ;
750710 }
751711 }
752712 }
0 commit comments