Repository: rust-analyzer/rust-analyzer
Pull request #2489 (2019-12-06 18:52:39)

Implement `format_args`
This fixes a huge amount of type mismatches (because every format call was a type mismatch so far); I also hoped to get go to def working within `format!` etc., and the test says it should, but in practice it still doesn't seem to...

Also remove the `len` parameter from `Name::new_inline_ascii`, which I'm assuming was only there because of `const fn` limitations?

cc @edwin0cheng 

edwin0cheng: Oh... nice, but If I remember correctly, `format_args!` should be `eager` expansion ?
e.g.
```rust
fn main() {
    format!(concat!("ABC","DEF"));
}
```
flodiebold: I don't think that really matters for now, I ignore the format string anyway :sweat_smile: 
edwin0cheng: > to get go to def working within format! and the test says it should, but in practice it still doesn't seem to...

I think it is because :

https://github.com/rust-analyzer/rust-analyzer/blob/a25e8cff6755c1a0c46ee3690dcd75b641c0b3e4/crates/ra_hir_expand/src/db.rs#L45-L49

We should set it to `mbe::Origin::Call` , right now `quote!` macro produce `tt::TokenId::unspecific` , so all builtin macro def do not produce any TokenId.

flodiebold: Just setting it to `mbe::Origin::Call` doesn't seem to do it :confused: 
flodiebold: The problem seems to be [here](https://github.com/rust-analyzer/rust-analyzer/blob/d3702c02cdff158f05d2af1bd7106cca8a3e4ba9/crates/ra_hir/src/source_binder.rs#L304), we're not getting an expr ID :confused: 

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index a95f9139f1..0e7594f807 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -13,11 +13,6 @@ name = "anyhow"
 version = "1.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "anymap"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "arrayvec"
 version = "0.5.1"
@@ -963,7 +958,6 @@ dependencies = [
 name = "ra_hir_def"
 version = "0.1.0"
 dependencies = [
- "anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1782,7 +1776,6 @@ dependencies = [
 [metadata]
 "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
 "checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
-"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
 "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
 "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
 "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 437f800c1e..5cb222bd38 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,7 +1,9 @@
 //! FIXME: write short doc here
+use either::Either;
+
 use hir_def::{
-    child_by_source::ChildBySource, dyn_map::DynMap, keys, nameres::ModuleSource, AstItemDef,
-    EnumVariantId, LocationCtx, ModuleId, VariantId,
+    child_from_source::ChildFromSource, nameres::ModuleSource, AstItemDef, EnumVariantId, ImplId,
+    LocationCtx, ModuleId, TraitId, VariantId,
 };
 use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
 use ra_syntax::{
@@ -51,9 +53,8 @@ impl FromSource for Trait {
 impl FromSource for Function {
     type Ast = ast::FnDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
-        Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::FUNCTION]
-            .get(&src)
-            .copied()
+        Container::find(db, src.as_ref().map(|it| it.syntax()))?
+            .child_from_source(db, src)
             .map(Function::from)
     }
 }
@@ -61,29 +62,26 @@ impl FromSource for Function {
 impl FromSource for Const {
     type Ast = ast::ConstDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
-        Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::CONST]
-            .get(&src)
-            .copied()
+        Container::find(db, src.as_ref().map(|it| it.syntax()))?
+            .child_from_source(db, src)
             .map(Const::from)
     }
 }
 impl FromSource for Static {
     type Ast = ast::StaticDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
-        Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::STATIC]
-            .get(&src)
-            .copied()
-            .map(Static::from)
+        match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
+            Container::Module(it) => it.id.child_from_source(db, src).map(Static::from),
+            Container::Trait(_) | Container::ImplBlock(_) => None,
+        }
     }
 }
 
 impl FromSource for TypeAlias {
     type Ast = ast::TypeAliasDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
-        Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)
-            [keys::TYPE_ALIAS]
-            .get(&src)
-            .copied()
+        Container::find(db, src.as_ref().map(|it| it.syntax()))?
+            .child_from_source(db, src)
             .map(TypeAlias::from)
     }
 }
@@ -118,41 +116,32 @@ impl FromSource for EnumVariant {
         let parent_enum = src.value.parent_enum();
         let src_enum = InFile { file_id: src.file_id, value: parent_enum };
         let parent_enum = Enum::from_source(db, src_enum)?;
-        parent_enum.id.child_by_source(db)[keys::ENUM_VARIANT]
-            .get(&src)
-            .copied()
-            .map(EnumVariant::from)
+        parent_enum.id.child_from_source(db, src).map(EnumVariant::from)
     }
 }
 
 impl FromSource for StructField {
     type Ast = FieldSource;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
-        let src = src.as_ref();
-
-        // FIXME this is buggy
         let variant_id: VariantId = match src.value {
-            FieldSource::Named(field) => {
+            FieldSource::Named(ref field) => {
                 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?;
                 let src = InFile { file_id: src.file_id, value };
                 let def = Struct::from_source(db, src)?;
                 def.id.into()
             }
-            FieldSource::Pos(field) => {
+            FieldSource::Pos(ref field) => {
                 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?;
                 let src = InFile { file_id: src.file_id, value };
                 let def = EnumVariant::from_source(db, src)?;
                 EnumVariantId::from(def).into()
             }
         };
-
-        let dyn_map = variant_id.child_by_source(db);
-        match src.value {
-            FieldSource::Pos(it) => dyn_map[keys::TUPLE_FIELD].get(&src.with_value(it.clone())),
-            FieldSource::Named(it) => dyn_map[keys::RECORD_FIELD].get(&src.with_value(it.clone())),
-        }
-        .copied()
-        .map(StructField::from)
+        let src = src.map(|field_source| match field_source {
+            FieldSource::Pos(it) => Either::Left(it),
+            FieldSource::Named(it) => Either::Right(it),
+        });
+        variant_id.child_from_source(db, src).map(StructField::from)
     }
 }
 
@@ -266,12 +255,21 @@ impl Container {
     }
 }
 
-impl ChildBySource for Container {
-    fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
+impl<CHILD, SOURCE> ChildFromSource<CHILD, SOURCE> for Container
+where
+    TraitId: ChildFromSource<CHILD, SOURCE>,
+    ImplId: ChildFromSource<CHILD, SOURCE>,
+    ModuleId: ChildFromSource<CHILD, SOURCE>,
+{
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<SOURCE>,
+    ) -> Option<CHILD> {
         match self {
-            Container::Trait(it) => it.id.child_by_source(db),
-            Container::ImplBlock(it) => it.id.child_by_source(db),
-            Container::Module(it) => it.id.child_by_source(db),
+            Container::Trait(it) => it.id.child_from_source(db, child_source),
+            Container::ImplBlock(it) => it.id.child_from_source(db, child_source),
+            Container::Module(it) => it.id.child_from_source(db, child_source),
         }
     }
 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 42c3925135..0e136b9049 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -76,12 +76,13 @@ fn def_with_body_from_child_node(
     db: &impl HirDatabase,
     child: InFile<&SyntaxNode>,
 ) -> Option<DefWithBody> {
-    child.value.ancestors().find_map(|node| {
+    child.cloned().ancestors_with_macros(db).find_map(|node| {
+        let n = &node.value;
         match_ast! {
-            match node {
-                ast::FnDef(def)  => { return Function::from_source(db, child.with_value(def)).map(DefWithBody::from); },
-                ast::ConstDef(def) => { return Const::from_source(db, child.with_value(def)).map(DefWithBody::from); },
-                ast::StaticDef(def) => { return Static::from_source(db, child.with_value(def)).map(DefWithBody::from); },
+            match n {
+                ast::FnDef(def)  => { return Function::from_source(db, node.with_value(def)).map(DefWithBody::from); },
+                ast::ConstDef(def) => { return Const::from_source(db, node.with_value(def)).map(DefWithBody::from); },
+                ast::StaticDef(def) => { return Static::from_source(db, node.with_value(def)).map(DefWithBody::from); },
                 _ => { None },
             }
         }
@@ -135,6 +136,7 @@ pub struct ReferenceDescriptor {
     pub name: String,
 }
 
+#[derive(Debug)]
 pub struct Expansion {
     macro_file_kind: MacroFileKind,
     macro_call_id: MacroCallId,
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index b1923bbf2e..cf3a446fcc 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -12,7 +12,6 @@ log = "0.4.5"
 once_cell = "1.0.1"
 rustc-hash = "1.0"
 either = "1.5"
-anymap = "0.12"
 
 ra_arena = { path = "../ra_arena" }
 ra_db = { path = "../ra_db" }
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs
deleted file mode 100644
index a3574a9dbb..0000000000
--- a/crates/ra_hir_def/src/child_by_source.rs
+++ /dev/null
@@ -1,139 +0,0 @@
-//! When *constructing* `hir`, we start at some parent syntax node and recursively
-//! lower the children.
-//!
-//! This modules allows one to go in the opposite direction: start with a syntax
-//! node for a *child*, and get its hir.
-
-use either::Either;
-
-use crate::{
-    db::DefDatabase,
-    dyn_map::DynMap,
-    keys,
-    src::{HasChildSource, HasSource},
-    AssocItemId, EnumId, EnumVariantId, ImplId, Lookup, ModuleDefId, ModuleId, StructFieldId,
-    TraitId, VariantId,
-};
-
-pub trait ChildBySource {
-    fn child_by_source(&self, db: &impl DefDatabase) -> DynMap;
-}
-
-impl ChildBySource for TraitId {
-    fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-
-        let data = db.trait_data(*self);
-        for (_name, item) in data.items.iter() {
-            match *item {
-                AssocItemId::FunctionId(func) => {
-                    let src = func.lookup(db).source(db);
-                    res[keys::FUNCTION].insert(src, func)
-                }
-                AssocItemId::ConstId(konst) => {
-                    let src = konst.lookup(db).source(db);
-                    res[keys::CONST].insert(src, konst)
-                }
-                AssocItemId::TypeAliasId(ty) => {
-                    let src = ty.lookup(db).source(db);
-                    res[keys::TYPE_ALIAS].insert(src, ty)
-                }
-            }
-        }
-
-        res
-    }
-}
-
-impl ChildBySource for ImplId {
-    fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-
-        let data = db.impl_data(*self);
-        for &item in data.items.iter() {
-            match item {
-                AssocItemId::FunctionId(func) => {
-                    let src = func.lookup(db).source(db);
-                    res[keys::FUNCTION].insert(src, func)
-                }
-                AssocItemId::ConstId(konst) => {
-                    let src = konst.lookup(db).source(db);
-                    res[keys::CONST].insert(src, konst)
-                }
-                AssocItemId::TypeAliasId(ty) => {
-                    let src = ty.lookup(db).source(db);
-                    res[keys::TYPE_ALIAS].insert(src, ty)
-                }
-            }
-        }
-
-        res
-    }
-}
-
-impl ChildBySource for ModuleId {
-    fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-
-        let crate_def_map = db.crate_def_map(self.krate);
-        for item in crate_def_map[self.local_id].scope.declarations() {
-            match item {
-                ModuleDefId::FunctionId(func) => {
-                    let src = func.lookup(db).source(db);
-                    res[keys::FUNCTION].insert(src, func)
-                }
-                ModuleDefId::ConstId(konst) => {
-                    let src = konst.lookup(db).source(db);
-                    res[keys::CONST].insert(src, konst)
-                }
-                ModuleDefId::StaticId(statik) => {
-                    let src = statik.lookup(db).source(db);
-                    res[keys::STATIC].insert(src, statik)
-                }
-                ModuleDefId::TypeAliasId(ty) => {
-                    let src = ty.lookup(db).source(db);
-                    res[keys::TYPE_ALIAS].insert(src, ty)
-                }
-                _ => (),
-            }
-        }
-
-        res
-    }
-}
-
-impl ChildBySource for VariantId {
-    fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-
-        let arena_map = self.child_source(db);
-        let arena_map = arena_map.as_ref();
-        for (local_id, source) in arena_map.value.iter() {
-            let id = StructFieldId { parent: *self, local_id };
-            match source {
-                Either::Left(source) => {
-                    res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id)
-                }
-                Either::Right(source) => {
-                    res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id)
-                }
-            }
-        }
-        res
-    }
-}
-
-impl ChildBySource for EnumId {
-    fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-
-        let arena_map = self.child_source(db);
-        let arena_map = arena_map.as_ref();
-        for (local_id, source) in arena_map.value.iter() {
-            let id = EnumVariantId { parent: *self, local_id };
-            res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id)
-        }
-
-        res
-    }
-}
diff --git a/crates/ra_hir_def/src/child_from_source.rs b/crates/ra_hir_def/src/child_from_source.rs
new file mode 100644
index 0000000000..37d4b78706
--- /dev/null
+++ b/crates/ra_hir_def/src/child_from_source.rs
@@ -0,0 +1,276 @@
+//! When *constructing* `hir`, we start at some parent syntax node and recursively
+//! lower the children.
+//!
+//! This modules allows one to go in the opposite direction: start with a syntax
+//! node for a *child*, and get its hir.
+
+use either::Either;
+use hir_expand::InFile;
+use ra_syntax::{ast, AstNode, AstPtr};
+
+use crate::{
+    db::DefDatabase,
+    src::{HasChildSource, HasSource},
+    AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, ImplId, Lookup, ModuleDefId, ModuleId,
+    StaticId, StructFieldId, TraitId, TypeAliasId, VariantId,
+};
+
+pub trait ChildFromSource<CHILD, SOURCE> {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<SOURCE>,
+    ) -> Option<CHILD>;
+}
+
+impl ChildFromSource<FunctionId, ast::FnDef> for TraitId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::FnDef>,
+    ) -> Option<FunctionId> {
+        let data = db.trait_data(*self);
+        data.items
+            .iter()
+            .filter_map(|(_, item)| match item {
+                AssocItemId::FunctionId(it) => Some(*it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            })
+    }
+}
+
+impl ChildFromSource<FunctionId, ast::FnDef> for ImplId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::FnDef>,
+    ) -> Option<FunctionId> {
+        let data = db.impl_data(*self);
+        data.items
+            .iter()
+            .filter_map(|item| match item {
+                AssocItemId::FunctionId(it) => Some(*it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            })
+    }
+}
+
+impl ChildFromSource<FunctionId, ast::FnDef> for ModuleId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::FnDef>,
+    ) -> Option<FunctionId> {
+        let crate_def_map = db.crate_def_map(self.krate);
+        let res = crate_def_map[self.local_id]
+            .scope
+            .declarations()
+            .filter_map(|item| match item {
+                ModuleDefId::FunctionId(it) => Some(it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            });
+        res
+    }
+}
+
+impl ChildFromSource<ConstId, ast::ConstDef> for TraitId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::ConstDef>,
+    ) -> Option<ConstId> {
+        let data = db.trait_data(*self);
+        data.items
+            .iter()
+            .filter_map(|(_, item)| match item {
+                AssocItemId::ConstId(it) => Some(*it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            })
+    }
+}
+
+impl ChildFromSource<ConstId, ast::ConstDef> for ImplId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::ConstDef>,
+    ) -> Option<ConstId> {
+        let data = db.impl_data(*self);
+        data.items
+            .iter()
+            .filter_map(|item| match item {
+                AssocItemId::ConstId(it) => Some(*it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            })
+    }
+}
+
+impl ChildFromSource<ConstId, ast::ConstDef> for ModuleId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::ConstDef>,
+    ) -> Option<ConstId> {
+        let crate_def_map = db.crate_def_map(self.krate);
+        let res = crate_def_map[self.local_id]
+            .scope
+            .declarations()
+            .filter_map(|item| match item {
+                ModuleDefId::ConstId(it) => Some(it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            });
+        res
+    }
+}
+
+impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for TraitId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::TypeAliasDef>,
+    ) -> Option<TypeAliasId> {
+        let data = db.trait_data(*self);
+        data.items
+            .iter()
+            .filter_map(|(_, item)| match item {
+                AssocItemId::TypeAliasId(it) => Some(*it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            })
+    }
+}
+
+impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for ImplId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::TypeAliasDef>,
+    ) -> Option<TypeAliasId> {
+        let data = db.impl_data(*self);
+        data.items
+            .iter()
+            .filter_map(|item| match item {
+                AssocItemId::TypeAliasId(it) => Some(*it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            })
+    }
+}
+
+impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for ModuleId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::TypeAliasDef>,
+    ) -> Option<TypeAliasId> {
+        let crate_def_map = db.crate_def_map(self.krate);
+        let res = crate_def_map[self.local_id]
+            .scope
+            .declarations()
+            .filter_map(|item| match item {
+                ModuleDefId::TypeAliasId(it) => Some(it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            });
+        res
+    }
+}
+
+impl ChildFromSource<StaticId, ast::StaticDef> for ModuleId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::StaticDef>,
+    ) -> Option<StaticId> {
+        let crate_def_map = db.crate_def_map(self.krate);
+        let res = crate_def_map[self.local_id]
+            .scope
+            .declarations()
+            .filter_map(|item| match item {
+                ModuleDefId::StaticId(it) => Some(it),
+                _ => None,
+            })
+            .find(|func| {
+                let source = func.lookup(db).source(db);
+                same_source(&source, &child_source)
+            });
+        res
+    }
+}
+
+impl ChildFromSource<StructFieldId, Either<ast::TupleFieldDef, ast::RecordFieldDef>> for VariantId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
+    ) -> Option<StructFieldId> {
+        let arena_map = self.child_source(db);
+        let (local_id, _) = arena_map.as_ref().value.iter().find(|(_local_id, source)| {
+            child_source.file_id == arena_map.file_id
+                && match (source, &child_source.value) {
+                    (Either::Left(a), Either::Left(b)) => AstPtr::new(a) == AstPtr::new(b),
+                    (Either::Right(a), Either::Right(b)) => AstPtr::new(a) == AstPtr::new(b),
+                    _ => false,
+                }
+        })?;
+        Some(StructFieldId { parent: *self, local_id })
+    }
+}
+
+impl ChildFromSource<EnumVariantId, ast::EnumVariant> for EnumId {
+    fn child_from_source(
+        &self,
+        db: &impl DefDatabase,
+        child_source: InFile<ast::EnumVariant>,
+    ) -> Option<EnumVariantId> {
+        let arena_map = self.child_source(db);
+        let (local_id, _) = arena_map.as_ref().value.iter().find(|(_local_id, source)| {
+            child_source.file_id == arena_map.file_id
+                && AstPtr::new(*source) == AstPtr::new(&child_source.value)
+        })?;
+        Some(EnumVariantId { parent: *self, local_id })
+    }
+}
+
+/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
+/// equal if they point to exactly the same object.
+///
+/// In general, we do not guarantee that we have exactly one instance of a
+/// syntax tree for each file. We probably should add such guarantee, but, for
+/// the time being, we will use identity-less AstPtr comparison.
+fn same_source<N: AstNode>(s1: &InFile<N>, s2: &InFile<N>) -> bool {
+    s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new)
+}
diff --git a/crates/ra_hir_def/src/dyn_map.rs b/crates/ra_hir_def/src/dyn_map.rs
deleted file mode 100644
index 6f269d7b01..0000000000
--- a/crates/ra_hir_def/src/dyn_map.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-//! This module defines a `DynMap` -- a container for heterogeneous maps.
-//!
-//! This means that `DynMap` stores a bunch of hash maps inside, and those maps
-//! can be of different types.
-//!
-//! It is used like this:
-//!
-//! ```
-//! // keys define submaps of a `DynMap`
-//! const STRING_TO_U32: Key<String, u32> = Key::new();
-//! const U32_TO_VEC: Key<u32, Vec<bool>> = Key::new();
-//!
-//! // Note: concrete type, no type params!
-//! let mut map = DynMap::new();
-//!
-//! // To access a specific map, index the `DynMap` by `Key`:
-//! map[STRING_TO_U32].insert("hello".to_string(), 92);
-//! let value = map[U32_TO_VEC].get(92);
-//! assert!(value.is_none());
-//! ```
-//!
-//! This is a work of fiction. Any similarities to Kotlin's `BindingContext` are
-//! a coincidence.
-use std::{
-    hash::Hash,
-    marker::PhantomData,
-    ops::{Index, IndexMut},
-};
-
-use anymap::Map;
-use rustc_hash::FxHashMap;
-
-pub struct Key<K, V, P = (K, V)> {
-    _phantom: PhantomData<(K, V, P)>,
-}
-
-impl<K, V, P> Key<K, V, P> {
-    pub(crate) const fn new() -> Key<K, V, P> {
-        Key { _phantom: PhantomData }
-    }
-}
-
-impl<K, V, P> Copy for Key<K, V, P> {}
-
-impl<K, V, P> Clone for Key<K, V, P> {
-    fn clone(&self) -> Key<K, V, P> {
-        *self
-    }
-}
-
-pub trait Policy {
-    type K;
-    type V;
-
-    fn insert(map: &mut DynMap, key: Self::K, value: Self::V);
-    fn get<'a>(map: &'a DynMap, key: &Self::K) -> Option<&'a Self::V>;
-}
-
-impl<K: Hash + Eq + 'static, V: 'static> Policy for (K, V) {
-    type K = K;
-    type V = V;
-    fn insert(map: &mut DynMap, key: K, value: V) {
-        map.map.entry::<FxHashMap<K, V>>().or_insert_with(Default::default).insert(key, value);
-    }
-    fn get<'a>(map: &'a DynMap, key: &K) -> Option<&'a V> {
-        map.map.get::<FxHashMap<K, V>>()?.get(key)
-    }
-}
-
-pub struct DynMap {
-    pub(crate) map: Map,
-}
-
-impl Default for DynMap {
-    fn default() -> Self {
-        DynMap { map: Map::new() }
-    }
-}
-
-#[repr(transparent)]
-pub struct KeyMap<KEY> {
-    map: DynMap,
-    _phantom: PhantomData<KEY>,
-}
-
-impl<P: Policy> KeyMap<Key<P::K, P::V, P>> {
-    pub fn insert(&mut self, key: P::K, value: P::V) {
-        P::insert(&mut self.map, key, value)
-    }
-    pub fn get(&self, key: &P::K) -> Option<&P::V> {
-        P::get(&self.map, key)
-    }
-}
-
-impl<P: Policy> Index<Key<P::K, P::V, P>> for DynMap {
-    type Output = KeyMap<Key<P::K, P::V, P>>;
-    fn index(&self, _key: Key<P::K, P::V, P>) -> &Self::Output {
-        // Safe due to `#[repr(transparent)]`.
-        unsafe { std::mem::transmute::<&DynMap, &KeyMap<Key<P::K, P::V, P>>>(self) }
-    }
-}
-
-impl<P: Policy> IndexMut<Key<P::K, P::V, P>> for DynMap {
-    fn index_mut(&mut self, _key: Key<P::K, P::V, P>) -> &mut Self::Output {
-        // Safe due to `#[repr(transparent)]`.
-        unsafe { std::mem::transmute::<&mut DynMap, &mut KeyMap<Key<P::K, P::V, P>>>(self) }
-    }
-}
diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs
deleted file mode 100644
index 447b7e3baa..0000000000
--- a/crates/ra_hir_def/src/keys.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-//! keys to be used with `DynMap`
-
-use std::marker::PhantomData;
-
-use hir_expand::InFile;
-use ra_syntax::{ast, AstNode, AstPtr};
-use rustc_hash::FxHashMap;
-
-use crate::{
-    dyn_map::{DynMap, Policy},
-    ConstId, EnumVariantId, FunctionId, StaticId, StructFieldId, TypeAliasId,
-};
-
-type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
-
-pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new();
-pub const CONST: Key<ast::ConstDef, ConstId> = Key::new();
-pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new();
-pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new();
-pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new();
-pub const TUPLE_FIELD: Key<ast::TupleFieldDef, StructFieldId> = Key::new();
-pub const RECORD_FIELD: Key<ast::RecordFieldDef, StructFieldId> = Key::new();
-
-/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
-/// equal if they point to exactly the same object.
-///
-/// In general, we do not guarantee that we have exactly one instance of a
-/// syntax tree for each file. We probably should add such guarantee, but, for
-/// the time being, we will use identity-less AstPtr comparison.
-pub struct AstPtrPolicy<AST, ID> {
-    _phantom: PhantomData<(AST, ID)>,
-}
-
-impl<AST: AstNode + 'static, ID: 'static> Policy for AstPtrPolicy<AST, ID> {
-    type K = InFile<AST>;
-    type V = ID;
-    fn insert(map: &mut DynMap, key: InFile<AST>, value: ID) {
-        let key = key.as_ref().map(AstPtr::new);
-        map.map
-            .entry::<FxHashMap<InFile<AstPtr<AST>>, ID>>()
-            .or_insert_with(Default::default)
-            .insert(key, value);
-    }
-    fn get<'a>(map: &'a DynMap, key: &InFile<AST>) -> Option<&'a ID> {
-        let key = key.as_ref().map(AstPtr::new);
-        map.map.get::<FxHashMap<InFile<AstPtr<AST>>, ID>>()?.get(&key)
-    }
-}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 68e66d2765..e02622f62e 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -16,9 +16,6 @@ pub mod builtin_type;
 pub mod diagnostics;
 pub mod per_ns;
 
-pub mod dyn_map;
-pub mod keys;
-
 pub mod adt;
 pub mod data;
 pub mod generics;
@@ -33,7 +30,7 @@ mod trace;
 pub mod nameres;
 
 pub mod src;
-pub mod child_by_source;
+pub mod child_from_source;
 
 #[cfg(test)]
 mod test_db;
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 35f99b2bc4..99303188bf 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -49,7 +49,11 @@ register_builtin! {
     (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand,
     (FILE_MACRO, File) => file_expand,
     (LINE_MACRO, Line) => line_expand,
-    (STRINGIFY_MACRO, Stringify) => stringify_expand
+    (STRINGIFY_MACRO, Stringify) => stringify_expand,
+    (FORMAT_ARGS_MACRO, FormatArgs) => format_args_expand,
+    // format_args_nl only differs in that it adds a newline in the end,
+    // so we use the same stub expansion for now
+    (FORMAT_ARGS_NL_MACRO, FormatArgsNl) => format_args_expand
 }
 
 fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
@@ -200,6 +204,41 @@ fn compile_error_expand(
     Err(mbe::ExpandError::BindingError("Must be a string".into()))
 }
 
+fn format_args_expand(
+    _db: &dyn AstDatabase,
+    _id: MacroCallId,
+    tt: &tt::Subtree,
+) -> Result<tt::Subtree, mbe::ExpandError> {
+    // We expand `format_args!("", arg1, arg2)` to
+    // `std::fmt::Arguments::new_v1(&[], &[&arg1, &arg2])`,
+    // which is still not really correct, but close enough for now
+    let mut args = Vec::new();
+    let mut current = Vec::new();
+    for tt in tt.token_trees.iter().cloned() {
+        match tt {
+            tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
+                args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current });
+                current = Vec::new();
+            }
+            _ => {
+                current.push(tt);
+            }
+        }
+    }
+    if !current.is_empty() {
+        args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current });
+    }
+    if args.is_empty() {
+        return Err(mbe::ExpandError::NoMatchingRule);
+    }
+    let _format_string = args.remove(0);
+    let arg_tts = args.into_iter().flat_map(|arg| (quote! { & #arg , }).token_trees);
+    let expanded = quote! {
+        std::fmt::Arguments::new_v1(&[], &[##arg_tts])
+    };
+    Ok(expanded)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -307,4 +346,21 @@ mod tests {
 
         assert_eq!(expanded, r#"loop{"error!"}"#);
     }
+
+    #[test]
+    fn test_format_args_expand() {
+        let expanded = expand_builtin_macro(
+            r#"
+        #[rustc_builtin_macro]
+        macro_rules! format_args {
+            ($fmt:expr) => ({ /* compiler built-in */ });
+            ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
+        }
+        format_args!("{} {:?}", arg1(a, b, c), arg2);
+"#,
+            BuiltinFnLikeExpander::FormatArgs,
+        );
+
+        assert_eq!(expanded, r#"std::fmt::Arguments::new_v1(&[] ,&[&arg1(a,b,c),&arg2,])"#);
+    }
 }
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index 99dabf3fbb..013a6c8ba9 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -45,8 +45,8 @@ impl TokenExpander {
     pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
         match self {
             TokenExpander::MacroRules(it) => it.map_id_up(id),
-            TokenExpander::Builtin(..) => (id, mbe::Origin::Def),
-            TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Def),
+            TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
+            TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
         }
     }
 }
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 59c69b91bb..0a5da7e547 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -76,6 +76,17 @@ impl HirFileId {
         }
     }
 
+    /// If this is a macro call, returns the syntax node of the call.
+    pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
+        match self.0 {
+            HirFileIdRepr::FileId(_) => None,
+            HirFileIdRepr::MacroFile(macro_file) => {
+                let loc = db.lookup_intern_macro(macro_file.macro_call_id);
+                Some(loc.kind.node(db))
+            }
+        }
+    }
+
     /// Return expansion information if it is a macro-expansion file
     pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
         match self.0 {
@@ -176,6 +187,13 @@ impl MacroCallKind {
         }
     }
 
+    pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
+        match self {
+            MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
+            MacroCallKind::Attr(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
+        }
+    }
+
     pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
         match self {
             MacroCallKind::FnLike(ast_id) => {
@@ -283,3 +301,24 @@ impl<T> InFile<T> {
         db.parse_or_expand(self.file_id).expect("source created from invalid file")
     }
 }
+
+impl<T: Clone> InFile<&T> {
+    pub fn cloned(&self) -> InFile<T> {
+        self.with_value(self.value.clone())
+    }
+}
+
+impl InFile<SyntaxNode> {
+    pub fn ancestors_with_macros<'a>(
+        self,
+        db: &'a impl crate::db::AstDatabase,
+    ) -> impl Iterator<Item = InFile<SyntaxNode>> + 'a {
+        std::iter::successors(Some(self), move |node| match node.value.parent() {
+            Some(parent) => Some(node.with_value(parent)),
+            None => {
+                let parent_node = node.file_id.call_node(db)?;
+                Some(parent_node)
+            }
+        })
+    }
+}
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index c5a1911609..4f2f702c01 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -38,8 +38,8 @@ impl Name {
     }
 
     /// Shortcut to create inline plain text name
-    const fn new_inline_ascii(len: usize, text: &[u8]) -> Name {
-        Name::new_text(SmolStr::new_inline_from_ascii(len, text))
+    const fn new_inline_ascii(text: &[u8]) -> Name {
+        Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text))
     }
 
     /// Resolve a name from the text of token.
@@ -105,68 +105,70 @@ impl AsName for ra_db::Dependency {
 }
 
 // Primitives
-pub const ISIZE: Name = Name::new_inline_ascii(5, b"isize");
-pub const I8: Name = Name::new_inline_ascii(2, b"i8");
-pub const I16: Name = Name::new_inline_ascii(3, b"i16");
-pub const I32: Name = Name::new_inline_ascii(3, b"i32");
-pub const I64: Name = Name::new_inline_ascii(3, b"i64");
-pub const I128: Name = Name::new_inline_ascii(4, b"i128");
-pub const USIZE: Name = Name::new_inline_ascii(5, b"usize");
-pub const U8: Name = Name::new_inline_ascii(2, b"u8");
-pub const U16: Name = Name::new_inline_ascii(3, b"u16");
-pub const U32: Name = Name::new_inline_ascii(3, b"u32");
-pub const U64: Name = Name::new_inline_ascii(3, b"u64");
-pub const U128: Name = Name::new_inline_ascii(4, b"u128");
-pub const F32: Name = Name::new_inline_ascii(3, b"f32");
-pub const F64: Name = Name::new_inline_ascii(3, b"f64");
-pub const BOOL: Name = Name::new_inline_ascii(4, b"bool");
-pub const CHAR: Name = Name::new_inline_ascii(4, b"char");
-pub const STR: Name = Name::new_inline_ascii(3, b"str");
+pub const ISIZE: Name = Name::new_inline_ascii(b"isize");
+pub const I8: Name = Name::new_inline_ascii(b"i8");
+pub const I16: Name = Name::new_inline_ascii(b"i16");
+pub const I32: Name = Name::new_inline_ascii(b"i32");
+pub const I64: Name = Name::new_inline_ascii(b"i64");
+pub const I128: Name = Name::new_inline_ascii(b"i128");
+pub const USIZE: Name = Name::new_inline_ascii(b"usize");
+pub const U8: Name = Name::new_inline_ascii(b"u8");
+pub const U16: Name = Name::new_inline_ascii(b"u16");
+pub const U32: Name = Name::new_inline_ascii(b"u32");
+pub const U64: Name = Name::new_inline_ascii(b"u64");
+pub const U128: Name = Name::new_inline_ascii(b"u128");
+pub const F32: Name = Name::new_inline_ascii(b"f32");
+pub const F64: Name = Name::new_inline_ascii(b"f64");
+pub const BOOL: Name = Name::new_inline_ascii(b"bool");
+pub const CHAR: Name = Name::new_inline_ascii(b"char");
+pub const STR: Name = Name::new_inline_ascii(b"str");
 
 // Special names
-pub const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self");
-pub const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self");
-pub const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules");
+pub const SELF_PARAM: Name = Name::new_inline_ascii(b"self");
+pub const SELF_TYPE: Name = Name::new_inline_ascii(b"Self");
+pub const MACRO_RULES: Name = Name::new_inline_ascii(b"macro_rules");
 
 // Components of known path (value or mod name)
-pub const STD: Name = Name::new_inline_ascii(3, b"std");
-pub const ITER: Name = Name::new_inline_ascii(4, b"iter");
-pub const OPS: Name = Name::new_inline_ascii(3, b"ops");
-pub const FUTURE: Name = Name::new_inline_ascii(6, b"future");
-pub const RESULT: Name = Name::new_inline_ascii(6, b"result");
-pub const BOXED: Name = Name::new_inline_ascii(5, b"boxed");
+pub const STD: Name = Name::new_inline_ascii(b"std");
+pub const ITER: Name = Name::new_inline_ascii(b"iter");
+pub const OPS: Name = Name::new_inline_ascii(b"ops");
+pub const FUTURE: Name = Name::new_inline_ascii(b"future");
+pub const RESULT: Name = Name::new_inline_ascii(b"result");
+pub const BOXED: Name = Name::new_inline_ascii(b"boxed");
 
 // Components of known path (type name)
-pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator");
-pub const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item");
-pub const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try");
-pub const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok");
-pub const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future");
-pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result");
-pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output");
-pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target");
-pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box");
-pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(9, b"RangeFrom");
-pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(9, b"RangeFull");
-pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(14, b"RangeInclusive");
-pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(16, b"RangeToInclusive");
-pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(7, b"RangeTo");
-pub const RANGE_TYPE: Name = Name::new_inline_ascii(5, b"Range");
+pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(b"IntoIterator");
+pub const ITEM_TYPE: Name = Name::new_inline_ascii(b"Item");
+pub const TRY_TYPE: Name = Name::new_inline_ascii(b"Try");
+pub const OK_TYPE: Name = Name::new_inline_ascii(b"Ok");
+pub const FUTURE_TYPE: Name = Name::new_inline_ascii(b"Future");
+pub const RESULT_TYPE: Name = Name::new_inline_ascii(b"Result");
+pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(b"Output");
+pub const TARGET_TYPE: Name = Name::new_inline_ascii(b"Target");
+pub const BOX_TYPE: Name = Name::new_inline_ascii(b"Box");
+pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(b"RangeFrom");
+pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(b"RangeFull");
+pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeInclusive");
+pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive");
+pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo");
+pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range");
 
 // Builtin Macros
-pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file");
-pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column");
-pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error");
-pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line");
-pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify");
+pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file");
+pub const COLUMN_MACRO: Name = Name::new_inline_ascii(b"column");
+pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(b"compile_error");
+pub const LINE_MACRO: Name = Name::new_inline_ascii(b"line");
+pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(b"stringify");
+pub const FORMAT_ARGS_MACRO: Name = Name::new_inline_ascii(b"format_args");
+pub const FORMAT_ARGS_NL_MACRO: Name = Name::new_inline_ascii(b"format_args_nl");
 
 // Builtin derives
-pub const COPY_TRAIT: Name = Name::new_inline_ascii(4, b"Copy");
-pub const CLONE_TRAIT: Name = Name::new_inline_ascii(5, b"Clone");
-pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(7, b"Default");
-pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(5, b"Debug");
-pub const HASH_TRAIT: Name = Name::new_inline_ascii(4, b"Hash");
-pub const ORD_TRAIT: Name = Name::new_inline_ascii(3, b"Ord");
-pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(10, b"PartialOrd");
-pub const EQ_TRAIT: Name = Name::new_inline_ascii(2, b"Eq");
-pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(9, b"PartialEq");
+pub const COPY_TRAIT: Name = Name::new_inline_ascii(b"Copy");
+pub const CLONE_TRAIT: Name = Name::new_inline_ascii(b"Clone");
+pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(b"Default");
+pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(b"Debug");
+pub const HASH_TRAIT: Name = Name::new_inline_ascii(b"Hash");
+pub const ORD_TRAIT: Name = Name::new_inline_ascii(b"Ord");
+pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(b"PartialOrd");
+pub const EQ_TRAIT: Name = Name::new_inline_ascii(b"Eq");
+pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(b"PartialEq");
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 76a7412076..d3c1988132 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -689,8 +689,38 @@ mod tests {
                     fo<|>o();
                 }
             }
+            mod confuse_index { fn foo(); }
             ",
             "foo FN_DEF FileId(1) [52; 63) [55; 58)",
         );
     }
+
+    #[should_panic] // currently failing because of expr mapping problems
+    #[test]
+    fn goto_through_format() {
+        check_goto(
+            "
+            //- /lib.rs
+            #[macro_export]
+            macro_rules! format {
+                ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
+            }
+            #[rustc_builtin_macro]
+            #[macro_export]
+            macro_rules! format_args {
+                ($fmt:expr) => ({ /* compiler built-in */ });
+                ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
+            }
+            pub mod __export {
+                pub use crate::format_args;
+                fn foo() {} // for index confusion
+            }
+            fn foo() -> i8 {}
+            fn test() {
+                format!(\"{}\", fo<|>o())
+            }
+            ",
+            "foo FN_DEF FileId(1) [359; 376) [362; 365)",
+        );
+    }
 }
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index db6230aab9..e049fce611 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -1,10 +1,6 @@
 //! FIXME: write short doc here
 
-use std::{
-    hash::{Hash, Hasher},
-    iter::successors,
-    marker::PhantomData,
-};
+use std::{iter::successors, marker::PhantomData};
 
 use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};
 
@@ -47,7 +43,7 @@ impl SyntaxNodePtr {
 }
 
 /// Like `SyntaxNodePtr`, but remembers the type of node
-#[derive(Debug)]
+#[derive(Debug, Hash)]
 pub struct AstPtr<N: AstNode> {
     raw: SyntaxNodePtr,
     _ty: PhantomData<fn() -> N>,
@@ -68,12 +64,6 @@ impl<N: AstNode> PartialEq for AstPtr<N> {
     }
 }
 
-impl<N: AstNode> Hash for AstPtr<N> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.raw.hash(state)
-    }
-}
-
 impl<N: AstNode> AstPtr<N> {
     pub fn new(node: &N) -> AstPtr<N> {
         AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }


Test patch:
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index d724ee1223..f1b67555f2 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -11,8 +11,8 @@ use std::fmt::Write;
 use std::sync::Arc;
 
 use hir_def::{
-    body::BodySourceMap, child_by_source::ChildBySource, db::DefDatabase, keys,
-    nameres::CrateDefMap, AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
+    body::BodySourceMap, child_from_source::ChildFromSource, db::DefDatabase, nameres::CrateDefMap,
+    AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
 };
 use hir_expand::InFile;
 use insta::assert_snapshot;
@@ -33,9 +33,7 @@ fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
     let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
     let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
     let module = db.module_for_file(pos.file_id);
-    let func = *module.child_by_source(db)[keys::FUNCTION]
-        .get(&InFile::new(pos.file_id.into(), fn_def))
-        .unwrap();
+    let func = module.child_from_source(db, InFile::new(pos.file_id.into(), fn_def)).unwrap();
 
     let (_body, source_map) = db.body_with_source_map(func.into());
     if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {