@@ -22,6 +22,7 @@ use ty;
2222
2323use std:: fmt;
2424use std:: mem;
25+ use rustc_data_structures:: small_vec:: SmallVec ;
2526use rustc_data_structures:: sync:: Lrc ;
2627use syntax:: codemap;
2728use syntax:: ast;
@@ -677,96 +678,75 @@ impl<'tcx> ScopeTree {
677678 -> Scope {
678679 if scope_a == scope_b { return scope_a; }
679680
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;
723698 }
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;
727706 }
728- } ;
729- }
707+ seen. push ( b) ;
708+ mb = self . parent_map . get ( & b) . map ( |s| * s) ;
709+ }
730710
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 ;
740713 }
741- }
714+ } ;
742715
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 {
749717 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+ }
759723 }
724+ }
760725
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 ! ( )
768744 }
769745 }
746+ _ => {
747+ // root ids are always Node right now
748+ bug ! ( )
749+ }
770750 }
771751 }
772752
0 commit comments