From ebaaafcd5d9c71745bfb489e51b074ce00d2e158 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Wed, 14 Sep 2016 09:55:20 +0000
Subject: [PATCH] Peform def id assignment during expansion.

---
 src/librustc/hir/map/def_collector.rs | 86 +++++++++++++++++----------
 src/librustc/hir/map/definitions.rs   |  9 +--
 src/librustc/hir/map/mod.rs           |  2 +-
 src/librustc_driver/driver.rs         |  3 -
 src/librustc_resolve/lib.rs           | 16 ++++-
 src/librustc_resolve/macros.rs        | 43 +++++++++++---
 6 files changed, 106 insertions(+), 53 deletions(-)

diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index b0a717e18f9..1fb078ec325 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -18,31 +18,33 @@ use middle::cstore::InlinedItem;
 
 use syntax::ast::*;
 use syntax::visit;
-use syntax::parse::token;
+use syntax::parse::token::{self, keywords};
 
 /// Creates def ids for nodes in the HIR.
-pub struct DefCollector<'ast> {
+pub struct DefCollector<'a> {
     // If we are walking HIR (c.f., AST), we need to keep a reference to the
     // crate.
-    hir_crate: Option<&'ast hir::Crate>,
-    definitions: &'ast mut Definitions,
+    hir_crate: Option<&'a hir::Crate>,
+    definitions: &'a mut Definitions,
     parent_def: Option<DefIndex>,
+    pub visit_macro_invoc: Option<&'a mut FnMut(NodeId, DefIndex)>,
 }
 
-impl<'ast> DefCollector<'ast> {
-    pub fn new(definitions: &'ast mut Definitions) -> DefCollector<'ast> {
+impl<'a> DefCollector<'a> {
+    pub fn new(definitions: &'a mut Definitions) -> Self {
         DefCollector {
             hir_crate: None,
             definitions: definitions,
             parent_def: None,
+            visit_macro_invoc: None,
         }
     }
 
     pub fn extend(parent_node: NodeId,
                   parent_def_path: DefPath,
                   parent_def_id: DefId,
-                  definitions: &'ast mut Definitions)
-                  -> DefCollector<'ast> {
+                  definitions: &'a mut Definitions)
+                  -> Self {
         let mut collector = DefCollector::new(definitions);
 
         assert_eq!(parent_def_path.krate, parent_def_id.krate);
@@ -65,7 +67,7 @@ impl<'ast> DefCollector<'ast> {
         self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
     }
 
-    pub fn walk_item(&mut self, ii: &'ast InlinedItem, krate: &'ast hir::Crate) {
+    pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) {
         self.hir_crate = Some(krate);
         ii.visit(self);
     }
@@ -84,7 +86,7 @@ impl<'ast> DefCollector<'ast> {
         self.definitions.create_def_with_parent(parent, node_id, data)
     }
 
-    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
+    pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
         let parent = self.parent_def;
         self.parent_def = Some(parent_def);
         f(self);
@@ -106,7 +108,7 @@ impl<'ast> DefCollector<'ast> {
         self.create_def(expr.id, DefPathData::Initializer);
     }
 
-    fn visit_hir_const_integer(&mut self, expr: &'ast hir::Expr) {
+    fn visit_hir_const_integer(&mut self, expr: &hir::Expr) {
         // FIXME(eddyb) Closures should have separate
         // function definition IDs and expression IDs.
         if let hir::ExprClosure(..) = expr.node {
@@ -115,9 +117,15 @@ impl<'ast> DefCollector<'ast> {
 
         self.create_def(expr.id, DefPathData::Initializer);
     }
+
+    fn visit_macro_invoc(&mut self, id: NodeId) {
+        if let Some(ref mut visit) = self.visit_macro_invoc {
+            visit(id, self.parent_def.unwrap());
+        }
+    }
 }
 
-impl<'ast> visit::Visitor for DefCollector<'ast> {
+impl<'a> visit::Visitor for DefCollector<'a> {
     fn visit_item(&mut self, i: &Item) {
         debug!("visit_item: {:?}", i);
 
@@ -129,10 +137,14 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
             ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
                 DefPathData::TypeNs(i.ident.name.as_str()),
+            ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
+                return visit::walk_item(self, i);
+            }
             ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
                 DefPathData::ValueNs(i.ident.name.as_str()),
-            ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name.as_str()),
+            ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder
+            ItemKind::Mac(..) => return self.visit_macro_invoc(i.id),
             ItemKind::Use(..) => DefPathData::Misc,
         };
         let def = self.create_def(i.id, def_data);
@@ -198,7 +210,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
             TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
                 DefPathData::ValueNs(ti.ident.name.as_str()),
             TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
-            TraitItemKind::Macro(..) => DefPathData::MacroDef(ti.ident.name.as_str()),
+            TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
         };
 
         let def = self.create_def(ti.id, def_data);
@@ -216,7 +228,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
                 DefPathData::ValueNs(ii.ident.name.as_str()),
             ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
-            ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name.as_str()),
+            ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
         };
 
         let def = self.create_def(ii.id, def_data);
@@ -232,9 +244,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
     fn visit_pat(&mut self, pat: &Pat) {
         let parent_def = self.parent_def;
 
-        if let PatKind::Ident(_, id, _) = pat.node {
-            let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
-            self.parent_def = Some(def);
+        match pat.node {
+            PatKind::Mac(..) => return self.visit_macro_invoc(pat.id),
+            PatKind::Ident(_, id, _) => {
+                let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
+                self.parent_def = Some(def);
+            }
+            _ => {}
         }
 
         visit::walk_pat(self, pat);
@@ -244,13 +260,14 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
     fn visit_expr(&mut self, expr: &Expr) {
         let parent_def = self.parent_def;
 
-        if let ExprKind::Repeat(_, ref count) = expr.node {
-            self.visit_ast_const_integer(count);
-        }
-
-        if let ExprKind::Closure(..) = expr.node {
-            let def = self.create_def(expr.id, DefPathData::ClosureExpr);
-            self.parent_def = Some(def);
+        match expr.node {
+            ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
+            ExprKind::Repeat(_, ref count) => self.visit_ast_const_integer(count),
+            ExprKind::Closure(..) => {
+                let def = self.create_def(expr.id, DefPathData::ClosureExpr);
+                self.parent_def = Some(def);
+            }
+            _ => {}
         }
 
         visit::walk_expr(self, expr);
@@ -258,11 +275,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
     }
 
     fn visit_ty(&mut self, ty: &Ty) {
-        if let TyKind::FixedLengthVec(_, ref length) = ty.node {
-            self.visit_ast_const_integer(length);
-        }
-        if let TyKind::ImplTrait(..) = ty.node {
-            self.create_def(ty.id, DefPathData::ImplTrait);
+        match ty.node {
+            TyKind::Mac(..) => return self.visit_macro_invoc(ty.id),
+            TyKind::FixedLengthVec(_, ref length) => self.visit_ast_const_integer(length),
+            TyKind::ImplTrait(..) => {
+                self.create_def(ty.id, DefPathData::ImplTrait);
+            }
+            _ => {}
         }
         visit::walk_ty(self, ty);
     }
@@ -274,6 +293,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
     fn visit_macro_def(&mut self, macro_def: &MacroDef) {
         self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
     }
+
+    fn visit_stmt(&mut self, stmt: &Stmt) {
+        match stmt.node {
+            StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id),
+            _ => visit::walk_stmt(self, stmt),
+        }
+    }
 }
 
 // We walk the HIR rather than the AST when reading items from metadata.
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 5cfb71f4fc8..f87844652cc 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -9,11 +9,10 @@
 // except according to those terms.
 
 use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
-use hir::map::def_collector::DefCollector;
 use rustc_data_structures::fnv::FnvHashMap;
 use std::fmt::Write;
 use std::hash::{Hash, Hasher, SipHasher};
-use syntax::{ast, visit};
+use syntax::ast;
 use syntax::parse::token::{self, InternedString};
 use ty::TyCtxt;
 use util::nodemap::NodeMap;
@@ -224,12 +223,6 @@ impl Definitions {
         }
     }
 
-    pub fn collect(&mut self, krate: &ast::Crate) {
-        let mut def_collector = DefCollector::new(self);
-        def_collector.collect_root();
-        visit::walk_crate(&mut def_collector, krate);
-    }
-
     /// Get the number of definitions.
     pub fn len(&self) -> usize {
         self.data.len()
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index b351bd427ac..cd085177ed7 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -11,7 +11,7 @@
 pub use self::Node::*;
 use self::MapEntry::*;
 use self::collector::NodeCollector;
-use self::def_collector::DefCollector;
+pub use self::def_collector::DefCollector;
 pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
                             DisambiguatedDefPathData, InlinedRootPath};
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 9d5dce7ad05..226eb545d2c 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -733,9 +733,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
         })
     })?;
 
-    // Collect defintions for def ids.
-    time(sess.time_passes(), "collecting defs", || resolver.definitions.collect(&krate));
-
     time(sess.time_passes(),
          "early lint checks",
          || lint::check_ast_crate(sess, &krate));
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index fb9819b72ab..467967a4f33 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -42,7 +42,7 @@ use self::RibKind::*;
 use self::UseLexicalScopeFlag::*;
 use self::ModulePrefixResult::*;
 
-use rustc::hir::map::Definitions;
+use rustc::hir::map::{Definitions, DefCollector};
 use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr};
 use rustc::middle::cstore::CrateLoader;
 use rustc::session::Session;
@@ -1188,13 +1188,16 @@ impl<'a> Resolver<'a> {
         let mut module_map = NodeMap();
         module_map.insert(CRATE_NODE_ID, graph_root);
 
+        let mut definitions = Definitions::new();
+        DefCollector::new(&mut definitions).collect_root();
+
         let mut expansion_data = FnvHashMap();
-        expansion_data.insert(0, macros::ExpansionData::default()); // Crate root expansion
+        expansion_data.insert(0, macros::ExpansionData::root()); // Crate root expansion
 
         Resolver {
             session: session,
 
-            definitions: Definitions::new(),
+            definitions: definitions,
             macros_at_scope: FnvHashMap(),
 
             // The outermost module has def ID 0; this is not reflected in the
@@ -1264,6 +1267,13 @@ impl<'a> Resolver<'a> {
 
     /// Entry point to crate resolution.
     pub fn resolve_crate(&mut self, krate: &Crate) {
+        // Collect `DefId`s for exported macro defs.
+        for def in &krate.exported_macros {
+            DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
+                collector.visit_macro_def(def)
+            })
+        }
+
         self.current_module = self.graph_root;
         visit::walk_crate(self, krate);
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 3a9fb845190..ebfdc32fabd 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 use Resolver;
+use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
+use rustc::hir::map::DefCollector;
 use rustc::middle::cstore::LoadedMacro;
 use rustc::util::nodemap::FnvHashMap;
 use std::cell::RefCell;
@@ -27,9 +29,19 @@ use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::visit::{self, Visitor};
 use syntax_pos::Span;
 
-#[derive(Clone, Default)]
+#[derive(Clone)]
 pub struct ExpansionData {
     module: Rc<ModuleData>,
+    def_index: DefIndex,
+}
+
+impl ExpansionData {
+    pub fn root() -> Self {
+        ExpansionData {
+            module: Default::default(),
+            def_index: CRATE_DEF_INDEX,
+        }
+    }
 }
 
 // FIXME(jseyfried): merge with `::ModuleS`.
@@ -46,10 +58,10 @@ impl<'a> base::Resolver for Resolver<'a> {
     }
 
     fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
-        expansion.visit_with(&mut ExpansionVisitor {
-            current_module: self.expansion_data[&mark.as_u32()].module.clone(),
-            resolver: self,
-        });
+        let module = self.expansion_data[&mark.as_u32()].module.clone();
+        let mut visitor = ExpansionVisitor { current_module: module, resolver: self };
+        visitor.collect_def_ids(mark, expansion);
+        expansion.visit_with(&mut visitor);
     }
 
     fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
@@ -166,9 +178,8 @@ struct ExpansionVisitor<'b, 'a: 'b> {
 
 impl<'a, 'b> ExpansionVisitor<'a, 'b> {
     fn visit_invoc(&mut self, id: ast::NodeId) {
-        self.resolver.expansion_data.insert(id.as_u32(), ExpansionData {
-            module: self.current_module.clone(),
-        });
+        self.resolver.expansion_data.get_mut(&id.as_u32()).unwrap().module =
+            self.current_module.clone();
     }
 
     // does this attribute list contain "macro_use"?
@@ -195,6 +206,22 @@ impl<'a, 'b> ExpansionVisitor<'a, 'b> {
 
         false
     }
+
+    fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) {
+        let expansion_data = &mut self.resolver.expansion_data;
+        let module = &self.current_module;
+        let def_index = expansion_data[&mark.as_u32()].def_index;
+        let visit_macro_invoc = &mut |id: ast::NodeId, def_index| {
+            expansion_data.insert(id.as_u32(), ExpansionData {
+                def_index: def_index,
+                module: module.clone(),
+            });
+        };
+
+        let mut def_collector = DefCollector::new(&mut self.resolver.definitions);
+        def_collector.visit_macro_invoc = Some(visit_macro_invoc);
+        def_collector.with_parent(def_index, |def_collector| expansion.visit_with(def_collector));
+    }
 }
 
 macro_rules! method {