@@ -22,6 +22,7 @@ use ty;
22
22
23
23
use std:: fmt;
24
24
use std:: mem;
25
+ use rustc_data_structures:: small_vec:: SmallVec ;
25
26
use rustc_data_structures:: sync:: Lrc ;
26
27
use syntax:: codemap;
27
28
use syntax:: ast;
@@ -677,96 +678,75 @@ impl<'tcx> ScopeTree {
677
678
-> Scope {
678
679
if scope_a == scope_b { return scope_a; }
679
680
680
- // [1] The initial values for `a_buf` and `b_buf` are not used.
681
- // The `ancestors_of` function will return some prefix that
682
- // is re-initialized with new values (or else fallback to a
683
- // heap-allocated vector).
684
- let mut a_buf: [ Scope ; 32 ] = [ scope_a /* [1] */ ; 32 ] ;
685
- let mut a_vec: Vec < Scope > = vec ! [ ] ;
686
- let mut b_buf: [ Scope ; 32 ] = [ scope_b /* [1] */ ; 32 ] ;
687
- let mut b_vec: Vec < Scope > = vec ! [ ] ;
688
- let parent_map = & self . parent_map ;
689
- let a_ancestors = ancestors_of ( parent_map, scope_a, & mut a_buf, & mut a_vec) ;
690
- let b_ancestors = ancestors_of ( parent_map, scope_b, & mut b_buf, & mut b_vec) ;
691
- let mut a_index = a_ancestors. len ( ) - 1 ;
692
- let mut b_index = b_ancestors. len ( ) - 1 ;
693
-
694
- // Here, [ab]_ancestors is a vector going from narrow to broad.
695
- // The end of each vector will be the item where the scope is
696
- // defined; if there are any common ancestors, then the tails of
697
- // the vector will be the same. So basically we want to walk
698
- // backwards from the tail of each vector and find the first point
699
- // where they diverge. If one vector is a suffix of the other,
700
- // then the corresponding scope is a superscope of the other.
701
-
702
- if a_ancestors[ a_index] != b_ancestors[ b_index] {
703
- // In this case, the two regions belong to completely
704
- // different functions. Compare those fn for lexical
705
- // nesting. The reasoning behind this is subtle. See the
706
- // "Modeling closures" section of the README in
707
- // infer::region_constraints for more details.
708
- let a_root_scope = a_ancestors[ a_index] ;
709
- let b_root_scope = a_ancestors[ a_index] ;
710
- return match ( a_root_scope. data ( ) , b_root_scope. data ( ) ) {
711
- ( ScopeData :: Destruction ( a_root_id) ,
712
- ScopeData :: Destruction ( b_root_id) ) => {
713
- if self . closure_is_enclosed_by ( a_root_id, b_root_id) {
714
- // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
715
- scope_b
716
- } else if self . closure_is_enclosed_by ( b_root_id, a_root_id) {
717
- // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
718
- scope_a
719
- } else {
720
- // neither fn encloses the other
721
- bug ! ( )
722
- }
681
+ // Process the lists in tandem from the innermost scope, recording the
682
+ // scopes seen so far. The first scope that comes up for a second time
683
+ // is the nearest common ancestor.
684
+ //
685
+ // Note: another way to compute the nearest common ancestor is to get
686
+ // the full scope chain for both scopes and then compare the chains to
687
+ // find the first scope in a common tail. But getting a parent scope
688
+ // requires a hash table lookup, and we often have very long scope
689
+ // chains (10s or 100s of scopes) that only differ by a few elements at
690
+ // 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: SmallVec < [ Scope ; 32 ] > = SmallVec :: new ( ) ;
694
+ loop {
695
+ if let Some ( a) = ma {
696
+ if seen. iter ( ) . position ( |s| * s == a) . is_some ( ) {
697
+ return a;
723
698
}
724
- _ => {
725
- // root ids are always Node right now
726
- bug ! ( )
699
+ seen. push ( a) ;
700
+ ma = self . parent_map . get ( & a) . map ( |s| * s) ;
701
+ }
702
+
703
+ if let Some ( b) = mb {
704
+ if seen. iter ( ) . position ( |s| * s == b) . is_some ( ) {
705
+ return b;
727
706
}
728
- } ;
729
- }
707
+ seen. push ( b) ;
708
+ mb = self . parent_map . get ( & b) . map ( |s| * s) ;
709
+ }
730
710
731
- loop {
732
- // Loop invariant: a_ancestors[a_index] == b_ancestors[b_index]
733
- // for all indices between a_index and the end of the array
734
- if a_index == 0 { return scope_a; }
735
- if b_index == 0 { return scope_b; }
736
- a_index -= 1 ;
737
- b_index -= 1 ;
738
- if a_ancestors[ a_index] != b_ancestors[ b_index] {
739
- return a_ancestors[ a_index + 1 ] ;
711
+ if ma. is_none ( ) && mb. is_none ( ) {
712
+ break ;
740
713
}
741
- }
714
+ } ;
742
715
743
- fn ancestors_of < ' a , ' tcx > ( parent_map : & FxHashMap < Scope , Scope > ,
744
- scope : Scope ,
745
- buf : & ' a mut [ Scope ; 32 ] ,
746
- vec : & ' a mut Vec < Scope > )
747
- -> & ' a [ Scope ] {
748
- // debug!("ancestors_of(scope={:?})", scope);
716
+ fn outermost_scope ( parent_map : & FxHashMap < Scope , Scope > , scope : Scope ) -> Scope {
749
717
let mut scope = scope;
750
-
751
- let mut i = 0 ;
752
- while i < 32 {
753
- buf[ i] = scope;
754
- match parent_map. get ( & scope) {
755
- Some ( & superscope) => scope = superscope,
756
- _ => return & buf[ ..i+1 ]
757
- }
758
- i += 1 ;
718
+ loop {
719
+ match parent_map. get ( & scope) {
720
+ Some ( & superscope) => scope = superscope,
721
+ None => break scope,
722
+ }
759
723
}
724
+ }
760
725
761
- * vec = Vec :: with_capacity ( 64 ) ;
762
- vec. extend_from_slice ( buf) ;
763
- loop {
764
- vec. push ( scope) ;
765
- match parent_map. get ( & scope) {
766
- Some ( & superscope) => scope = superscope,
767
- _ => return & * vec
726
+ // In this (rare) case, the two regions belong to completely different
727
+ // functions. Compare those fn for lexical nesting. The reasoning
728
+ // behind this is subtle. See the "Modeling closures" section of the
729
+ // README in infer::region_constraints for more details.
730
+ let a_root_scope = outermost_scope ( & self . parent_map , scope_a) ;
731
+ let b_root_scope = outermost_scope ( & self . parent_map , scope_b) ;
732
+ match ( a_root_scope. data ( ) , b_root_scope. data ( ) ) {
733
+ ( ScopeData :: Destruction ( a_root_id) ,
734
+ ScopeData :: Destruction ( b_root_id) ) => {
735
+ if self . closure_is_enclosed_by ( a_root_id, b_root_id) {
736
+ // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
737
+ scope_b
738
+ } else if self . closure_is_enclosed_by ( b_root_id, a_root_id) {
739
+ // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
740
+ scope_a
741
+ } else {
742
+ // neither fn encloses the other
743
+ bug ! ( )
768
744
}
769
745
}
746
+ _ => {
747
+ // root ids are always Node right now
748
+ bug ! ( )
749
+ }
770
750
}
771
751
}
772
752
0 commit comments