@@ -23,8 +23,6 @@ use syntax::source_map::Spanned;
2323use syntax:: ext:: base:: MacroKind ;
2424use syntax_pos:: { Span , DUMMY_SP } ;
2525
26- use std:: result:: Result :: Err ;
27-
2826pub mod blocks;
2927mod collector;
3028mod def_collector;
@@ -183,6 +181,44 @@ pub struct Map<'hir> {
183181 hir_to_node_id : FxHashMap < HirId , NodeId > ,
184182}
185183
184+ struct ParentHirIterator < ' map > {
185+ current_id : HirId ,
186+ map : & ' map Map < ' map > ,
187+ }
188+
189+ impl < ' map > ParentHirIterator < ' map > {
190+ fn new ( current_id : HirId , map : & ' map Map < ' map > ) -> ParentHirIterator < ' map > {
191+ ParentHirIterator {
192+ current_id,
193+ map,
194+ }
195+ }
196+ }
197+
198+ impl < ' map > Iterator for ParentHirIterator < ' map > {
199+ type Item = ( HirId , Node < ' map > ) ;
200+
201+ fn next ( & mut self ) -> Option < Self :: Item > {
202+ if self . current_id == CRATE_HIR_ID {
203+ return None ;
204+ }
205+ loop { // There are nodes that do not have entries, so we need to skip them.
206+ let parent_id = self . map . get_parent_node ( self . current_id ) ;
207+
208+ if parent_id == self . current_id {
209+ self . current_id = CRATE_HIR_ID ;
210+ return None ;
211+ }
212+
213+ self . current_id = parent_id;
214+ if let Some ( entry) = self . map . find_entry ( parent_id) {
215+ return Some ( ( parent_id, entry. node ) ) ;
216+ }
217+ // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`.
218+ }
219+ }
220+ }
221+
186222impl < ' hir > Map < ' hir > {
187223 #[ inline]
188224 fn lookup ( & self , id : HirId ) -> Option < & Entry < ' hir > > {
@@ -682,45 +718,6 @@ impl<'hir> Map<'hir> {
682718 }
683719 }
684720
685-
686- /// If there is some error when walking the parents (e.g., a node does not
687- /// have a parent in the map or a node can't be found), then we return the
688- /// last good `HirId` we found. Note that reaching the crate root (`id == 0`),
689- /// is not an error, since items in the crate module have the crate root as
690- /// parent.
691- fn walk_parent_nodes < F , F2 > ( & self ,
692- start_id : HirId ,
693- found : F ,
694- bail_early : F2 )
695- -> Result < HirId , HirId >
696- where F : Fn ( & Node < ' hir > ) -> bool , F2 : Fn ( & Node < ' hir > ) -> bool
697- {
698- let mut id = start_id;
699- loop {
700- let parent_id = self . get_parent_node ( id) ;
701- if parent_id == CRATE_HIR_ID {
702- return Ok ( CRATE_HIR_ID ) ;
703- }
704- if parent_id == id {
705- return Err ( id) ;
706- }
707-
708- if let Some ( entry) = self . find_entry ( parent_id) {
709- if let Node :: Crate = entry. node {
710- return Err ( id) ;
711- }
712- if found ( & entry. node ) {
713- return Ok ( parent_id) ;
714- } else if bail_early ( & entry. node ) {
715- return Err ( parent_id) ;
716- }
717- id = parent_id;
718- } else {
719- return Err ( id) ;
720- }
721- }
722- }
723-
724721 /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
725722 /// `while` or `loop` before reaching it, as block tail returns are not
726723 /// available in them.
@@ -744,46 +741,64 @@ impl<'hir> Map<'hir> {
744741 /// }
745742 /// ```
746743 pub fn get_return_block ( & self , id : HirId ) -> Option < HirId > {
747- let match_fn = |node : & Node < ' _ > | {
748- match * node {
744+ let mut iter = ParentHirIterator :: new ( id, & self ) . peekable ( ) ;
745+ let mut ignore_tail = false ;
746+ if let Some ( entry) = self . find_entry ( id) {
747+ if let Node :: Expr ( Expr { node : ExprKind :: Ret ( _) , .. } ) = entry. node {
748+ // When dealing with `return` statements, we don't care about climbing only tail
749+ // expressions.
750+ ignore_tail = true ;
751+ }
752+ }
753+ while let Some ( ( hir_id, node) ) = iter. next ( ) {
754+ if let ( Some ( ( _, next_node) ) , false ) = ( iter. peek ( ) , ignore_tail) {
755+ match next_node {
756+ Node :: Block ( Block { expr : None , .. } ) => return None ,
757+ Node :: Block ( Block { expr : Some ( expr) , .. } ) => {
758+ if hir_id != expr. hir_id {
759+ // The current node is not the tail expression of its parent.
760+ return None ;
761+ }
762+ }
763+ _ => { }
764+ }
765+ }
766+ match node {
749767 Node :: Item ( _) |
750768 Node :: ForeignItem ( _) |
751769 Node :: TraitItem ( _) |
752770 Node :: Expr ( Expr { node : ExprKind :: Closure ( ..) , ..} ) |
753- Node :: ImplItem ( _) => true ,
754- _ => false ,
755- }
756- } ;
757- let match_non_returning_block = |node : & Node < ' _ > | {
758- match * node {
771+ Node :: ImplItem ( _) => return Some ( hir_id) ,
759772 Node :: Expr ( ref expr) => {
760773 match expr. node {
761- ExprKind :: Loop ( ..) | ExprKind :: Ret ( ..) => true ,
762- _ => false ,
774+ // Ignore `return`s on the first iteration
775+ ExprKind :: Ret ( ..) | ExprKind :: Loop ( ..) => return None ,
776+ _ => { }
763777 }
764778 }
765- _ => false ,
779+ Node :: Local ( _) => return None ,
780+ _ => { }
766781 }
767- } ;
768-
769- self . walk_parent_nodes ( id, match_fn, match_non_returning_block) . ok ( )
782+ }
783+ None
770784 }
771785
772786 /// Retrieves the `HirId` for `id`'s parent item, or `id` itself if no
773787 /// parent item is in this map. The "parent item" is the closest parent node
774788 /// in the HIR which is recorded by the map and is an item, either an item
775789 /// in a module, trait, or impl.
776790 pub fn get_parent_item ( & self , hir_id : HirId ) -> HirId {
777- match self . walk_parent_nodes ( hir_id, | node| match * node {
778- Node :: Item ( _ ) |
779- Node :: ForeignItem ( _ ) |
780- Node :: TraitItem ( _) |
781- Node :: ImplItem ( _) => true ,
782- _ => false ,
783- } , |_| false ) {
784- Ok ( id ) => id ,
785- Err ( id ) => id ,
791+ for ( hir_id, node) in ParentHirIterator :: new ( hir_id , & self ) {
792+ match node {
793+ Node :: Crate |
794+ Node :: Item ( _) |
795+ Node :: ForeignItem ( _) |
796+ Node :: TraitItem ( _ ) |
797+ Node :: ImplItem ( _ ) => return hir_id ,
798+ _ => { }
799+ }
786800 }
801+ hir_id
787802 }
788803
789804 /// Returns the `DefId` of `id`'s nearest module parent, or `id` itself if no
@@ -795,60 +810,64 @@ impl<'hir> Map<'hir> {
795810 /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
796811 /// module parent is in this map.
797812 pub fn get_module_parent_node ( & self , hir_id : HirId ) -> HirId {
798- match self . walk_parent_nodes ( hir_id, |node| match * node {
799- Node :: Item ( & Item { node : ItemKind :: Mod ( _) , .. } ) => true ,
800- _ => false ,
801- } , |_| false ) {
802- Ok ( id) => id,
803- Err ( id) => id,
813+ for ( hir_id, node) in ParentHirIterator :: new ( hir_id, & self ) {
814+ if let Node :: Item ( & Item { node : ItemKind :: Mod ( _) , .. } ) = node {
815+ return hir_id;
816+ }
804817 }
818+ CRATE_HIR_ID
805819 }
806820
807821 /// Returns the nearest enclosing scope. A scope is roughly an item or block.
808822 pub fn get_enclosing_scope ( & self , hir_id : HirId ) -> Option < HirId > {
809- self . walk_parent_nodes ( hir_id, |node| match * node {
810- Node :: Item ( i) => {
811- match i. node {
812- ItemKind :: Fn ( ..)
813- | ItemKind :: Mod ( ..)
814- | ItemKind :: Enum ( ..)
815- | ItemKind :: Struct ( ..)
816- | ItemKind :: Union ( ..)
817- | ItemKind :: Trait ( ..)
818- | ItemKind :: Impl ( ..) => true ,
819- _ => false ,
820- }
821- } ,
822- Node :: ForeignItem ( fi) => {
823- match fi. node {
824- ForeignItemKind :: Fn ( ..) => true ,
825- _ => false ,
826- }
827- } ,
828- Node :: TraitItem ( ti) => {
829- match ti. node {
830- TraitItemKind :: Method ( ..) => true ,
831- _ => false ,
832- }
833- } ,
834- Node :: ImplItem ( ii) => {
835- match ii. node {
836- ImplItemKind :: Method ( ..) => true ,
837- _ => false ,
838- }
839- } ,
840- Node :: Block ( _) => true ,
841- _ => false ,
842- } , |_| false ) . ok ( )
823+ for ( hir_id, node) in ParentHirIterator :: new ( hir_id, & self ) {
824+ if match node {
825+ Node :: Item ( i) => {
826+ match i. node {
827+ ItemKind :: Fn ( ..)
828+ | ItemKind :: Mod ( ..)
829+ | ItemKind :: Enum ( ..)
830+ | ItemKind :: Struct ( ..)
831+ | ItemKind :: Union ( ..)
832+ | ItemKind :: Trait ( ..)
833+ | ItemKind :: Impl ( ..) => true ,
834+ _ => false ,
835+ }
836+ } ,
837+ Node :: ForeignItem ( fi) => {
838+ match fi. node {
839+ ForeignItemKind :: Fn ( ..) => true ,
840+ _ => false ,
841+ }
842+ } ,
843+ Node :: TraitItem ( ti) => {
844+ match ti. node {
845+ TraitItemKind :: Method ( ..) => true ,
846+ _ => false ,
847+ }
848+ } ,
849+ Node :: ImplItem ( ii) => {
850+ match ii. node {
851+ ImplItemKind :: Method ( ..) => true ,
852+ _ => false ,
853+ }
854+ } ,
855+ Node :: Block ( _) => true ,
856+ _ => false ,
857+ } {
858+ return Some ( hir_id) ;
859+ }
860+ }
861+ None
843862 }
844863
845864 /// Returns the defining scope for an opaque type definition.
846- pub fn get_defining_scope ( & self , id : HirId ) -> Option < HirId > {
865+ pub fn get_defining_scope ( & self , id : HirId ) -> HirId {
847866 let mut scope = id;
848867 loop {
849- scope = self . get_enclosing_scope ( scope) ? ;
868+ scope = self . get_enclosing_scope ( scope) . unwrap_or ( CRATE_HIR_ID ) ;
850869 if scope == CRATE_HIR_ID {
851- return Some ( CRATE_HIR_ID ) ;
870+ return CRATE_HIR_ID ;
852871 }
853872 match self . get ( scope) {
854873 Node :: Item ( i) => {
@@ -861,7 +880,7 @@ impl<'hir> Map<'hir> {
861880 _ => break ,
862881 }
863882 }
864- Some ( scope)
883+ scope
865884 }
866885
867886 pub fn get_parent_did ( & self , id : HirId ) -> DefId {
0 commit comments