@@ -542,18 +542,6 @@ impl<'tcx> ScopeTree {
542
542
assert ! ( previous. is_none( ) ) ;
543
543
}
544
544
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
-
557
545
fn record_var_scope ( & mut self , var : hir:: ItemLocalId , lifetime : Scope ) {
558
546
debug ! ( "record_var_scope(sub={:?}, sup={:?})" , var, lifetime) ;
559
547
assert ! ( var != lifetime. item_local_id( ) ) ;
@@ -688,65 +676,37 @@ impl<'tcx> ScopeTree {
688
676
// requires a hash table lookup, and we often have very long scope
689
677
// chains (10s or 100s of scopes) that only differ by a few elements at
690
678
// 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
+
695
690
loop {
696
691
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;
699
694
}
700
695
seen_a. push ( a) ;
701
- ma = self . parent_map . get ( & a) . map ( |s| * s ) ;
696
+ ma = self . parent_map . get ( & a) ;
702
697
}
703
698
704
699
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;
707
702
}
708
703
seen_b. push ( b) ;
709
- mb = self . parent_map . get ( & b) . map ( |s| * s ) ;
704
+ mb = self . parent_map . get ( & b) ;
710
705
}
711
706
712
707
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 ! ( ) ;
750
710
}
751
711
}
752
712
}
0 commit comments